Move bitcoin and monero parts into self modules.

M committed Dec 24, 2021 at 14:52 UTC 4535a1aaa8aaa4997c40eadba6426f94e37b9c65
126 files changed +25452
cw_bitcoin/.gitignore new
+74
@@ -0,0 +1,74 @@
1 +# Miscellaneous
2 +*.class
3 +*.log
4 +*.pyc
5 +*.swp
6 +.DS_Store
7 +.atom/
8 +.buildlog/
9 +.history
10 +.svn/
11 +
12 +# IntelliJ related
13 +*.iml
14 +*.ipr
15 +*.iws
16 +.idea/
17 +
18 +# The .vscode folder contains launch configuration and tasks you configure in
19 +# VS Code which you may wish to be included in version control, so this line
20 +# is commented out by default.
21 +#.vscode/
22 +
23 +# Flutter/Dart/Pub related
24 +**/doc/api/
25 +.dart_tool/
26 +.flutter-plugins
27 +.flutter-plugins-dependencies
28 +.packages
29 +.pub-cache/
30 +.pub/
31 +build/
32 +
33 +# Android related
34 +**/android/**/gradle-wrapper.jar
35 +**/android/.gradle
36 +**/android/captures/
37 +**/android/gradlew
38 +**/android/gradlew.bat
39 +**/android/local.properties
40 +**/android/**/GeneratedPluginRegistrant.java
41 +
42 +# iOS/XCode related
43 +**/ios/**/*.mode1v3
44 +**/ios/**/*.mode2v3
45 +**/ios/**/*.moved-aside
46 +**/ios/**/*.pbxuser
47 +**/ios/**/*.perspectivev3
48 +**/ios/**/*sync/
49 +**/ios/**/.sconsign.dblite
50 +**/ios/**/.tags*
51 +**/ios/**/.vagrant/
52 +**/ios/**/DerivedData/
53 +**/ios/**/Icon?
54 +**/ios/**/Pods/
55 +**/ios/**/.symlinks/
56 +**/ios/**/profile
57 +**/ios/**/xcuserdata
58 +**/ios/.generated/
59 +**/ios/Flutter/App.framework
60 +**/ios/Flutter/Flutter.framework
61 +**/ios/Flutter/Flutter.podspec
62 +**/ios/Flutter/Generated.xcconfig
63 +**/ios/Flutter/app.flx
64 +**/ios/Flutter/app.zip
65 +**/ios/Flutter/flutter_assets/
66 +**/ios/Flutter/flutter_export_environment.sh
67 +**/ios/ServiceDefinitions.json
68 +**/ios/Runner/GeneratedPluginRegistrant.*
69 +
70 +# Exceptions to above rules.
71 +!**/ios/**/default.mode1v3
72 +!**/ios/**/default.mode2v3
73 +!**/ios/**/default.pbxuser
74 +!**/ios/**/default.perspectivev3
cw_bitcoin/.metadata new
+10
@@ -0,0 +1,10 @@
1 +# This file tracks properties of this Flutter project.
2 +# Used by Flutter tool to assess capabilities and perform upgrades etc.
3 +#
4 +# This file should be version controlled and should not be manually edited.
5 +
6 +version:
7 + revision: b1395592de68cc8ac4522094ae59956dd21a91db
8 + channel: stable
9 +
10 +project_type: package
cw_bitcoin/CHANGELOG.md new
+3
@@ -0,0 +1,3 @@
1 +## [0.0.1] - TODO: Add release date.
2 +
3 +* TODO: Describe initial release.
cw_bitcoin/LICENSE new
+1
@@ -0,0 +1 @@
1 +TODO: Add your license here.
cw_bitcoin/README.md new
+14
@@ -0,0 +1,14 @@
1 +# cw_bitcoin
2 +
3 +A new Flutter package project.
4 +
5 +## Getting Started
6 +
7 +This project is a starting point for a Dart
8 +[package](https://flutter.dev/developing-packages/),
9 +a library module containing code that can be shared easily across
10 +multiple Flutter or Dart projects.
11 +
12 +For help getting started with Flutter, view our
13 +[online documentation](https://flutter.dev/docs), which offers tutorials,
14 +samples, guidance on mobile development, and a full API reference.
cw_bitcoin/lib/address_to_output_script.dart new
+29
@@ -0,0 +1,29 @@
1 +import 'dart:typed_data';
2 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
3 +import 'package:bs58check/bs58check.dart' as bs58check;
4 +import 'package:bitcoin_flutter/src/utils/constants/op.dart';
5 +import 'package:bitcoin_flutter/src/utils/script.dart' as bscript;
6 +import 'package:bitcoin_flutter/src/address.dart';
7 +
8 +Uint8List p2shAddressToOutputScript(String address) {
9 + final decodeBase58 = bs58check.decode(address);
10 + final hash = decodeBase58.sublist(1);
11 + return bscript.compile(<dynamic>[OPS['OP_HASH160'], hash, OPS['OP_EQUAL']]);
12 +}
13 +
14 +Uint8List addressToOutputScript(
15 + String address, bitcoin.NetworkType networkType) {
16 + try {
17 + // FIXME: improve validation for p2sh addresses
18 + // 3 for bitcoin
19 + // m for litecoin
20 + if (address.startsWith('3') || address.toLowerCase().startsWith('m')) {
21 + return p2shAddressToOutputScript(address);
22 + }
23 +
24 + return Address.addressToOutputScript(address, networkType);
25 + } catch (err) {
26 + print(err);
27 + return Uint8List(0);
28 + }
29 +}
cw_bitcoin/lib/bitcoin_address_record.dart new
+28
@@ -0,0 +1,28 @@
1 +import 'dart:convert';
2 +
3 +class BitcoinAddressRecord {
4 + BitcoinAddressRecord(this.address, {this.index, bool isHidden})
5 + : _isHidden = isHidden;
6 +
7 + factory BitcoinAddressRecord.fromJSON(String jsonSource) {
8 + final decoded = json.decode(jsonSource) as Map;
9 +
10 + return BitcoinAddressRecord(decoded['address'] as String,
11 + index: decoded['index'] as int, isHidden: decoded['isHidden'] as bool);
12 + }
13 +
14 + @override
15 + bool operator ==(Object o) =>
16 + o is BitcoinAddressRecord && address == o.address;
17 +
18 + final String address;
19 + bool get isHidden => _isHidden ?? false;
20 + int index;
21 + final bool _isHidden;
22 +
23 + @override
24 + int get hashCode => address.hashCode;
25 +
26 + String toJSON() =>
27 + json.encode({'address': address, 'index': index, 'isHidden': isHidden});
28 +}
cw_bitcoin/lib/bitcoin_amount_format.dart new
+28
@@ -0,0 +1,28 @@
1 +import 'dart:math';
2 +
3 +import 'package:intl/intl.dart';
4 +import 'package:cw_core/crypto_amount_format.dart';
5 +
6 +const bitcoinAmountLength = 8;
7 +const bitcoinAmountDivider = 100000000;
8 +final bitcoinAmountFormat = NumberFormat()
9 + ..maximumFractionDigits = bitcoinAmountLength
10 + ..minimumFractionDigits = 1;
11 +
12 +String bitcoinAmountToString({int amount}) => bitcoinAmountFormat.format(
13 + cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
14 +
15 +double bitcoinAmountToDouble({int amount}) =>
16 + cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
17 +
18 +int stringDoubleToBitcoinAmount(String amount) {
19 + int result = 0;
20 +
21 + try {
22 + result = (double.parse(amount) * bitcoinAmountDivider).toInt();
23 + } catch (e) {
24 + result = 0;
25 + }
26 +
27 + return result;
28 +}
cw_bitcoin/lib/bitcoin_commit_transaction_exception.dart new
+4
@@ -0,0 +1,4 @@
1 +class BitcoinCommitTransactionException implements Exception {
2 + @override
3 + String toString() => 'Transaction commit is failed.';
4 +}
\ No newline at end of file
cw_bitcoin/lib/bitcoin_mnemonic.dart new
+2297
@@ -0,0 +1,2297 @@
1 +import 'dart:convert';
2 +import 'dart:math';
3 +import 'dart:typed_data';
4 +import 'package:crypto/crypto.dart';
5 +import 'package:unorm_dart/unorm_dart.dart' as unorm;
6 +import 'package:cryptography/cryptography.dart' as cryptography;
7 +import 'package:cake_wallet/core/sec_random_native.dart';
8 +
9 +const segwit = '100';
10 +final wordlist = englishWordlist;
11 +
12 +double logBase(num x, num base) => log(x) / log(base);
13 +
14 +String mnemonicEncode(int i) {
15 + var _i = i;
16 + final n = wordlist.length;
17 + final words = <String>[];
18 +
19 + while (_i > 0) {
20 + final x = i % n;
21 + _i = (i / n).floor();
22 + words.add(wordlist[x]);
23 + }
24 +
25 + return words.join(' ');
26 +}
27 +
28 +int mnemonicDecode(String seed) {
29 + var i = 0;
30 + final n = wordlist.length;
31 + final words = seed.split(' ');
32 +
33 + while (words.length > 0) {
34 + final word = words.removeLast();
35 + final k = wordlist.indexOf(word);
36 + i = i * n + k;
37 + }
38 +
39 + return i;
40 +}
41 +
42 +bool isNewSeed(String seed, {String prefix = segwit}) {
43 + final hmacSha512 = Hmac(sha512, utf8.encode('Seed version'));
44 + final digest = hmacSha512.convert(utf8.encode(normalizeText(seed)));
45 + final hx = digest.toString();
46 + return hx.startsWith(prefix.toLowerCase());
47 +}
48 +
49 +void maskBytes(Uint8List bytes, int bits) {
50 + final skipCount = (bits / 8).floor();
51 + var lastByte = (1 << bits % 8) - 1;
52 +
53 + for (var i = bytes.length - 1 - skipCount; i >= 0; i--) {
54 + bytes[i] &= lastByte;
55 +
56 + if (lastByte > 0) {
57 + lastByte = 0;
58 + }
59 + }
60 +}
61 +
62 +String bufferToBin(Uint8List data) {
63 + final q1 = data.map((e) => e.toRadixString(2).padLeft(8, '0'));
64 + final q2 = q1.join('');
65 + return q2;
66 +}
67 +
68 +String encode(Uint8List data) {
69 + final dataBitLen = data.length * 8;
70 + final wordBitLen = logBase(wordlist.length, 2).ceil();
71 + final wordCount = (dataBitLen / wordBitLen).floor();
72 + maskBytes(data, wordCount * wordBitLen);
73 + final bin = bufferToBin(data);
74 + final binStr = bin.substring(bin.length - (wordCount * wordBitLen));
75 + final result = <Object>[];
76 +
77 + for (var i = 0; i < wordCount; i++) {
78 + final wordBin = binStr.substring(i * wordBitLen, (i + 1) * wordBitLen);
79 + result.add(wordlist[int.parse(wordBin, radix: 2)]);
80 + }
81 +
82 + return result.join(' ');
83 +}
84 +
85 +List<bool> prefixMatches(String source, List<String> prefixes) {
86 + final hmacSha512 = Hmac(sha512, utf8.encode('Seed version'));
87 + final digest = hmacSha512.convert(utf8.encode(normalizeText(source)));
88 + final hx = digest.toString();
89 +
90 + return prefixes.map((prefix) => hx.startsWith(prefix.toLowerCase())).toList();
91 +}
92 +
93 +Future<String> generateMnemonic(
94 + {int strength = 264, String prefix = segwit}) async {
95 + final wordBitlen = logBase(wordlist.length, 2).ceil();
96 + final wordCount = strength / wordBitlen;
97 + final byteCount = ((wordCount * wordBitlen).ceil() / 8).ceil();
98 + var result = '';
99 +
100 + do {
101 + final bytes = await secRandom(byteCount);
102 + maskBytes(bytes, strength);
103 + result = encode(bytes);
104 + } while (!prefixMatches(result, [prefix]).first);
105 +
106 + return result;
107 +}
108 +
109 +Uint8List mnemonicToSeedBytes(String mnemonic, {String prefix = segwit}) {
110 + final pbkdf2 = cryptography.Pbkdf2(
111 + macAlgorithm: cryptography.Hmac(cryptography.sha512),
112 + iterations: 2048,
113 + bits: 512);
114 + final text = normalizeText(mnemonic);
115 +
116 + return pbkdf2.deriveBitsSync(text.codeUnits,
117 + nonce: cryptography.Nonce('electrum'.codeUnits));
118 +}
119 +
120 +bool matchesAnyPrefix(String mnemonic) =>
121 + prefixMatches(mnemonic, [segwit]).any((el) => el);
122 +
123 +bool validateMnemonic(String mnemonic, {String prefix = segwit}) {
124 + try {
125 + return matchesAnyPrefix(mnemonic);
126 + } catch (e) {
127 + return false;
128 + }
129 +}
130 +
131 +final COMBININGCODEPOINTS = combiningcodepoints();
132 +
133 +List<int> combiningcodepoints() {
134 + final source = '300:34e|350:36f|483:487|591:5bd|5bf|5c1|5c2|5c4|5c5|5c7|610:61a|64b:65f|670|' +
135 + '6d6:6dc|6df:6e4|6e7|6e8|6ea:6ed|711|730:74a|7eb:7f3|816:819|81b:823|825:827|' +
136 + '829:82d|859:85b|8d4:8e1|8e3:8ff|93c|94d|951:954|9bc|9cd|a3c|a4d|abc|acd|b3c|' +
137 + 'b4d|bcd|c4d|c55|c56|cbc|ccd|d4d|dca|e38:e3a|e48:e4b|eb8|eb9|ec8:ecb|f18|f19|' +
138 + 'f35|f37|f39|f71|f72|f74|f7a:f7d|f80|f82:f84|f86|f87|fc6|1037|1039|103a|108d|' +
139 + '135d:135f|1714|1734|17d2|17dd|18a9|1939:193b|1a17|1a18|1a60|1a75:1a7c|1a7f|' +
140 + '1ab0:1abd|1b34|1b44|1b6b:1b73|1baa|1bab|1be6|1bf2|1bf3|1c37|1cd0:1cd2|' +
141 + '1cd4:1ce0|1ce2:1ce8|1ced|1cf4|1cf8|1cf9|1dc0:1df5|1dfb:1dff|20d0:20dc|20e1|' +
142 + '20e5:20f0|2cef:2cf1|2d7f|2de0:2dff|302a:302f|3099|309a|a66f|a674:a67d|a69e|' +
143 + 'a69f|a6f0|a6f1|a806|a8c4|a8e0:a8f1|a92b:a92d|a953|a9b3|a9c0|aab0|aab2:aab4|' +
144 + 'aab7|aab8|aabe|aabf|aac1|aaf6|abed|fb1e|fe20:fe2f|101fd|102e0|10376:1037a|' +
145 + '10a0d|10a0f|10a38:10a3a|10a3f|10ae5|10ae6|11046|1107f|110b9|110ba|11100:11102|' +
146 + '11133|11134|11173|111c0|111ca|11235|11236|112e9|112ea|1133c|1134d|11366:1136c|' +
147 + '11370:11374|11442|11446|114c2|114c3|115bf|115c0|1163f|116b6|116b7|1172b|11c3f|' +
148 + '16af0:16af4|16b30:16b36|1bc9e|1d165:1d169|1d16d:1d172|1d17b:1d182|1d185:1d18b|' +
149 + '1d1aa:1d1ad|1d242:1d244|1e000:1e006|1e008:1e018|1e01b:1e021|1e023|1e024|' +
150 + '1e026:1e02a|1e8d0:1e8d6|1e944:1e94a';
151 +
152 + return source.split('|').map((e) {
153 + if (e.contains(':')) {
154 + return e.split(':').map((hex) => int.parse(hex, radix: 16));
155 + }
156 +
157 + return int.parse(e, radix: 16);
158 + }).fold(<int>[], (List<int> acc, element) {
159 + if (element is List) {
160 + for (var i = element[0] as int; i <= (element[1] as int); i++) {}
161 + } else if (element is int) {
162 + acc.add(element);
163 + }
164 +
165 + return acc;
166 + }).toList();
167 +}
168 +
169 +String removeCombiningCharacters(String source) {
170 + return source
171 + .split('')
172 + .where((char) => !COMBININGCODEPOINTS.contains(char.codeUnits.first))
173 + .join('');
174 +}
175 +
176 +bool isCJK(String char) {
177 + final n = char.codeUnitAt(0);
178 +
179 + for (var x in CJKINTERVALS) {
180 + final imin = x[0] as num;
181 + final imax = x[1] as num;
182 +
183 + if (n >= imin && n <= imax) return true;
184 + }
185 +
186 + return false;
187 +}
188 +
189 +String removeCJKSpaces(String source) {
190 + final splitted = source.split('');
191 + final filtered = <String>[];
192 +
193 + for (var i = 0; i < splitted.length; i++) {
194 + final char = splitted[i];
195 + final isSpace = char.trim() == '';
196 + final prevIsCJK = i != 0 && isCJK(splitted[i - 1]);
197 + final nextIsCJK = i != splitted.length - 1 && isCJK(splitted[i + 1]);
198 +
199 + if (!(isSpace && prevIsCJK && nextIsCJK)) {
200 + filtered.add(char);
201 + }
202 + }
203 +
204 + return filtered.join('');
205 +}
206 +
207 +String normalizeText(String source) {
208 + final res = removeCombiningCharacters(unorm.nfkd(source).toLowerCase())
209 + .trim()
210 + .split('/\s+/')
211 + .join(' ');
212 +
213 + return removeCJKSpaces(res);
214 +}
215 +
216 +const CJKINTERVALS = [
217 + [0x4e00, 0x9fff, 'CJK Unified Ideographs'],
218 + [0x3400, 0x4dbf, 'CJK Unified Ideographs Extension A'],
219 + [0x20000, 0x2a6df, 'CJK Unified Ideographs Extension B'],
220 + [0x2a700, 0x2b73f, 'CJK Unified Ideographs Extension C'],
221 + [0x2b740, 0x2b81f, 'CJK Unified Ideographs Extension D'],
222 + [0xf900, 0xfaff, 'CJK Compatibility Ideographs'],
223 + [0x2f800, 0x2fa1d, 'CJK Compatibility Ideographs Supplement'],
224 + [0x3190, 0x319f, 'Kanbun'],
225 + [0x2e80, 0x2eff, 'CJK Radicals Supplement'],
226 + [0x2f00, 0x2fdf, 'CJK Radicals'],
227 + [0x31c0, 0x31ef, 'CJK Strokes'],
228 + [0x2ff0, 0x2fff, 'Ideographic Description Characters'],
229 + [0xe0100, 0xe01ef, 'Variation Selectors Supplement'],
230 + [0x3100, 0x312f, 'Bopomofo'],
231 + [0x31a0, 0x31bf, 'Bopomofo Extended'],
232 + [0xff00, 0xffef, 'Halfwidth and Fullwidth Forms'],
233 + [0x3040, 0x309f, 'Hiragana'],
234 + [0x30a0, 0x30ff, 'Katakana'],
235 + [0x31f0, 0x31ff, 'Katakana Phonetic Extensions'],
236 + [0x1b000, 0x1b0ff, 'Kana Supplement'],
237 + [0xac00, 0xd7af, 'Hangul Syllables'],
238 + [0x1100, 0x11ff, 'Hangul Jamo'],
239 + [0xa960, 0xa97f, 'Hangul Jamo Extended A'],
240 + [0xd7b0, 0xd7ff, 'Hangul Jamo Extended B'],
241 + [0x3130, 0x318f, 'Hangul Compatibility Jamo'],
242 + [0xa4d0, 0xa4ff, 'Lisu'],
243 + [0x16f00, 0x16f9f, 'Miao'],
244 + [0xa000, 0xa48f, 'Yi Syllables'],
245 + [0xa490, 0xa4cf, 'Yi Radicals'],
246 +];
247 +
248 +final englishWordlist = <String>[
249 + 'abandon',
250 + 'ability',
251 + 'able',
252 + 'about',
253 + 'above',
254 + 'absent',
255 + 'absorb',
256 + 'abstract',
257 + 'absurd',
258 + 'abuse',
259 + 'access',
260 + 'accident',
261 + 'account',
262 + 'accuse',
263 + 'achieve',
264 + 'acid',
265 + 'acoustic',
266 + 'acquire',
267 + 'across',
268 + 'act',
269 + 'action',
270 + 'actor',
271 + 'actress',
272 + 'actual',
273 + 'adapt',
274 + 'add',
275 + 'addict',
276 + 'address',
277 + 'adjust',
278 + 'admit',
279 + 'adult',
280 + 'advance',
281 + 'advice',
282 + 'aerobic',
283 + 'affair',
284 + 'afford',
285 + 'afraid',
286 + 'again',
287 + 'age',
288 + 'agent',
289 + 'agree',
290 + 'ahead',
291 + 'aim',
292 + 'air',
293 + 'airport',
294 + 'aisle',
295 + 'alarm',
296 + 'album',
297 + 'alcohol',
298 + 'alert',
299 + 'alien',
300 + 'all',
301 + 'alley',
302 + 'allow',
303 + 'almost',
304 + 'alone',
305 + 'alpha',
306 + 'already',
307 + 'also',
308 + 'alter',
309 + 'always',
310 + 'amateur',
311 + 'amazing',
312 + 'among',
313 + 'amount',
314 + 'amused',
315 + 'analyst',
316 + 'anchor',
317 + 'ancient',
318 + 'anger',
319 + 'angle',
320 + 'angry',
321 + 'animal',
322 + 'ankle',
323 + 'announce',
324 + 'annual',
325 + 'another',
326 + 'answer',
327 + 'antenna',
328 + 'antique',
329 + 'anxiety',
330 + 'any',
331 + 'apart',
332 + 'apology',
333 + 'appear',
334 + 'apple',
335 + 'approve',
336 + 'april',
337 + 'arch',
338 + 'arctic',
339 + 'area',
340 + 'arena',
341 + 'argue',
342 + 'arm',
343 + 'armed',
344 + 'armor',
345 + 'army',
346 + 'around',
347 + 'arrange',
348 + 'arrest',
349 + 'arrive',
350 + 'arrow',
351 + 'art',
352 + 'artefact',
353 + 'artist',
354 + 'artwork',
355 + 'ask',
356 + 'aspect',
357 + 'assault',
358 + 'asset',
359 + 'assist',
360 + 'assume',
361 + 'asthma',
362 + 'athlete',
363 + 'atom',
364 + 'attack',
365 + 'attend',
366 + 'attitude',
367 + 'attract',
368 + 'auction',
369 + 'audit',
370 + 'august',
371 + 'aunt',
372 + 'author',
373 + 'auto',
374 + 'autumn',
375 + 'average',
376 + 'avocado',
377 + 'avoid',
378 + 'awake',
379 + 'aware',
380 + 'away',
381 + 'awesome',
382 + 'awful',
383 + 'awkward',
384 + 'axis',
385 + 'baby',
386 + 'bachelor',
387 + 'bacon',
388 + 'badge',
389 + 'bag',
390 + 'balance',
391 + 'balcony',
392 + 'ball',
393 + 'bamboo',
394 + 'banana',
395 + 'banner',
396 + 'bar',
397 + 'barely',
398 + 'bargain',
399 + 'barrel',
400 + 'base',
401 + 'basic',
402 + 'basket',
403 + 'battle',
404 + 'beach',
405 + 'bean',
406 + 'beauty',
407 + 'because',
408 + 'become',
409 + 'beef',
410 + 'before',
411 + 'begin',
412 + 'behave',
413 + 'behind',
414 + 'believe',
415 + 'below',
416 + 'belt',
417 + 'bench',
418 + 'benefit',
419 + 'best',
420 + 'betray',
421 + 'better',
422 + 'between',
423 + 'beyond',
424 + 'bicycle',
425 + 'bid',
426 + 'bike',
427 + 'bind',
428 + 'biology',
429 + 'bird',
430 + 'birth',
431 + 'bitter',
432 + 'black',
433 + 'blade',
434 + 'blame',
435 + 'blanket',
436 + 'blast',
437 + 'bleak',
438 + 'bless',
439 + 'blind',
440 + 'blood',
441 + 'blossom',
442 + 'blouse',
443 + 'blue',
444 + 'blur',
445 + 'blush',
446 + 'board',
447 + 'boat',
448 + 'body',
449 + 'boil',
450 + 'bomb',
451 + 'bone',
452 + 'bonus',
453 + 'book',
454 + 'boost',
455 + 'border',
456 + 'boring',
457 + 'borrow',
458 + 'boss',
459 + 'bottom',
460 + 'bounce',
461 + 'box',
462 + 'boy',
463 + 'bracket',
464 + 'brain',
465 + 'brand',
466 + 'brass',
467 + 'brave',
468 + 'bread',
469 + 'breeze',
470 + 'brick',
471 + 'bridge',
472 + 'brief',
473 + 'bright',
474 + 'bring',
475 + 'brisk',
476 + 'broccoli',
477 + 'broken',
478 + 'bronze',
479 + 'broom',
480 + 'brother',
481 + 'brown',
482 + 'brush',
483 + 'bubble',
484 + 'buddy',
485 + 'budget',
486 + 'buffalo',
487 + 'build',
488 + 'bulb',
489 + 'bulk',
490 + 'bullet',
491 + 'bundle',
492 + 'bunker',
493 + 'burden',
494 + 'burger',
495 + 'burst',
496 + 'bus',
497 + 'business',
498 + 'busy',
499 + 'butter',
500 + 'buyer',
501 + 'buzz',
502 + 'cabbage',
503 + 'cabin',
504 + 'cable',
505 + 'cactus',
506 + 'cage',
507 + 'cake',
508 + 'call',
509 + 'calm',
510 + 'camera',
511 + 'camp',
512 + 'can',
513 + 'canal',
514 + 'cancel',
515 + 'candy',
516 + 'cannon',
517 + 'canoe',
518 + 'canvas',
519 + 'canyon',
520 + 'capable',
521 + 'capital',
522 + 'captain',
523 + 'car',
524 + 'carbon',
525 + 'card',
526 + 'cargo',
527 + 'carpet',
528 + 'carry',
529 + 'cart',
530 + 'case',
531 + 'cash',
532 + 'casino',
533 + 'castle',
534 + 'casual',
535 + 'cat',
536 + 'catalog',
537 + 'catch',
538 + 'category',
539 + 'cattle',
540 + 'caught',
541 + 'cause',
542 + 'caution',
543 + 'cave',
544 + 'ceiling',
545 + 'celery',
546 + 'cement',
547 + 'census',
548 + 'century',
549 + 'cereal',
550 + 'certain',
551 + 'chair',
552 + 'chalk',
553 + 'champion',
554 + 'change',
555 + 'chaos',
556 + 'chapter',
557 + 'charge',
558 + 'chase',
559 + 'chat',
560 + 'cheap',
561 + 'check',
562 + 'cheese',
563 + 'chef',
564 + 'cherry',
565 + 'chest',
566 + 'chicken',
567 + 'chief',
568 + 'child',
569 + 'chimney',
570 + 'choice',
571 + 'choose',
572 + 'chronic',
573 + 'chuckle',
574 + 'chunk',
575 + 'churn',
576 + 'cigar',
577 + 'cinnamon',
578 + 'circle',
579 + 'citizen',
580 + 'city',
581 + 'civil',
582 + 'claim',
583 + 'clap',
584 + 'clarify',
585 + 'claw',
586 + 'clay',
587 + 'clean',
588 + 'clerk',
589 + 'clever',
590 + 'click',
591 + 'client',
592 + 'cliff',
593 + 'climb',
594 + 'clinic',
595 + 'clip',
596 + 'clock',
597 + 'clog',
598 + 'close',
599 + 'cloth',
600 + 'cloud',
601 + 'clown',
602 + 'club',
603 + 'clump',
604 + 'cluster',
605 + 'clutch',
606 + 'coach',
607 + 'coast',
608 + 'coconut',
609 + 'code',
610 + 'coffee',
611 + 'coil',
612 + 'coin',
613 + 'collect',
614 + 'color',
615 + 'column',
616 + 'combine',
617 + 'come',
618 + 'comfort',
619 + 'comic',
620 + 'common',
621 + 'company',
622 + 'concert',
623 + 'conduct',
624 + 'confirm',
625 + 'congress',
626 + 'connect',
627 + 'consider',
628 + 'control',
629 + 'convince',
630 + 'cook',
631 + 'cool',
632 + 'copper',
633 + 'copy',
634 + 'coral',
635 + 'core',
636 + 'corn',
637 + 'correct',
638 + 'cost',
639 + 'cotton',
640 + 'couch',
641 + 'country',
642 + 'couple',
643 + 'course',
644 + 'cousin',
645 + 'cover',
646 + 'coyote',
647 + 'crack',
648 + 'cradle',
649 + 'craft',
650 + 'cram',
651 + 'crane',
652 + 'crash',
653 + 'crater',
654 + 'crawl',
655 + 'crazy',
656 + 'cream',
657 + 'credit',
658 + 'creek',
659 + 'crew',
660 + 'cricket',
661 + 'crime',
662 + 'crisp',
663 + 'critic',
664 + 'crop',
665 + 'cross',
666 + 'crouch',
667 + 'crowd',
668 + 'crucial',
669 + 'cruel',
670 + 'cruise',
671 + 'crumble',
672 + 'crunch',
673 + 'crush',
674 + 'cry',
675 + 'crystal',
676 + 'cube',
677 + 'culture',
678 + 'cup',
679 + 'cupboard',
680 + 'curious',
681 + 'current',
682 + 'curtain',
683 + 'curve',
684 + 'cushion',
685 + 'custom',
686 + 'cute',
687 + 'cycle',
688 + 'dad',
689 + 'damage',
690 + 'damp',
691 + 'dance',
692 + 'danger',
693 + 'daring',
694 + 'dash',
695 + 'daughter',
696 + 'dawn',
697 + 'day',
698 + 'deal',
699 + 'debate',
700 + 'debris',
701 + 'decade',
702 + 'december',
703 + 'decide',
704 + 'decline',
705 + 'decorate',
706 + 'decrease',
707 + 'deer',
708 + 'defense',
709 + 'define',
710 + 'defy',
711 + 'degree',
712 + 'delay',
713 + 'deliver',
714 + 'demand',
715 + 'demise',
716 + 'denial',
717 + 'dentist',
718 + 'deny',
719 + 'depart',
720 + 'depend',
721 + 'deposit',
722 + 'depth',
723 + 'deputy',
724 + 'derive',
725 + 'describe',
726 + 'desert',
727 + 'design',
728 + 'desk',
729 + 'despair',
730 + 'destroy',
731 + 'detail',
732 + 'detect',
733 + 'develop',
734 + 'device',
735 + 'devote',
736 + 'diagram',
737 + 'dial',
738 + 'diamond',
739 + 'diary',
740 + 'dice',
741 + 'diesel',
742 + 'diet',
743 + 'differ',
744 + 'digital',
745 + 'dignity',
746 + 'dilemma',
747 + 'dinner',
748 + 'dinosaur',
749 + 'direct',
750 + 'dirt',
751 + 'disagree',
752 + 'discover',
753 + 'disease',
754 + 'dish',
755 + 'dismiss',
756 + 'disorder',
757 + 'display',
758 + 'distance',
759 + 'divert',
760 + 'divide',
761 + 'divorce',
762 + 'dizzy',
763 + 'doctor',
764 + 'document',
765 + 'dog',
766 + 'doll',
767 + 'dolphin',
768 + 'domain',
769 + 'donate',
770 + 'donkey',
771 + 'donor',
772 + 'door',
773 + 'dose',
774 + 'double',
775 + 'dove',
776 + 'draft',
777 + 'dragon',
778 + 'drama',
779 + 'drastic',
780 + 'draw',
781 + 'dream',
782 + 'dress',
783 + 'drift',
784 + 'drill',
785 + 'drink',
786 + 'drip',
787 + 'drive',
788 + 'drop',
789 + 'drum',
790 + 'dry',
791 + 'duck',
792 + 'dumb',
793 + 'dune',
794 + 'during',
795 + 'dust',
796 + 'dutch',
797 + 'duty',
798 + 'dwarf',
799 + 'dynamic',
800 + 'eager',
801 + 'eagle',
802 + 'early',
803 + 'earn',
804 + 'earth',
805 + 'easily',
806 + 'east',
807 + 'easy',
808 + 'echo',
809 + 'ecology',
810 + 'economy',
811 + 'edge',
812 + 'edit',
813 + 'educate',
814 + 'effort',
815 + 'egg',
816 + 'eight',
817 + 'either',
818 + 'elbow',
819 + 'elder',
820 + 'electric',
821 + 'elegant',
822 + 'element',
823 + 'elephant',
824 + 'elevator',
825 + 'elite',
826 + 'else',
827 + 'embark',
828 + 'embody',
829 + 'embrace',
830 + 'emerge',
831 + 'emotion',
832 + 'employ',
833 + 'empower',
834 + 'empty',
835 + 'enable',
836 + 'enact',
837 + 'end',
838 + 'endless',
839 + 'endorse',
840 + 'enemy',
841 + 'energy',
842 + 'enforce',
843 + 'engage',
844 + 'engine',
845 + 'enhance',
846 + 'enjoy',
847 + 'enlist',
848 + 'enough',
849 + 'enrich',
850 + 'enroll',
851 + 'ensure',
852 + 'enter',
853 + 'entire',
854 + 'entry',
855 + 'envelope',
856 + 'episode',
857 + 'equal',
858 + 'equip',
859 + 'era',
860 + 'erase',
861 + 'erode',
862 + 'erosion',
863 + 'error',
864 + 'erupt',
865 + 'escape',
866 + 'essay',
867 + 'essence',
868 + 'estate',
869 + 'eternal',
870 + 'ethics',
871 + 'evidence',
872 + 'evil',
873 + 'evoke',
874 + 'evolve',
875 + 'exact',
876 + 'example',
877 + 'excess',
878 + 'exchange',
879 + 'excite',
880 + 'exclude',
881 + 'excuse',
882 + 'execute',
883 + 'exercise',
884 + 'exhaust',
885 + 'exhibit',
886 + 'exile',
887 + 'exist',
888 + 'exit',
889 + 'exotic',
890 + 'expand',
891 + 'expect',
892 + 'expire',
893 + 'explain',
894 + 'expose',
895 + 'express',
896 + 'extend',
897 + 'extra',
898 + 'eye',
899 + 'eyebrow',
900 + 'fabric',
901 + 'face',
902 + 'faculty',
903 + 'fade',
904 + 'faint',
905 + 'faith',
906 + 'fall',
907 + 'false',
908 + 'fame',
909 + 'family',
910 + 'famous',
911 + 'fan',
912 + 'fancy',
913 + 'fantasy',
914 + 'farm',
915 + 'fashion',
916 + 'fat',
917 + 'fatal',
918 + 'father',
919 + 'fatigue',
920 + 'fault',
921 + 'favorite',
922 + 'feature',
923 + 'february',
924 + 'federal',
925 + 'fee',
926 + 'feed',
927 + 'feel',
928 + 'female',
929 + 'fence',
930 + 'festival',
931 + 'fetch',
932 + 'fever',
933 + 'few',
934 + 'fiber',
935 + 'fiction',
936 + 'field',
937 + 'figure',
938 + 'file',
939 + 'film',
940 + 'filter',
941 + 'final',
942 + 'find',
943 + 'fine',
944 + 'finger',
945 + 'finish',
946 + 'fire',
947 + 'firm',
948 + 'first',
949 + 'fiscal',
950 + 'fish',
951 + 'fit',
952 + 'fitness',
953 + 'fix',
954 + 'flag',
955 + 'flame',
956 + 'flash',
957 + 'flat',
958 + 'flavor',
959 + 'flee',
960 + 'flight',
961 + 'flip',
962 + 'float',
963 + 'flock',
964 + 'floor',
965 + 'flower',
966 + 'fluid',
967 + 'flush',
968 + 'fly',
969 + 'foam',
970 + 'focus',
971 + 'fog',
972 + 'foil',
973 + 'fold',
974 + 'follow',
975 + 'food',
976 + 'foot',
977 + 'force',
978 + 'forest',
979 + 'forget',
980 + 'fork',
981 + 'fortune',
982 + 'forum',
983 + 'forward',
984 + 'fossil',
985 + 'foster',
986 + 'found',
987 + 'fox',
988 + 'fragile',
989 + 'frame',
990 + 'frequent',
991 + 'fresh',
992 + 'friend',
993 + 'fringe',
994 + 'frog',
995 + 'front',
996 + 'frost',
997 + 'frown',
998 + 'frozen',
999 + 'fruit',
1000 + 'fuel',
1001 + 'fun',
1002 + 'funny',
1003 + 'furnace',
1004 + 'fury',
1005 + 'future',
1006 + 'gadget',
1007 + 'gain',
1008 + 'galaxy',
1009 + 'gallery',
1010 + 'game',
1011 + 'gap',
1012 + 'garage',
1013 + 'garbage',
1014 + 'garden',
1015 + 'garlic',
1016 + 'garment',
1017 + 'gas',
1018 + 'gasp',
1019 + 'gate',
1020 + 'gather',
1021 + 'gauge',
1022 + 'gaze',
1023 + 'general',
1024 + 'genius',
1025 + 'genre',
1026 + 'gentle',
1027 + 'genuine',
1028 + 'gesture',
1029 + 'ghost',
1030 + 'giant',
1031 + 'gift',
1032 + 'giggle',
1033 + 'ginger',
1034 + 'giraffe',
1035 + 'girl',
1036 + 'give',
1037 + 'glad',
1038 + 'glance',
1039 + 'glare',
1040 + 'glass',
1041 + 'glide',
1042 + 'glimpse',
1043 + 'globe',
1044 + 'gloom',
1045 + 'glory',
1046 + 'glove',
1047 + 'glow',
1048 + 'glue',
1049 + 'goat',
1050 + 'goddess',
1051 + 'gold',
1052 + 'good',
1053 + 'goose',
1054 + 'gorilla',
1055 + 'gospel',
1056 + 'gossip',
1057 + 'govern',
1058 + 'gown',
1059 + 'grab',
1060 + 'grace',
1061 + 'grain',
1062 + 'grant',
1063 + 'grape',
1064 + 'grass',
1065 + 'gravity',
1066 + 'great',
1067 + 'green',
1068 + 'grid',
1069 + 'grief',
1070 + 'grit',
1071 + 'grocery',
1072 + 'group',
1073 + 'grow',
1074 + 'grunt',
1075 + 'guard',
1076 + 'guess',
1077 + 'guide',
1078 + 'guilt',
1079 + 'guitar',
1080 + 'gun',
1081 + 'gym',
1082 + 'habit',
1083 + 'hair',
1084 + 'half',
1085 + 'hammer',
1086 + 'hamster',
1087 + 'hand',
1088 + 'happy',
1089 + 'harbor',
1090 + 'hard',
1091 + 'harsh',
1092 + 'harvest',
1093 + 'hat',
1094 + 'have',
1095 + 'hawk',
1096 + 'hazard',
1097 + 'head',
1098 + 'health',
1099 + 'heart',
1100 + 'heavy',
1101 + 'hedgehog',
1102 + 'height',
1103 + 'hello',
1104 + 'helmet',
1105 + 'help',
1106 + 'hen',
1107 + 'hero',
1108 + 'hidden',
1109 + 'high',
1110 + 'hill',
1111 + 'hint',
1112 + 'hip',
1113 + 'hire',
1114 + 'history',
1115 + 'hobby',
1116 + 'hockey',
1117 + 'hold',
1118 + 'hole',
1119 + 'holiday',
1120 + 'hollow',
1121 + 'home',
1122 + 'honey',
1123 + 'hood',
1124 + 'hope',
1125 + 'horn',
1126 + 'horror',
1127 + 'horse',
1128 + 'hospital',
1129 + 'host',
1130 + 'hotel',
1131 + 'hour',
1132 + 'hover',
1133 + 'hub',
1134 + 'huge',
1135 + 'human',
1136 + 'humble',
1137 + 'humor',
1138 + 'hundred',
1139 + 'hungry',
1140 + 'hunt',
1141 + 'hurdle',
1142 + 'hurry',
1143 + 'hurt',
1144 + 'husband',
1145 + 'hybrid',
1146 + 'ice',
1147 + 'icon',
1148 + 'idea',
1149 + 'identify',
1150 + 'idle',
1151 + 'ignore',
1152 + 'ill',
1153 + 'illegal',
1154 + 'illness',
1155 + 'image',
1156 + 'imitate',
1157 + 'immense',
1158 + 'immune',
1159 + 'impact',
1160 + 'impose',
1161 + 'improve',
1162 + 'impulse',
1163 + 'inch',
1164 + 'include',
1165 + 'income',
1166 + 'increase',
1167 + 'index',
1168 + 'indicate',
1169 + 'indoor',
1170 + 'industry',
1171 + 'infant',
1172 + 'inflict',
1173 + 'inform',
1174 + 'inhale',
1175 + 'inherit',
1176 + 'initial',
1177 + 'inject',
1178 + 'injury',
1179 + 'inmate',
1180 + 'inner',
1181 + 'innocent',
1182 + 'input',
1183 + 'inquiry',
1184 + 'insane',
1185 + 'insect',
1186 + 'inside',
1187 + 'inspire',
1188 + 'install',
1189 + 'intact',
1190 + 'interest',
1191 + 'into',
1192 + 'invest',
1193 + 'invite',
1194 + 'involve',
1195 + 'iron',
1196 + 'island',
1197 + 'isolate',
1198 + 'issue',
1199 + 'item',
1200 + 'ivory',
1201 + 'jacket',
1202 + 'jaguar',
1203 + 'jar',
1204 + 'jazz',
1205 + 'jealous',
1206 + 'jeans',
1207 + 'jelly',
1208 + 'jewel',
1209 + 'job',
1210 + 'join',
1211 + 'joke',
1212 + 'journey',
1213 + 'joy',
1214 + 'judge',
1215 + 'juice',
1216 + 'jump',
1217 + 'jungle',
1218 + 'junior',
1219 + 'junk',
1220 + 'just',
1221 + 'kangaroo',
1222 + 'keen',
1223 + 'keep',
1224 + 'ketchup',
1225 + 'key',
1226 + 'kick',
1227 + 'kid',
1228 + 'kidney',
1229 + 'kind',
1230 + 'kingdom',
1231 + 'kiss',
1232 + 'kit',
1233 + 'kitchen',
1234 + 'kite',
1235 + 'kitten',
1236 + 'kiwi',
1237 + 'knee',
1238 + 'knife',
1239 + 'knock',
1240 + 'know',
1241 + 'lab',
1242 + 'label',
1243 + 'labor',
1244 + 'ladder',
1245 + 'lady',
1246 + 'lake',
1247 + 'lamp',
1248 + 'language',
1249 + 'laptop',
1250 + 'large',
1251 + 'later',
1252 + 'latin',
1253 + 'laugh',
1254 + 'laundry',
1255 + 'lava',
1256 + 'law',
1257 + 'lawn',
1258 + 'lawsuit',
1259 + 'layer',
1260 + 'lazy',
1261 + 'leader',
1262 + 'leaf',
1263 + 'learn',
1264 + 'leave',
1265 + 'lecture',
1266 + 'left',
1267 + 'leg',
1268 + 'legal',
1269 + 'legend',
1270 + 'leisure',
1271 + 'lemon',
1272 + 'lend',
1273 + 'length',
1274 + 'lens',
1275 + 'leopard',
1276 + 'lesson',
1277 + 'letter',
1278 + 'level',
1279 + 'liar',
1280 + 'liberty',
1281 + 'library',
1282 + 'license',
1283 + 'life',
1284 + 'lift',
1285 + 'light',
1286 + 'like',
1287 + 'limb',
1288 + 'limit',
1289 + 'link',
1290 + 'lion',
1291 + 'liquid',
1292 + 'list',
1293 + 'little',
1294 + 'live',
1295 + 'lizard',
1296 + 'load',
1297 + 'loan',
1298 + 'lobster',
1299 + 'local',
1300 + 'lock',
1301 + 'logic',
1302 + 'lonely',
1303 + 'long',
1304 + 'loop',
1305 + 'lottery',
1306 + 'loud',
1307 + 'lounge',
1308 + 'love',
1309 + 'loyal',
1310 + 'lucky',
1311 + 'luggage',
1312 + 'lumber',
1313 + 'lunar',
1314 + 'lunch',
1315 + 'luxury',
1316 + 'lyrics',
1317 + 'machine',
1318 + 'mad',
1319 + 'magic',
1320 + 'magnet',
1321 + 'maid',
1322 + 'mail',
1323 + 'main',
1324 + 'major',
1325 + 'make',
1326 + 'mammal',
1327 + 'man',
1328 + 'manage',
1329 + 'mandate',
1330 + 'mango',
1331 + 'mansion',
1332 + 'manual',
1333 + 'maple',
1334 + 'marble',
1335 + 'march',
1336 + 'margin',
1337 + 'marine',
1338 + 'market',
1339 + 'marriage',
1340 + 'mask',
1341 + 'mass',
1342 + 'master',
1343 + 'match',
1344 + 'material',
1345 + 'math',
1346 + 'matrix',
1347 + 'matter',
1348 + 'maximum',
1349 + 'maze',
1350 + 'meadow',
1351 + 'mean',
1352 + 'measure',
1353 + 'meat',
1354 + 'mechanic',
1355 + 'medal',
1356 + 'media',
1357 + 'melody',
1358 + 'melt',
1359 + 'member',
1360 + 'memory',
1361 + 'mention',
1362 + 'menu',
1363 + 'mercy',
1364 + 'merge',
1365 + 'merit',
1366 + 'merry',
1367 + 'mesh',
1368 + 'message',
1369 + 'metal',
1370 + 'method',
1371 + 'middle',
1372 + 'midnight',
1373 + 'milk',
1374 + 'million',
1375 + 'mimic',
1376 + 'mind',
1377 + 'minimum',
1378 + 'minor',
1379 + 'minute',
1380 + 'miracle',
1381 + 'mirror',
1382 + 'misery',
1383 + 'miss',
1384 + 'mistake',
1385 + 'mix',
1386 + 'mixed',
1387 + 'mixture',
1388 + 'mobile',
1389 + 'model',
1390 + 'modify',
1391 + 'mom',
1392 + 'moment',
1393 + 'monitor',
1394 + 'monkey',
1395 + 'monster',
1396 + 'month',
1397 + 'moon',
1398 + 'moral',
1399 + 'more',
1400 + 'morning',
1401 + 'mosquito',
1402 + 'mother',
1403 + 'motion',
1404 + 'motor',
1405 + 'mountain',
1406 + 'mouse',
1407 + 'move',
1408 + 'movie',
1409 + 'much',
1410 + 'muffin',
1411 + 'mule',
1412 + 'multiply',
1413 + 'muscle',
1414 + 'museum',
1415 + 'mushroom',
1416 + 'music',
1417 + 'must',
1418 + 'mutual',
1419 + 'myself',
1420 + 'mystery',
1421 + 'myth',
1422 + 'naive',
1423 + 'name',
1424 + 'napkin',
1425 + 'narrow',
1426 + 'nasty',
1427 + 'nation',
1428 + 'nature',
1429 + 'near',
1430 + 'neck',
1431 + 'need',
1432 + 'negative',
1433 + 'neglect',
1434 + 'neither',
1435 + 'nephew',
1436 + 'nerve',
1437 + 'nest',
1438 + 'net',
1439 + 'network',
1440 + 'neutral',
1441 + 'never',
1442 + 'news',
1443 + 'next',
1444 + 'nice',
1445 + 'night',
1446 + 'noble',
1447 + 'noise',
1448 + 'nominee',
1449 + 'noodle',
1450 + 'normal',
1451 + 'north',
1452 + 'nose',
1453 + 'notable',
1454 + 'note',
1455 + 'nothing',
1456 + 'notice',
1457 + 'novel',
1458 + 'now',
1459 + 'nuclear',
1460 + 'number',
1461 + 'nurse',
1462 + 'nut',
1463 + 'oak',
1464 + 'obey',
1465 + 'object',
1466 + 'oblige',
1467 + 'obscure',
1468 + 'observe',
1469 + 'obtain',
1470 + 'obvious',
1471 + 'occur',
1472 + 'ocean',
1473 + 'october',
1474 + 'odor',
1475 + 'off',
1476 + 'offer',
1477 + 'office',
1478 + 'often',
1479 + 'oil',
1480 + 'okay',
1481 + 'old',
1482 + 'olive',
1483 + 'olympic',
1484 + 'omit',
1485 + 'once',
1486 + 'one',
1487 + 'onion',
1488 + 'online',
1489 + 'only',
1490 + 'open',
1491 + 'opera',
1492 + 'opinion',
1493 + 'oppose',
1494 + 'option',
1495 + 'orange',
1496 + 'orbit',
1497 + 'orchard',
1498 + 'order',
1499 + 'ordinary',
1500 + 'organ',
1501 + 'orient',
1502 + 'original',
1503 + 'orphan',
1504 + 'ostrich',
1505 + 'other',
1506 + 'outdoor',
1507 + 'outer',
1508 + 'output',
1509 + 'outside',
1510 + 'oval',
1511 + 'oven',
1512 + 'over',
1513 + 'own',
1514 + 'owner',
1515 + 'oxygen',
1516 + 'oyster',
1517 + 'ozone',
1518 + 'pact',
1519 + 'paddle',
1520 + 'page',
1521 + 'pair',
1522 + 'palace',
1523 + 'palm',
1524 + 'panda',
1525 + 'panel',
1526 + 'panic',
1527 + 'panther',
1528 + 'paper',
1529 + 'parade',
1530 + 'parent',
1531 + 'park',
1532 + 'parrot',
1533 + 'party',
1534 + 'pass',
1535 + 'patch',
1536 + 'path',
1537 + 'patient',
1538 + 'patrol',
1539 + 'pattern',
1540 + 'pause',
1541 + 'pave',
1542 + 'payment',
1543 + 'peace',
1544 + 'peanut',
1545 + 'pear',
1546 + 'peasant',
1547 + 'pelican',
1548 + 'pen',
1549 + 'penalty',
1550 + 'pencil',
1551 + 'people',
1552 + 'pepper',
1553 + 'perfect',
1554 + 'permit',
1555 + 'person',
1556 + 'pet',
1557 + 'phone',
1558 + 'photo',
1559 + 'phrase',
1560 + 'physical',
1561 + 'piano',
1562 + 'picnic',
1563 + 'picture',
1564 + 'piece',
1565 + 'pig',
1566 + 'pigeon',
1567 + 'pill',
1568 + 'pilot',
1569 + 'pink',
1570 + 'pioneer',
1571 + 'pipe',
1572 + 'pistol',
1573 + 'pitch',
1574 + 'pizza',
1575 + 'place',
1576 + 'planet',
1577 + 'plastic',
1578 + 'plate',
1579 + 'play',
1580 + 'please',
1581 + 'pledge',
1582 + 'pluck',
1583 + 'plug',
1584 + 'plunge',
1585 + 'poem',
1586 + 'poet',
1587 + 'point',
1588 + 'polar',
1589 + 'pole',
1590 + 'police',
1591 + 'pond',
1592 + 'pony',
1593 + 'pool',
1594 + 'popular',
1595 + 'portion',
1596 + 'position',
1597 + 'possible',
1598 + 'post',
1599 + 'potato',
1600 + 'pottery',
1601 + 'poverty',
1602 + 'powder',
1603 + 'power',
1604 + 'practice',
1605 + 'praise',
1606 + 'predict',
1607 + 'prefer',
1608 + 'prepare',
1609 + 'present',
1610 + 'pretty',
1611 + 'prevent',
1612 + 'price',
1613 + 'pride',
1614 + 'primary',
1615 + 'print',
1616 + 'priority',
1617 + 'prison',
1618 + 'private',
1619 + 'prize',
1620 + 'problem',
1621 + 'process',
1622 + 'produce',
1623 + 'profit',
1624 + 'program',
1625 + 'project',
1626 + 'promote',
1627 + 'proof',
1628 + 'property',
1629 + 'prosper',
1630 + 'protect',
1631 + 'proud',
1632 + 'provide',
1633 + 'public',
1634 + 'pudding',
1635 + 'pull',
1636 + 'pulp',
1637 + 'pulse',
1638 + 'pumpkin',
1639 + 'punch',
1640 + 'pupil',
1641 + 'puppy',
1642 + 'purchase',
1643 + 'purity',
1644 + 'purpose',
1645 + 'purse',
1646 + 'push',
1647 + 'put',
1648 + 'puzzle',
1649 + 'pyramid',
1650 + 'quality',
1651 + 'quantum',
1652 + 'quarter',
1653 + 'question',
1654 + 'quick',
1655 + 'quit',
1656 + 'quiz',
1657 + 'quote',
1658 + 'rabbit',
1659 + 'raccoon',
1660 + 'race',
1661 + 'rack',
1662 + 'radar',
1663 + 'radio',
1664 + 'rail',
1665 + 'rain',
1666 + 'raise',
1667 + 'rally',
1668 + 'ramp',
1669 + 'ranch',
1670 + 'random',
1671 + 'range',
1672 + 'rapid',
1673 + 'rare',
1674 + 'rate',
1675 + 'rather',
1676 + 'raven',
1677 + 'raw',
1678 + 'razor',
1679 + 'ready',
1680 + 'real',
1681 + 'reason',
1682 + 'rebel',
1683 + 'rebuild',
1684 + 'recall',
1685 + 'receive',
1686 + 'recipe',
1687 + 'record',
1688 + 'recycle',
1689 + 'reduce',
1690 + 'reflect',
1691 + 'reform',
1692 + 'refuse',
1693 + 'region',
1694 + 'regret',
1695 + 'regular',
1696 + 'reject',
1697 + 'relax',
1698 + 'release',
1699 + 'relief',
1700 + 'rely',
1701 + 'remain',
1702 + 'remember',
1703 + 'remind',
1704 + 'remove',
1705 + 'render',
1706 + 'renew',
1707 + 'rent',
1708 + 'reopen',
1709 + 'repair',
1710 + 'repeat',
1711 + 'replace',
1712 + 'report',
1713 + 'require',
1714 + 'rescue',
1715 + 'resemble',
1716 + 'resist',
1717 + 'resource',
1718 + 'response',
1719 + 'result',
1720 + 'retire',
1721 + 'retreat',
1722 + 'return',
1723 + 'reunion',
1724 + 'reveal',
1725 + 'review',
1726 + 'reward',
1727 + 'rhythm',
1728 + 'rib',
1729 + 'ribbon',
1730 + 'rice',
1731 + 'rich',
1732 + 'ride',
1733 + 'ridge',
1734 + 'rifle',
1735 + 'right',
1736 + 'rigid',
1737 + 'ring',
1738 + 'riot',
1739 + 'ripple',
1740 + 'risk',
1741 + 'ritual',
1742 + 'rival',
1743 + 'river',
1744 + 'road',
1745 + 'roast',
1746 + 'robot',
1747 + 'robust',
1748 + 'rocket',
1749 + 'romance',
1750 + 'roof',
1751 + 'rookie',
1752 + 'room',
1753 + 'rose',
1754 + 'rotate',
1755 + 'rough',
1756 + 'round',
1757 + 'route',
1758 + 'royal',
1759 + 'rubber',
1760 + 'rude',
1761 + 'rug',
1762 + 'rule',
1763 + 'run',
1764 + 'runway',
1765 + 'rural',
1766 + 'sad',
1767 + 'saddle',
1768 + 'sadness',
1769 + 'safe',
1770 + 'sail',
1771 + 'salad',
1772 + 'salmon',
1773 + 'salon',
1774 + 'salt',
1775 + 'salute',
1776 + 'same',
1777 + 'sample',
1778 + 'sand',
1779 + 'satisfy',
1780 + 'satoshi',
1781 + 'sauce',
1782 + 'sausage',
1783 + 'save',
1784 + 'say',
1785 + 'scale',
1786 + 'scan',
1787 + 'scare',
1788 + 'scatter',
1789 + 'scene',
1790 + 'scheme',
1791 + 'school',
1792 + 'science',
1793 + 'scissors',
1794 + 'scorpion',
1795 + 'scout',
1796 + 'scrap',
1797 + 'screen',
1798 + 'script',
1799 + 'scrub',
1800 + 'sea',
1801 + 'search',
1802 + 'season',
1803 + 'seat',
1804 + 'second',
1805 + 'secret',
1806 + 'section',
1807 + 'security',
1808 + 'seed',
1809 + 'seek',
1810 + 'segment',
1811 + 'select',
1812 + 'sell',
1813 + 'seminar',
1814 + 'senior',
1815 + 'sense',
1816 + 'sentence',
1817 + 'series',
1818 + 'service',
1819 + 'session',
1820 + 'settle',
1821 + 'setup',
1822 + 'seven',
1823 + 'shadow',
1824 + 'shaft',
1825 + 'shallow',
1826 + 'share',
1827 + 'shed',
1828 + 'shell',
1829 + 'sheriff',
1830 + 'shield',
1831 + 'shift',
1832 + 'shine',
1833 + 'ship',
1834 + 'shiver',
1835 + 'shock',
1836 + 'shoe',
1837 + 'shoot',
1838 + 'shop',
1839 + 'short',
1840 + 'shoulder',
1841 + 'shove',
1842 + 'shrimp',
1843 + 'shrug',
1844 + 'shuffle',
1845 + 'shy',
1846 + 'sibling',
1847 + 'sick',
1848 + 'side',
1849 + 'siege',
1850 + 'sight',
1851 + 'sign',
1852 + 'silent',
1853 + 'silk',
1854 + 'silly',
1855 + 'silver',
1856 + 'similar',
1857 + 'simple',
1858 + 'since',
1859 + 'sing',
1860 + 'siren',
1861 + 'sister',
1862 + 'situate',
1863 + 'six',
1864 + 'size',
1865 + 'skate',
1866 + 'sketch',
1867 + 'ski',
1868 + 'skill',
1869 + 'skin',
1870 + 'skirt',
1871 + 'skull',
1872 + 'slab',
1873 + 'slam',
1874 + 'sleep',
1875 + 'slender',
1876 + 'slice',
1877 + 'slide',
1878 + 'slight',
1879 + 'slim',
1880 + 'slogan',
1881 + 'slot',
1882 + 'slow',
1883 + 'slush',
1884 + 'small',
1885 + 'smart',
1886 + 'smile',
1887 + 'smoke',
1888 + 'smooth',
1889 + 'snack',
1890 + 'snake',
1891 + 'snap',
1892 + 'sniff',
1893 + 'snow',
1894 + 'soap',
1895 + 'soccer',
1896 + 'social',
1897 + 'sock',
1898 + 'soda',
1899 + 'soft',
1900 + 'solar',
1901 + 'soldier',
1902 + 'solid',
1903 + 'solution',
1904 + 'solve',
1905 + 'someone',
1906 + 'song',
1907 + 'soon',
1908 + 'sorry',
1909 + 'sort',
1910 + 'soul',
1911 + 'sound',
1912 + 'soup',
1913 + 'source',
1914 + 'south',
1915 + 'space',
1916 + 'spare',
1917 + 'spatial',
1918 + 'spawn',
1919 + 'speak',
1920 + 'special',
1921 + 'speed',
1922 + 'spell',
1923 + 'spend',
1924 + 'sphere',
1925 + 'spice',
1926 + 'spider',
1927 + 'spike',
1928 + 'spin',
1929 + 'spirit',
1930 + 'split',
1931 + 'spoil',
1932 + 'sponsor',
1933 + 'spoon',
1934 + 'sport',
1935 + 'spot',
1936 + 'spray',
1937 + 'spread',
1938 + 'spring',
1939 + 'spy',
1940 + 'square',
1941 + 'squeeze',
1942 + 'squirrel',
1943 + 'stable',
1944 + 'stadium',
1945 + 'staff',
1946 + 'stage',
1947 + 'stairs',
1948 + 'stamp',
1949 + 'stand',
1950 + 'start',
1951 + 'state',
1952 + 'stay',
1953 + 'steak',
1954 + 'steel',
1955 + 'stem',
1956 + 'step',
1957 + 'stereo',
1958 + 'stick',
1959 + 'still',
1960 + 'sting',
1961 + 'stock',
1962 + 'stomach',
1963 + 'stone',
1964 + 'stool',
1965 + 'story',
1966 + 'stove',
1967 + 'strategy',
1968 + 'street',
1969 + 'strike',
1970 + 'strong',
1971 + 'struggle',
1972 + 'student',
1973 + 'stuff',
1974 + 'stumble',
1975 + 'style',
1976 + 'subject',
1977 + 'submit',
1978 + 'subway',
1979 + 'success',
1980 + 'such',
1981 + 'sudden',
1982 + 'suffer',
1983 + 'sugar',
1984 + 'suggest',
1985 + 'suit',
1986 + 'summer',
1987 + 'sun',
1988 + 'sunny',
1989 + 'sunset',
1990 + 'super',
1991 + 'supply',
1992 + 'supreme',
1993 + 'sure',
1994 + 'surface',
1995 + 'surge',
1996 + 'surprise',
1997 + 'surround',
1998 + 'survey',
1999 + 'suspect',
2000 + 'sustain',
2001 + 'swallow',
2002 + 'swamp',
2003 + 'swap',
2004 + 'swarm',
2005 + 'swear',
2006 + 'sweet',
2007 + 'swift',
2008 + 'swim',
2009 + 'swing',
2010 + 'switch',
2011 + 'sword',
2012 + 'symbol',
2013 + 'symptom',
2014 + 'syrup',
2015 + 'system',
2016 + 'table',
2017 + 'tackle',
2018 + 'tag',
2019 + 'tail',
2020 + 'talent',
2021 + 'talk',
2022 + 'tank',
2023 + 'tape',
2024 + 'target',
2025 + 'task',
2026 + 'taste',
2027 + 'tattoo',
2028 + 'taxi',
2029 + 'teach',
2030 + 'team',
2031 + 'tell',
2032 + 'ten',
2033 + 'tenant',
2034 + 'tennis',
2035 + 'tent',
2036 + 'term',
2037 + 'test',
2038 + 'text',
2039 + 'thank',
2040 + 'that',
2041 + 'theme',
2042 + 'then',
2043 + 'theory',
2044 + 'there',
2045 + 'they',
2046 + 'thing',
2047 + 'this',
2048 + 'thought',
2049 + 'three',
2050 + 'thrive',
2051 + 'throw',
2052 + 'thumb',
2053 + 'thunder',
2054 + 'ticket',
2055 + 'tide',
2056 + 'tiger',
2057 + 'tilt',
2058 + 'timber',
2059 + 'time',
2060 + 'tiny',
2061 + 'tip',
2062 + 'tired',
2063 + 'tissue',
2064 + 'title',
2065 + 'toast',
2066 + 'tobacco',
2067 + 'today',
2068 + 'toddler',
2069 + 'toe',
2070 + 'together',
2071 + 'toilet',
2072 + 'token',
2073 + 'tomato',
2074 + 'tomorrow',
2075 + 'tone',
2076 + 'tongue',
2077 + 'tonight',
2078 + 'tool',
2079 + 'tooth',
2080 + 'top',
2081 + 'topic',
2082 + 'topple',
2083 + 'torch',
2084 + 'tornado',
2085 + 'tortoise',
2086 + 'toss',
2087 + 'total',
2088 + 'tourist',
2089 + 'toward',
2090 + 'tower',
2091 + 'town',
2092 + 'toy',
2093 + 'track',
2094 + 'trade',
2095 + 'traffic',
2096 + 'tragic',
2097 + 'train',
2098 + 'transfer',
2099 + 'trap',
2100 + 'trash',
2101 + 'travel',
2102 + 'tray',
2103 + 'treat',
2104 + 'tree',
2105 + 'trend',
2106 + 'trial',
2107 + 'tribe',
2108 + 'trick',
2109 + 'trigger',
2110 + 'trim',
2111 + 'trip',
2112 + 'trophy',
2113 + 'trouble',
2114 + 'truck',
2115 + 'true',
2116 + 'truly',
2117 + 'trumpet',
2118 + 'trust',
2119 + 'truth',
2120 + 'try',
2121 + 'tube',
2122 + 'tuition',
2123 + 'tumble',
2124 + 'tuna',
2125 + 'tunnel',
2126 + 'turkey',
2127 + 'turn',
2128 + 'turtle',
2129 + 'twelve',
2130 + 'twenty',
2131 + 'twice',
2132 + 'twin',
2133 + 'twist',
2134 + 'two',
2135 + 'type',
2136 + 'typical',
2137 + 'ugly',
2138 + 'umbrella',
2139 + 'unable',
2140 + 'unaware',
2141 + 'uncle',
2142 + 'uncover',
2143 + 'under',
2144 + 'undo',
2145 + 'unfair',
2146 + 'unfold',
2147 + 'unhappy',
2148 + 'uniform',
2149 + 'unique',
2150 + 'unit',
2151 + 'universe',
2152 + 'unknown',
2153 + 'unlock',
2154 + 'until',
2155 + 'unusual',
2156 + 'unveil',
2157 + 'update',
2158 + 'upgrade',
2159 + 'uphold',
2160 + 'upon',
2161 + 'upper',
2162 + 'upset',
2163 + 'urban',
2164 + 'urge',
2165 + 'usage',
2166 + 'use',
2167 + 'used',
2168 + 'useful',
2169 + 'useless',
2170 + 'usual',
2171 + 'utility',
2172 + 'vacant',
2173 + 'vacuum',
2174 + 'vague',
2175 + 'valid',
2176 + 'valley',
2177 + 'valve',
2178 + 'van',
2179 + 'vanish',
2180 + 'vapor',
2181 + 'various',
2182 + 'vast',
2183 + 'vault',
2184 + 'vehicle',
2185 + 'velvet',
2186 + 'vendor',
2187 + 'venture',
2188 + 'venue',
2189 + 'verb',
2190 + 'verify',
2191 + 'version',
2192 + 'very',
2193 + 'vessel',
2194 + 'veteran',
2195 + 'viable',
2196 + 'vibrant',
2197 + 'vicious',
2198 + 'victory',
2199 + 'video',
2200 + 'view',
2201 + 'village',
2202 + 'vintage',
2203 + 'violin',
2204 + 'virtual',
2205 + 'virus',
2206 + 'visa',
2207 + 'visit',
2208 + 'visual',
2209 + 'vital',
2210 + 'vivid',
2211 + 'vocal',
2212 + 'voice',
2213 + 'void',
2214 + 'volcano',
2215 + 'volume',
2216 + 'vote',
2217 + 'voyage',
2218 + 'wage',
2219 + 'wagon',
2220 + 'wait',
2221 + 'walk',
2222 + 'wall',
2223 + 'walnut',
2224 + 'want',
2225 + 'warfare',
2226 + 'warm',
2227 + 'warrior',
2228 + 'wash',
2229 + 'wasp',
2230 + 'waste',
2231 + 'water',
2232 + 'wave',
2233 + 'way',
2234 + 'wealth',
2235 + 'weapon',
2236 + 'wear',
2237 + 'weasel',
2238 + 'weather',
2239 + 'web',
2240 + 'wedding',
2241 + 'weekend',
2242 + 'weird',
2243 + 'welcome',
2244 + 'west',
2245 + 'wet',
2246 + 'whale',
2247 + 'what',
2248 + 'wheat',
2249 + 'wheel',
2250 + 'when',
2251 + 'where',
2252 + 'whip',
2253 + 'whisper',
2254 + 'wide',
2255 + 'width',
2256 + 'wife',
2257 + 'wild',
2258 + 'will',
2259 + 'win',
2260 + 'window',
2261 + 'wine',
2262 + 'wing',
2263 + 'wink',
2264 + 'winner',
2265 + 'winter',
2266 + 'wire',
2267 + 'wisdom',
2268 + 'wise',
2269 + 'wish',
2270 + 'witness',
2271 + 'wolf',
2272 + 'woman',
2273 + 'wonder',
2274 + 'wood',
2275 + 'wool',
2276 + 'word',
2277 + 'work',
2278 + 'world',
2279 + 'worry',
2280 + 'worth',
2281 + 'wrap',
2282 + 'wreck',
2283 + 'wrestle',
2284 + 'wrist',
2285 + 'write',
2286 + 'wrong',
2287 + 'yard',
2288 + 'year',
2289 + 'yellow',
2290 + 'you',
2291 + 'young',
2292 + 'youth',
2293 + 'zebra',
2294 + 'zero',
2295 + 'zone',
2296 + 'zoo'
2297 +];
cw_bitcoin/lib/bitcoin_mnemonic_is_incorrect_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class BitcoinMnemonicIsIncorrectException implements Exception {
2 + @override
3 + String toString() =>
4 + 'Bitcoin mnemonic has incorrect format. Mnemonic should contain 12 or 24 words separated by space.';
5 +}
cw_bitcoin/lib/bitcoin_transaction_credentials.dart new
+9
@@ -0,0 +1,9 @@
1 +import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
2 +import 'package:cw_core/output_info.dart';
3 +
4 +class BitcoinTransactionCredentials {
5 + BitcoinTransactionCredentials(this.outputs, this.priority);
6 +
7 + final List<OutputInfo> outputs;
8 + BitcoinTransactionPriority priority;
9 +}
cw_bitcoin/lib/bitcoin_transaction_no_inputs_exception.dart new
+4
@@ -0,0 +1,4 @@
1 +class BitcoinTransactionNoInputsException implements Exception {
2 + @override
3 + String toString() => 'Not enough inputs available';
4 +}
cw_bitcoin/lib/bitcoin_transaction_priority.dart new
+103
@@ -0,0 +1,103 @@
1 +import 'package:cw_core/transaction_priority.dart';
2 +import 'package:cake_wallet/generated/i18n.dart';
3 +
4 +class BitcoinTransactionPriority extends TransactionPriority {
5 + const BitcoinTransactionPriority({String title, int raw})
6 + : super(title: title, raw: raw);
7 +
8 + static const List<BitcoinTransactionPriority> all = [fast, medium, slow];
9 + static const BitcoinTransactionPriority slow =
10 + BitcoinTransactionPriority(title: 'Slow', raw: 0);
11 + static const BitcoinTransactionPriority medium =
12 + BitcoinTransactionPriority(title: 'Medium', raw: 1);
13 + static const BitcoinTransactionPriority fast =
14 + BitcoinTransactionPriority(title: 'Fast', raw: 2);
15 +
16 + static BitcoinTransactionPriority deserialize({int raw}) {
17 + switch (raw) {
18 + case 0:
19 + return slow;
20 + case 1:
21 + return medium;
22 + case 2:
23 + return fast;
24 + default:
25 + return null;
26 + }
27 + }
28 +
29 + String get units => 'sat';
30 +
31 + @override
32 + String toString() {
33 + var label = '';
34 +
35 + switch (this) {
36 + case BitcoinTransactionPriority.slow:
37 + label = '${S.current.transaction_priority_slow} ~24hrs';
38 + break;
39 + case BitcoinTransactionPriority.medium:
40 + label = S.current.transaction_priority_medium;
41 + break;
42 + case BitcoinTransactionPriority.fast:
43 + label = S.current.transaction_priority_fast;
44 + break;
45 + default:
46 + break;
47 + }
48 +
49 + return label;
50 + }
51 +
52 + String labelWithRate(int rate) => '${toString()} ($rate ${units}/byte)';
53 +}
54 +
55 +class LitecoinTransactionPriority extends BitcoinTransactionPriority {
56 + const LitecoinTransactionPriority({String title, int raw})
57 + : super(title: title, raw: raw);
58 +
59 + static const List<LitecoinTransactionPriority> all = [fast, medium, slow];
60 + static const LitecoinTransactionPriority slow =
61 + LitecoinTransactionPriority(title: 'Slow', raw: 0);
62 + static const LitecoinTransactionPriority medium =
63 + LitecoinTransactionPriority(title: 'Medium', raw: 1);
64 + static const LitecoinTransactionPriority fast =
65 + LitecoinTransactionPriority(title: 'Fast', raw: 2);
66 +
67 + static LitecoinTransactionPriority deserialize({int raw}) {
68 + switch (raw) {
69 + case 0:
70 + return slow;
71 + case 1:
72 + return medium;
73 + case 2:
74 + return fast;
75 + default:
76 + return null;
77 + }
78 + }
79 +
80 + @override
81 + String get units => 'Latoshi';
82 +
83 + @override
84 + String toString() {
85 + var label = '';
86 +
87 + switch (this) {
88 + case LitecoinTransactionPriority.slow:
89 + label = S.current.transaction_priority_slow;
90 + break;
91 + case LitecoinTransactionPriority.medium:
92 + label = S.current.transaction_priority_medium;
93 + break;
94 + case LitecoinTransactionPriority.fast:
95 + label = S.current.transaction_priority_fast;
96 + break;
97 + default:
98 + break;
99 + }
100 +
101 + return label;
102 + }
103 +}
cw_bitcoin/lib/bitcoin_transaction_wrong_balance_exception.dart new
+10
@@ -0,0 +1,10 @@
1 +import 'package:cw_core/crypto_currency.dart';
2 +
3 +class BitcoinTransactionWrongBalanceException implements Exception {
4 + BitcoinTransactionWrongBalanceException(this.currency);
5 +
6 + final CryptoCurrency currency;
7 +
8 + @override
9 + String toString() => 'Wrong balance. Not enough ${currency.title} on your balance.';
10 +}
\ No newline at end of file
cw_bitcoin/lib/bitcoin_unspent.dart new
+24
@@ -0,0 +1,24 @@
1 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
2 +
3 +class BitcoinUnspent {
4 + BitcoinUnspent(this.address, this.hash, this.value, this.vout)
5 + : isSending = true,
6 + isFrozen = false,
7 + note = '';
8 +
9 + factory BitcoinUnspent.fromJSON(
10 + BitcoinAddressRecord address, Map<String, dynamic> json) =>
11 + BitcoinUnspent(address, json['tx_hash'] as String, json['value'] as int,
12 + json['tx_pos'] as int);
13 +
14 + final BitcoinAddressRecord address;
15 + final String hash;
16 + final int value;
17 + final int vout;
18 +
19 + bool get isP2wpkh =>
20 + address.address.startsWith('bc') || address.address.startsWith('ltc');
21 + bool isSending;
22 + bool isFrozen;
23 + String note;
24 +}
cw_bitcoin/lib/bitcoin_wallet.dart new
+63
@@ -0,0 +1,63 @@
1 +import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
2 +import 'package:cw_core/unspent_coins_info.dart';
3 +import 'package:hive/hive.dart';
4 +import 'package:mobx/mobx.dart';
5 +import 'package:flutter/foundation.dart';
6 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
7 +import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
8 +import 'package:cw_bitcoin/electrum_wallet.dart';
9 +import 'package:cw_core/wallet_info.dart';
10 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
11 +import 'package:cw_bitcoin/electrum_balance.dart';
12 +import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
13 +
14 +part 'bitcoin_wallet.g.dart';
15 +
16 +class BitcoinWallet = BitcoinWalletBase with _$BitcoinWallet;
17 +
18 +abstract class BitcoinWalletBase extends ElectrumWallet with Store {
19 + BitcoinWalletBase(
20 + {@required String mnemonic,
21 + @required String password,
22 + @required WalletInfo walletInfo,
23 + @required Box<UnspentCoinsInfo> unspentCoinsInfo,
24 + List<BitcoinAddressRecord> initialAddresses,
25 + ElectrumBalance initialBalance,
26 + int accountIndex = 0})
27 + : super(
28 + mnemonic: mnemonic,
29 + password: password,
30 + walletInfo: walletInfo,
31 + unspentCoinsInfo: unspentCoinsInfo,
32 + networkType: bitcoin.bitcoin,
33 + initialAddresses: initialAddresses,
34 + initialBalance: initialBalance) {
35 + walletAddresses = BitcoinWalletAddresses(
36 + walletInfo,
37 + initialAddresses: initialAddresses,
38 + accountIndex: accountIndex,
39 + mainHd: hd,
40 + sideHd: bitcoin.HDWallet.fromSeed(
41 + mnemonicToSeedBytes(mnemonic), network: networkType)
42 + .derivePath("m/0'/1"),
43 + networkType: networkType);
44 + }
45 +
46 + static Future<BitcoinWallet> open({
47 + @required String name,
48 + @required WalletInfo walletInfo,
49 + @required Box<UnspentCoinsInfo> unspentCoinsInfo,
50 + @required String password,
51 + }) async {
52 + final snp = ElectrumWallletSnapshot(name, walletInfo.type, password);
53 + await snp.load();
54 + return BitcoinWallet(
55 + mnemonic: snp.mnemonic,
56 + password: password,
57 + walletInfo: walletInfo,
58 + unspentCoinsInfo: unspentCoinsInfo,
59 + initialAddresses: snp.addresses,
60 + initialBalance: snp.balance,
61 + accountIndex: snp.accountIndex);
62 + }
63 +}
cw_bitcoin/lib/bitcoin_wallet_addresses.dart new
+35
@@ -0,0 +1,35 @@
1 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
2 +import 'package:cw_bitcoin/utils.dart';
3 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
4 +import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
5 +import 'package:cw_core/wallet_info.dart';
6 +import 'package:flutter/foundation.dart';
7 +import 'package:mobx/mobx.dart';
8 +
9 +part 'bitcoin_wallet_addresses.g.dart';
10 +
11 +class BitcoinWalletAddresses = BitcoinWalletAddressesBase
12 + with _$BitcoinWalletAddresses;
13 +
14 +abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses
15 + with Store {
16 + BitcoinWalletAddressesBase(
17 + WalletInfo walletInfo,
18 + {@required List<BitcoinAddressRecord> initialAddresses,
19 + int accountIndex = 0,
20 + @required bitcoin.HDWallet mainHd,
21 + @required bitcoin.HDWallet sideHd,
22 + @required this.networkType})
23 + : super(
24 + walletInfo,
25 + initialAddresses: initialAddresses,
26 + accountIndex: accountIndex,
27 + mainHd: mainHd,
28 + sideHd: sideHd);
29 +
30 + bitcoin.NetworkType networkType;
31 +
32 + @override
33 + String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
34 + generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
35 +}
\ No newline at end of file
cw_bitcoin/lib/bitcoin_wallet_creation_credentials.dart new
+23
@@ -0,0 +1,23 @@
1 +import 'package:cw_core/wallet_credentials.dart';
2 +import 'package:cw_core/wallet_info.dart';
3 +
4 +class BitcoinNewWalletCredentials extends WalletCredentials {
5 + BitcoinNewWalletCredentials({String name, WalletInfo walletInfo})
6 + : super(name: name, walletInfo: walletInfo);
7 +}
8 +
9 +class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
10 + BitcoinRestoreWalletFromSeedCredentials(
11 + {String name, String password, this.mnemonic, WalletInfo walletInfo})
12 + : super(name: name, password: password, walletInfo: walletInfo);
13 +
14 + final String mnemonic;
15 +}
16 +
17 +class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials {
18 + BitcoinRestoreWalletFromWIFCredentials(
19 + {String name, String password, this.wif, WalletInfo walletInfo})
20 + : super(name: name, password: password, walletInfo: walletInfo);
21 +
22 + final String wif;
23 +}
cw_bitcoin/lib/bitcoin_wallet_keys.dart new
+9
@@ -0,0 +1,9 @@
1 +import 'package:flutter/foundation.dart';
2 +
3 +class BitcoinWalletKeys {
4 + const BitcoinWalletKeys({@required this.wif, @required this.privateKey, @required this.publicKey});
5 +
6 + final String wif;
7 + final String privateKey;
8 + final String publicKey;
9 +}
\ No newline at end of file
cw_bitcoin/lib/bitcoin_wallet_service.dart new
+80
@@ -0,0 +1,80 @@
1 +import 'dart:io';
2 +import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
3 +import 'package:cw_bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart';
4 +import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
5 +import 'package:cw_core/unspent_coins_info.dart';
6 +import 'package:cw_core/wallet_base.dart';
7 +import 'package:cw_core/wallet_service.dart';
8 +import 'package:cw_bitcoin/bitcoin_wallet.dart';
9 +import 'package:cw_core/pathForWallet.dart';
10 +import 'package:cw_core/wallet_info.dart';
11 +import 'package:cw_core/wallet_type.dart';
12 +import 'package:hive/hive.dart';
13 +
14 +class BitcoinWalletService extends WalletService<
15 + BitcoinNewWalletCredentials,
16 + BitcoinRestoreWalletFromSeedCredentials,
17 + BitcoinRestoreWalletFromWIFCredentials> {
18 + BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
19 +
20 + final Box<WalletInfo> walletInfoSource;
21 + final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
22 +
23 + @override
24 + WalletType getType() => WalletType.bitcoin;
25 +
26 + @override
27 + Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials) async {
28 + final wallet = BitcoinWallet(
29 + mnemonic: await generateMnemonic(),
30 + password: credentials.password,
31 + walletInfo: credentials.walletInfo,
32 + unspentCoinsInfo: unspentCoinsInfoSource);
33 + await wallet.save();
34 + await wallet.init();
35 + return wallet;
36 + }
37 +
38 + @override
39 + Future<bool> isWalletExit(String name) async =>
40 + File(await pathForWallet(name: name, type: getType())).existsSync();
41 +
42 + @override
43 + Future<BitcoinWallet> openWallet(String name, String password) async {
44 + final walletInfo = walletInfoSource.values.firstWhere(
45 + (info) => info.id == WalletBase.idFor(name, getType()),
46 + orElse: () => null);
47 + final wallet = await BitcoinWalletBase.open(
48 + password: password, name: name, walletInfo: walletInfo,
49 + unspentCoinsInfo: unspentCoinsInfoSource);
50 + await wallet.init();
51 + return wallet;
52 + }
53 +
54 + @override
55 + Future<void> remove(String wallet) async =>
56 + File(await pathForWalletDir(name: wallet, type: WalletType.bitcoin))
57 + .delete(recursive: true);
58 +
59 + @override
60 + Future<BitcoinWallet> restoreFromKeys(
61 + BitcoinRestoreWalletFromWIFCredentials credentials) async =>
62 + throw UnimplementedError();
63 +
64 + @override
65 + Future<BitcoinWallet> restoreFromSeed(
66 + BitcoinRestoreWalletFromSeedCredentials credentials) async {
67 + if (!validateMnemonic(credentials.mnemonic)) {
68 + throw BitcoinMnemonicIsIncorrectException();
69 + }
70 +
71 + final wallet = BitcoinWallet(
72 + password: credentials.password,
73 + mnemonic: credentials.mnemonic,
74 + walletInfo: credentials.walletInfo,
75 + unspentCoinsInfo: unspentCoinsInfoSource);
76 + await wallet.save();
77 + await wallet.init();
78 + return wallet;
79 + }
80 +}
cw_bitcoin/lib/cw_bitcoin.dart new
+7
@@ -0,0 +1,7 @@
1 +library cw_bitcoin;
2 +
3 +/// A Calculator.
4 +class Calculator {
5 + /// Returns [value] plus 1.
6 + int addOne(int value) => value + 1;
7 +}
cw_bitcoin/lib/electrum.dart new
+444
@@ -0,0 +1,444 @@
1 +import 'dart:async';
2 +import 'dart:convert';
3 +import 'dart:io';
4 +import 'dart:typed_data';
5 +import 'package:bitcoin_flutter/bitcoin_flutter.dart';
6 +import 'package:cw_bitcoin/bitcoin_amount_format.dart';
7 +import 'package:cw_bitcoin/script_hash.dart';
8 +import 'package:flutter/foundation.dart';
9 +import 'package:rxdart/rxdart.dart';
10 +
11 +String jsonrpcparams(List<Object> params) {
12 + final _params = params?.map((val) => '"${val.toString()}"')?.join(',');
13 + return '[$_params]';
14 +}
15 +
16 +String jsonrpc(
17 + {String method, List<Object> params, int id, double version = 2.0}) =>
18 + '{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json.encode(params)}}\n';
19 +
20 +class SocketTask {
21 + SocketTask({this.completer, this.isSubscription, this.subject});
22 +
23 + final Completer completer;
24 + final BehaviorSubject subject;
25 + final bool isSubscription;
26 +}
27 +
28 +class ElectrumClient {
29 + ElectrumClient()
30 + : _id = 0,
31 + _isConnected = false,
32 + _tasks = {},
33 + unterminatedString = '';
34 +
35 + static const connectionTimeout = Duration(seconds: 5);
36 + static const aliveTimerDuration = Duration(seconds: 2);
37 +
38 + bool get isConnected => _isConnected;
39 + Socket socket;
40 + void Function(bool) onConnectionStatusChange;
41 + int _id;
42 + final Map<String, SocketTask> _tasks;
43 + bool _isConnected;
44 + Timer _aliveTimer;
45 + String unterminatedString;
46 +
47 + Future<void> connectToUri(Uri uri) async =>
48 + await connect(host: uri.host, port: uri.port);
49 +
50 + Future<void> connect({@required String host, @required int port}) async {
51 + try {
52 + await socket?.close();
53 + } catch (_) {}
54 +
55 + socket = await SecureSocket.connect(host, port,
56 + timeout: connectionTimeout, onBadCertificate: (_) => true);
57 + _setIsConnected(true);
58 +
59 + socket.listen((Uint8List event) {
60 + try {
61 + final response =
62 + json.decode(utf8.decode(event.toList())) as Map<String, Object>;
63 + _handleResponse(response);
64 + } on FormatException catch (e) {
65 + final msg = e.message.toLowerCase();
66 +
67 + if (e.source is String) {
68 + unterminatedString += e.source as String;
69 + }
70 +
71 + if (msg.contains("not a subtype of type")) {
72 + unterminatedString += e.source as String;
73 + return;
74 + }
75 +
76 + if (isJSONStringCorrect(unterminatedString)) {
77 + final response =
78 + json.decode(unterminatedString) as Map<String, Object>;
79 + _handleResponse(response);
80 + unterminatedString = '';
81 + }
82 + } on TypeError catch (e) {
83 + if (!e.toString().contains('Map<String, Object>')) {
84 + return;
85 + }
86 +
87 + final source = utf8.decode(event.toList());
88 + unterminatedString += source;
89 +
90 + if (isJSONStringCorrect(unterminatedString)) {
91 + final response =
92 + json.decode(unterminatedString) as Map<String, Object>;
93 + _handleResponse(response);
94 + unterminatedString = null;
95 + }
96 + } catch (e) {
97 + print(e.toString());
98 + }
99 + }, onError: (Object error) {
100 + print(error.toString());
101 + _setIsConnected(false);
102 + }, onDone: () {
103 + _setIsConnected(false);
104 + });
105 + keepAlive();
106 + }
107 +
108 + void keepAlive() {
109 + _aliveTimer?.cancel();
110 + _aliveTimer = Timer.periodic(aliveTimerDuration, (_) async => ping());
111 + }
112 +
113 + Future<void> ping() async {
114 + try {
115 + await callWithTimeout(method: 'server.ping');
116 + _setIsConnected(true);
117 + } on RequestFailedTimeoutException catch (_) {
118 + _setIsConnected(false);
119 + }
120 + }
121 +
122 + Future<List<String>> version() =>
123 + call(method: 'server.version').then((dynamic result) {
124 + if (result is List) {
125 + return result.map((dynamic val) => val.toString()).toList();
126 + }
127 +
128 + return [];
129 + });
130 +
131 + Future<Map<String, Object>> getBalance(String scriptHash) =>
132 + call(method: 'blockchain.scripthash.get_balance', params: [scriptHash])
133 + .then((dynamic result) {
134 + if (result is Map<String, Object>) {
135 + return result;
136 + }
137 +
138 + return <String, Object>{};
139 + });
140 +
141 + Future<List<Map<String, dynamic>>> getHistory(String scriptHash) =>
142 + call(method: 'blockchain.scripthash.get_history', params: [scriptHash])
143 + .then((dynamic result) {
144 + if (result is List) {
145 + return result.map((dynamic val) {
146 + if (val is Map<String, Object>) {
147 + return val;
148 + }
149 +
150 + return <String, Object>{};
151 + }).toList();
152 + }
153 +
154 + return [];
155 + });
156 +
157 + Future<List<Map<String, dynamic>>> getListUnspentWithAddress(
158 + String address, NetworkType networkType) =>
159 + call(
160 + method: 'blockchain.scripthash.listunspent',
161 + params: [scriptHash(address, networkType: networkType)])
162 + .then((dynamic result) {
163 + if (result is List) {
164 + return result.map((dynamic val) {
165 + if (val is Map<String, Object>) {
166 + val['address'] = address;
167 + return val;
168 + }
169 +
170 + return <String, Object>{};
171 + }).toList();
172 + }
173 +
174 + return [];
175 + });
176 +
177 + Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) =>
178 + call(method: 'blockchain.scripthash.listunspent', params: [scriptHash])
179 + .then((dynamic result) {
180 + if (result is List) {
181 + return result.map((dynamic val) {
182 + if (val is Map<String, Object>) {
183 + return val;
184 + }
185 +
186 + return <String, Object>{};
187 + }).toList();
188 + }
189 +
190 + return [];
191 + });
192 +
193 + Future<List<Map<String, dynamic>>> getMempool(String scriptHash) =>
194 + call(method: 'blockchain.scripthash.get_mempool', params: [scriptHash])
195 + .then((dynamic result) {
196 + if (result is List) {
197 + return result.map((dynamic val) {
198 + if (val is Map<String, Object>) {
199 + return val;
200 + }
201 +
202 + return <String, Object>{};
203 + }).toList();
204 + }
205 +
206 + return [];
207 + });
208 +
209 + Future<Map<String, Object>> getTransactionRaw(
210 + {@required String hash}) async =>
211 + call(method: 'blockchain.transaction.get', params: [hash, true])
212 + .then((dynamic result) {
213 + if (result is Map<String, Object>) {
214 + return result;
215 + }
216 +
217 + return <String, Object>{};
218 + });
219 +
220 + Future<Map<String, Object>> getTransactionExpanded(
221 + {@required String hash}) async {
222 + try {
223 + final originalTx = await getTransactionRaw(hash: hash);
224 + final vins = originalTx['vin'] as List<Object>;
225 +
226 + for (dynamic vin in vins) {
227 + if (vin is Map<String, Object>) {
228 + vin['tx'] = await getTransactionRaw(hash: vin['txid'] as String);
229 + }
230 + }
231 +
232 + return originalTx;
233 + } catch (_) {
234 + return {};
235 + }
236 + }
237 +
238 + Future<String> broadcastTransaction(
239 + {@required String transactionRaw}) async =>
240 + call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
241 + .then((dynamic result) {
242 + if (result is String) {
243 + return result;
244 + }
245 +
246 + return '';
247 + });
248 +
249 + Future<Map<String, dynamic>> getMerkle(
250 + {@required String hash, @required int height}) async =>
251 + await call(
252 + method: 'blockchain.transaction.get_merkle',
253 + params: [hash, height]) as Map<String, dynamic>;
254 +
255 + Future<Map<String, dynamic>> getHeader({@required int height}) async =>
256 + await call(method: 'blockchain.block.get_header', params: [height])
257 + as Map<String, dynamic>;
258 +
259 + Future<double> estimatefee({@required int p}) =>
260 + call(method: 'blockchain.estimatefee', params: [p])
261 + .then((dynamic result) {
262 + if (result is double) {
263 + return result;
264 + }
265 +
266 + if (result is String) {
267 + return double.parse(result);
268 + }
269 +
270 + return 0;
271 + });
272 +
273 + Future<List<List<int>>> feeHistogram() =>
274 + call(method: 'mempool.get_fee_histogram').then((dynamic result) {
275 + if (result is List) {
276 + return result.map((dynamic e) {
277 + if (e is List) {
278 + return e.map((dynamic ee) => ee is int ? ee : null).toList();
279 + }
280 +
281 + return null;
282 + }).toList();
283 + }
284 +
285 + return [];
286 + });
287 +
288 + Future<List<int>> feeRates() async {
289 + try {
290 + final topDoubleString = await estimatefee(p: 1);
291 + final middleDoubleString = await estimatefee(p: 20);
292 + final bottomDoubleString = await estimatefee(p: 100);
293 + final top =
294 + (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000)
295 + .round();
296 + final middle =
297 + (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000)
298 + .round();
299 + final bottom =
300 + (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000)
301 + .round();
302 +
303 + return [bottom, middle, top];
304 + } catch (_) {
305 + return [];
306 + }
307 + }
308 +
309 + BehaviorSubject<Object> scripthashUpdate(String scripthash) {
310 + _id += 1;
311 + return subscribe<Object>(
312 + id: 'blockchain.scripthash.subscribe:$scripthash',
313 + method: 'blockchain.scripthash.subscribe',
314 + params: [scripthash]);
315 + }
316 +
317 + BehaviorSubject<T> subscribe<T>(
318 + {@required String id,
319 + @required String method,
320 + List<Object> params = const []}) {
321 + try {
322 + final subscription = BehaviorSubject<T>();
323 + _regisrySubscription(id, subscription);
324 + socket.write(jsonrpc(method: method, id: _id, params: params));
325 +
326 + return subscription;
327 + } catch(e) {
328 + print(e.toString());
329 + }
330 + }
331 +
332 + Future<dynamic> call({String method, List<Object> params = const []}) async {
333 + final completer = Completer<dynamic>();
334 + _id += 1;
335 + final id = _id;
336 + _registryTask(id, completer);
337 + socket.write(jsonrpc(method: method, id: id, params: params));
338 +
339 + return completer.future;
340 + }
341 +
342 + Future<dynamic> callWithTimeout(
343 + {String method,
344 + List<Object> params = const [],
345 + int timeout = 2000}) async {
346 + try {
347 + final completer = Completer<dynamic>();
348 + _id += 1;
349 + final id = _id;
350 + _registryTask(id, completer);
351 + socket.write(jsonrpc(method: method, id: id, params: params));
352 + Timer(Duration(milliseconds: timeout), () {
353 + if (!completer.isCompleted) {
354 + completer.completeError(RequestFailedTimeoutException(method, id));
355 + }
356 + });
357 +
358 + return completer.future;
359 + } catch(e) {
360 + print(e.toString());
361 + }
362 + }
363 +
364 + Future<void> close() async {
365 + _aliveTimer.cancel();
366 + await socket.close();
367 + onConnectionStatusChange = null;
368 + }
369 +
370 + void _registryTask(int id, Completer completer) => _tasks[id.toString()] =
371 + SocketTask(completer: completer, isSubscription: false);
372 +
373 + void _regisrySubscription(String id, BehaviorSubject subject) =>
374 + _tasks[id] = SocketTask(subject: subject, isSubscription: true);
375 +
376 + void _finish(String id, Object data) {
377 + if (_tasks[id] == null) {
378 + return;
379 + }
380 +
381 + if (!(_tasks[id]?.completer?.isCompleted ?? false)) {
382 + _tasks[id]?.completer?.complete(data);
383 + }
384 +
385 + if (!(_tasks[id]?.isSubscription ?? false)) {
386 + _tasks[id] = null;
387 + } else {
388 + _tasks[id].subject.add(data);
389 + }
390 + }
391 +
392 + void _methodHandler(
393 + {@required String method, @required Map<String, Object> request}) {
394 + switch (method) {
395 + case 'blockchain.scripthash.subscribe':
396 + final params = request['params'] as List<dynamic>;
397 + final scripthash = params.first as String;
398 + final id = 'blockchain.scripthash.subscribe:$scripthash';
399 +
400 + _tasks[id]?.subject?.add(params.last);
401 + break;
402 + default:
403 + break;
404 + }
405 + }
406 +
407 + void _setIsConnected(bool isConnected) {
408 + if (_isConnected != isConnected) {
409 + onConnectionStatusChange?.call(isConnected);
410 + }
411 +
412 + _isConnected = isConnected;
413 + }
414 +
415 + void _handleResponse(Map<String, Object> response) {
416 + final method = response['method'];
417 + final id = response['id'] as String;
418 + final result = response['result'];
419 +
420 + if (method is String) {
421 + _methodHandler(method: method, request: response);
422 + return;
423 + }
424 +
425 + _finish(id, result);
426 + }
427 +}
428 +
429 +// FIXME: move me
430 +bool isJSONStringCorrect(String source) {
431 + try {
432 + json.decode(source);
433 + return true;
434 + } catch (_) {
435 + return false;
436 + }
437 +}
438 +
439 +class RequestFailedTimeoutException implements Exception {
440 + RequestFailedTimeoutException(this.method, this.id);
441 +
442 + final String method;
443 + final int id;
444 +}
cw_bitcoin/lib/electrum_balance.dart new
+35
@@ -0,0 +1,35 @@
1 +import 'dart:convert';
2 +import 'package:flutter/foundation.dart';
3 +import 'package:cw_bitcoin/bitcoin_amount_format.dart';
4 +import 'package:cw_core/balance.dart';
5 +
6 +class ElectrumBalance extends Balance {
7 + const ElectrumBalance({@required this.confirmed, @required this.unconfirmed})
8 + : super(confirmed, unconfirmed);
9 +
10 + factory ElectrumBalance.fromJSON(String jsonSource) {
11 + if (jsonSource == null) {
12 + return null;
13 + }
14 +
15 + final decoded = json.decode(jsonSource) as Map;
16 +
17 + return ElectrumBalance(
18 + confirmed: decoded['confirmed'] as int ?? 0,
19 + unconfirmed: decoded['unconfirmed'] as int ?? 0);
20 + }
21 +
22 + final int confirmed;
23 + final int unconfirmed;
24 +
25 + @override
26 + String get formattedAvailableBalance =>
27 + bitcoinAmountToString(amount: confirmed);
28 +
29 + @override
30 + String get formattedAdditionalBalance =>
31 + bitcoinAmountToString(amount: unconfirmed);
32 +
33 + String toJSON() =>
34 + json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed});
35 +}
cw_bitcoin/lib/electrum_transaction_history.dart new
+98
@@ -0,0 +1,98 @@
1 +import 'dart:convert';
2 +import 'package:cw_core/pathForWallet.dart';
3 +import 'package:cw_core/wallet_info.dart';
4 +import 'package:flutter/foundation.dart';
5 +import 'package:mobx/mobx.dart';
6 +import 'package:cw_core/transaction_history.dart';
7 +import 'package:cw_bitcoin/file.dart';
8 +import 'package:cw_bitcoin/electrum_transaction_info.dart';
9 +
10 +part 'electrum_transaction_history.g.dart';
11 +
12 +const _transactionsHistoryFileName = 'transactions.json';
13 +
14 +class ElectrumTransactionHistory = ElectrumTransactionHistoryBase
15 + with _$ElectrumTransactionHistory;
16 +
17 +abstract class ElectrumTransactionHistoryBase
18 + extends TransactionHistoryBase<ElectrumTransactionInfo> with Store {
19 + ElectrumTransactionHistoryBase(
20 + {@required this.walletInfo, @required String password})
21 + : _password = password,
22 + _height = 0 {
23 + transactions = ObservableMap<String, ElectrumTransactionInfo>();
24 + }
25 +
26 + final WalletInfo walletInfo;
27 + final String _password;
28 + int _height;
29 +
30 + Future<void> init() async => await _load();
31 +
32 + @override
33 + void addOne(ElectrumTransactionInfo transaction) =>
34 + transactions[transaction.id] = transaction;
35 +
36 + @override
37 + void addMany(Map<String, ElectrumTransactionInfo> transactions) =>
38 + transactions.forEach((_, tx) => _updateOrInsert(tx));
39 +
40 + @override
41 + Future<void> save() async {
42 + try {
43 + final dirPath =
44 + await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
45 + final path = '$dirPath/$_transactionsHistoryFileName';
46 + final data =
47 + json.encode({'height': _height, 'transactions': transactions});
48 + await writeData(path: path, password: _password, data: data);
49 + } catch (e) {
50 + print('Error while save bitcoin transaction history: ${e.toString()}');
51 + }
52 + }
53 +
54 + Future<Map<String, Object>> _read() async {
55 + final dirPath =
56 + await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
57 + final path = '$dirPath/$_transactionsHistoryFileName';
58 + final content = await read(path: path, password: _password);
59 + return json.decode(content) as Map<String, Object>;
60 + }
61 +
62 + Future<void> _load() async {
63 + try {
64 + final content = await _read();
65 + final txs = content['transactions'] as Map<String, Object> ?? {};
66 +
67 + txs.entries.forEach((entry) {
68 + final val = entry.value;
69 +
70 + if (val is Map<String, Object>) {
71 + final tx = ElectrumTransactionInfo.fromJson(val, walletInfo.type);
72 + _updateOrInsert(tx);
73 + }
74 + });
75 +
76 + _height = content['height'] as int;
77 + } catch (e) {
78 + print(e);
79 + }
80 + }
81 +
82 + void _updateOrInsert(ElectrumTransactionInfo transaction) {
83 + if (transaction.id == null) {
84 + return;
85 + }
86 +
87 + if (transactions[transaction.id] == null) {
88 + transactions[transaction.id] = transaction;
89 + } else {
90 + final originalTx = transactions[transaction.id];
91 + originalTx.confirmations = transaction.confirmations;
92 + originalTx.amount = transaction.amount;
93 + originalTx.height = transaction.height;
94 + originalTx.date ??= transaction.date;
95 + originalTx.isPending = transaction.isPending;
96 + }
97 + }
98 +}
cw_bitcoin/lib/electrum_transaction_info.dart new
+178
@@ -0,0 +1,178 @@
1 +import 'package:flutter/foundation.dart';
2 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
3 +import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
4 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
5 +import 'package:cw_bitcoin/bitcoin_amount_format.dart';
6 +import 'package:cw_core/transaction_direction.dart';
7 +import 'package:cw_core/transaction_info.dart';
8 +import 'package:cw_core/format_amount.dart';
9 +import 'package:cw_core/wallet_type.dart';
10 +
11 +class ElectrumTransactionInfo extends TransactionInfo {
12 + ElectrumTransactionInfo(this.type,
13 + {@required String id,
14 + @required int height,
15 + @required int amount,
16 + @required int fee,
17 + @required TransactionDirection direction,
18 + @required bool isPending,
19 + @required DateTime date,
20 + @required int confirmations}) {
21 + this.id = id;
22 + this.height = height;
23 + this.amount = amount;
24 + this.fee = fee;
25 + this.direction = direction;
26 + this.date = date;
27 + this.isPending = isPending;
28 + this.confirmations = confirmations;
29 + }
30 +
31 + factory ElectrumTransactionInfo.fromElectrumVerbose(
32 + Map<String, Object> obj, WalletType type,
33 + {@required List<BitcoinAddressRecord> addresses, @required int height}) {
34 + final addressesSet = addresses.map((addr) => addr.address).toSet();
35 + final id = obj['txid'] as String;
36 + final vins = obj['vin'] as List<Object> ?? [];
37 + final vout = (obj['vout'] as List<Object> ?? []);
38 + final date = obj['time'] is int
39 + ? DateTime.fromMillisecondsSinceEpoch((obj['time'] as int) * 1000)
40 + : DateTime.now();
41 + final confirmations = obj['confirmations'] as int ?? 0;
42 + var direction = TransactionDirection.incoming;
43 + var inputsAmount = 0;
44 + var amount = 0;
45 + var totalOutAmount = 0;
46 +
47 + for (dynamic vin in vins) {
48 + final vout = vin['vout'] as int;
49 + final out = vin['tx']['vout'][vout] as Map;
50 + final outAddresses =
51 + (out['scriptPubKey']['addresses'] as List<Object>)?.toSet();
52 + inputsAmount +=
53 + stringDoubleToBitcoinAmount((out['value'] as double ?? 0).toString());
54 +
55 + if (outAddresses?.intersection(addressesSet)?.isNotEmpty ?? false) {
56 + direction = TransactionDirection.outgoing;
57 + }
58 + }
59 +
60 + for (dynamic out in vout) {
61 + final outAddresses =
62 + out['scriptPubKey']['addresses'] as List<Object> ?? [];
63 + final ntrs = outAddresses.toSet().intersection(addressesSet);
64 + final value = stringDoubleToBitcoinAmount(
65 + (out['value'] as double ?? 0.0).toString());
66 + totalOutAmount += value;
67 +
68 + if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) ||
69 + (direction == TransactionDirection.outgoing && ntrs.isEmpty)) {
70 + amount += value;
71 + }
72 + }
73 +
74 + final fee = inputsAmount - totalOutAmount;
75 +
76 + return ElectrumTransactionInfo(type,
77 + id: id,
78 + height: height,
79 + isPending: false,
80 + fee: fee,
81 + direction: direction,
82 + amount: amount,
83 + date: date,
84 + confirmations: confirmations);
85 + }
86 +
87 + factory ElectrumTransactionInfo.fromHexAndHeader(WalletType type, String hex,
88 + {List<String> addresses, int height, int timestamp, int confirmations}) {
89 + final tx = bitcoin.Transaction.fromHex(hex);
90 + var exist = false;
91 + var amount = 0;
92 +
93 + if (addresses != null) {
94 + tx.outs.forEach((out) {
95 + try {
96 + final p2pkh = bitcoin.P2PKH(
97 + data: PaymentData(output: out.script), network: bitcoin.bitcoin);
98 + exist = addresses.contains(p2pkh.data.address);
99 +
100 + if (exist) {
101 + amount += out.value;
102 + }
103 + } catch (_) {}
104 + });
105 + }
106 +
107 + final date = timestamp != null
108 + ? DateTime.fromMillisecondsSinceEpoch(timestamp * 1000)
109 + : DateTime.now();
110 +
111 + return ElectrumTransactionInfo(type,
112 + id: tx.getId(),
113 + height: height,
114 + isPending: false,
115 + fee: null,
116 + direction: TransactionDirection.incoming,
117 + amount: amount,
118 + date: date,
119 + confirmations: confirmations);
120 + }
121 +
122 + factory ElectrumTransactionInfo.fromJson(
123 + Map<String, dynamic> data, WalletType type) {
124 + return ElectrumTransactionInfo(type,
125 + id: data['id'] as String,
126 + height: data['height'] as int,
127 + amount: data['amount'] as int,
128 + fee: data['fee'] as int,
129 + direction: parseTransactionDirectionFromInt(data['direction'] as int),
130 + date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
131 + isPending: data['isPending'] as bool,
132 + confirmations: data['confirmations'] as int);
133 + }
134 +
135 + final WalletType type;
136 +
137 + String _fiatAmount;
138 +
139 + @override
140 + String amountFormatted() =>
141 + '${formatAmount(bitcoinAmountToString(amount: amount))} ${walletTypeToCryptoCurrency(type).title}';
142 +
143 + @override
144 + String feeFormatted() => fee != null
145 + ? '${formatAmount(bitcoinAmountToString(amount: fee))} ${walletTypeToCryptoCurrency(type).title}'
146 + : '';
147 +
148 + @override
149 + String fiatAmount() => _fiatAmount ?? '';
150 +
151 + @override
152 + void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
153 +
154 + ElectrumTransactionInfo updated(ElectrumTransactionInfo info) {
155 + return ElectrumTransactionInfo(info.type,
156 + id: id,
157 + height: info.height,
158 + amount: info.amount,
159 + fee: info.fee,
160 + direction: direction ?? info.direction,
161 + date: date ?? info.date,
162 + isPending: isPending ?? info.isPending,
163 + confirmations: info.confirmations);
164 + }
165 +
166 + Map<String, dynamic> toJson() {
167 + final m = <String, dynamic>{};
168 + m['id'] = id;
169 + m['height'] = height;
170 + m['amount'] = amount;
171 + m['direction'] = direction.index;
172 + m['date'] = date.millisecondsSinceEpoch;
173 + m['isPending'] = isPending;
174 + m['confirmations'] = confirmations;
175 + m['fee'] = fee;
176 + return m;
177 + }
178 +}
cw_bitcoin/lib/electrum_wallet.dart new
+548
@@ -0,0 +1,548 @@
1 +import 'dart:async';
2 +import 'dart:convert';
3 +import 'package:cw_core/unspent_coins_info.dart';
4 +import 'package:hive/hive.dart';
5 +import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
6 +import 'package:mobx/mobx.dart';
7 +import 'package:rxdart/subjects.dart';
8 +import 'package:flutter/foundation.dart';
9 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
10 +import 'package:cw_bitcoin/electrum_transaction_info.dart';
11 +import 'package:cw_core/pathForWallet.dart';
12 +import 'package:cw_bitcoin/address_to_output_script.dart';
13 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
14 +import 'package:cw_bitcoin/bitcoin_amount_format.dart';
15 +import 'package:cw_bitcoin/electrum_balance.dart';
16 +import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
17 +import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
18 +import 'package:cw_bitcoin/electrum_transaction_history.dart';
19 +import 'package:cw_bitcoin/bitcoin_transaction_no_inputs_exception.dart';
20 +import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
21 +import 'package:cw_bitcoin/bitcoin_transaction_wrong_balance_exception.dart';
22 +import 'package:cw_bitcoin/bitcoin_unspent.dart';
23 +import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
24 +import 'package:cw_bitcoin/file.dart';
25 +import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
26 +import 'package:cw_bitcoin/script_hash.dart';
27 +import 'package:cw_bitcoin/utils.dart';
28 +import 'package:cw_core/wallet_base.dart';
29 +import 'package:cw_core/node.dart';
30 +import 'package:cw_core/sync_status.dart';
31 +import 'package:cw_core/transaction_priority.dart';
32 +import 'package:cw_core/wallet_info.dart';
33 +import 'package:cw_bitcoin/electrum.dart';
34 +
35 +part 'electrum_wallet.g.dart';
36 +
37 +class ElectrumWallet = ElectrumWalletBase with _$ElectrumWallet;
38 +
39 +abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
40 + ElectrumTransactionHistory, ElectrumTransactionInfo> with Store {
41 + ElectrumWalletBase(
42 + {@required String password,
43 + @required WalletInfo walletInfo,
44 + @required Box<UnspentCoinsInfo> unspentCoinsInfo,
45 + @required List<BitcoinAddressRecord> initialAddresses,
46 + @required this.networkType,
47 + @required this.mnemonic,
48 + ElectrumClient electrumClient,
49 + ElectrumBalance initialBalance})
50 + : balance = initialBalance ??
51 + const ElectrumBalance(confirmed: 0, unconfirmed: 0),
52 + hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
53 + network: networkType)
54 + .derivePath("m/0'/0"),
55 + syncStatus = NotConnectedSyncStatus(),
56 + _password = password,
57 + _feeRates = <int>[],
58 + _isTransactionUpdating = false,
59 + super(walletInfo) {
60 + this.electrumClient = electrumClient ?? ElectrumClient();
61 + this.walletInfo = walletInfo;
62 + this.unspentCoinsInfo = unspentCoinsInfo;
63 + transactionHistory =
64 + ElectrumTransactionHistory(walletInfo: walletInfo, password: password);
65 + unspentCoins = [];
66 + _scripthashesUpdateSubject = {};
67 + }
68 +
69 + static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
70 + inputsCount * 146 + outputsCounts * 33 + 8;
71 +
72 + final bitcoin.HDWallet hd;
73 + final String mnemonic;
74 +
75 + ElectrumClient electrumClient;
76 + Box<UnspentCoinsInfo> unspentCoinsInfo;
77 +
78 + @override
79 + ElectrumWalletAddresses walletAddresses;
80 +
81 + @override
82 + @observable
83 + ElectrumBalance balance;
84 +
85 + @override
86 + @observable
87 + SyncStatus syncStatus;
88 +
89 + List<String> get scriptHashes => walletAddresses.addresses
90 + .map((addr) => scriptHash(addr.address, networkType: networkType))
91 + .toList();
92 +
93 + List<String> get publicScriptHashes => walletAddresses.addresses
94 + .where((addr) => !addr.isHidden)
95 + .map((addr) => scriptHash(addr.address, networkType: networkType))
96 + .toList();
97 +
98 + String get xpub => hd.base58;
99 +
100 + @override
101 + String get seed => mnemonic;
102 +
103 + bitcoin.NetworkType networkType;
104 +
105 + @override
106 + BitcoinWalletKeys get keys => BitcoinWalletKeys(
107 + wif: hd.wif, privateKey: hd.privKey, publicKey: hd.pubKey);
108 +
109 + final String _password;
110 + List<BitcoinUnspent> unspentCoins;
111 + List<int> _feeRates;
112 + Map<String, BehaviorSubject<Object>> _scripthashesUpdateSubject;
113 + bool _isTransactionUpdating;
114 +
115 + Future<void> init() async {
116 + await walletAddresses.init();
117 + await transactionHistory.init();
118 + await save();
119 + }
120 +
121 + @action
122 + @override
123 + Future<void> startSync() async {
124 + try {
125 + syncStatus = StartingSyncStatus();
126 + await updateTransactions();
127 + _subscribeForUpdates();
128 + await _updateBalance();
129 + await updateUnspent();
130 + _feeRates = await electrumClient.feeRates();
131 +
132 + Timer.periodic(const Duration(minutes: 1),
133 + (timer) async => _feeRates = await electrumClient.feeRates());
134 +
135 + syncStatus = SyncedSyncStatus();
136 + } catch (e) {
137 + print(e.toString());
138 + syncStatus = FailedSyncStatus();
139 + }
140 + }
141 +
142 + @action
143 + @override
144 + Future<void> connectToNode({@required Node node}) async {
145 + try {
146 + syncStatus = ConnectingSyncStatus();
147 + await electrumClient.connectToUri(node.uri);
148 + electrumClient.onConnectionStatusChange = (bool isConnected) {
149 + if (!isConnected) {
150 + syncStatus = LostConnectionSyncStatus();
151 + }
152 + };
153 + syncStatus = ConnectedSyncStatus();
154 + } catch (e) {
155 + print(e.toString());
156 + syncStatus = FailedSyncStatus();
157 + }
158 + }
159 +
160 + @override
161 + Future<PendingBitcoinTransaction> createTransaction(
162 + Object credentials) async {
163 + const minAmount = 546;
164 + final transactionCredentials = credentials as BitcoinTransactionCredentials;
165 + final inputs = <BitcoinUnspent>[];
166 + final outputs = transactionCredentials.outputs;
167 + final hasMultiDestination = outputs.length > 1;
168 + var allInputsAmount = 0;
169 +
170 + if (unspentCoins.isEmpty) {
171 + await updateUnspent();
172 + }
173 +
174 + for (final utx in unspentCoins) {
175 + if (utx.isSending) {
176 + allInputsAmount += utx.value;
177 + inputs.add(utx);
178 + }
179 + }
180 +
181 + if (inputs.isEmpty) {
182 + throw BitcoinTransactionNoInputsException();
183 + }
184 +
185 + final allAmountFee = feeAmountForPriority(
186 + transactionCredentials.priority, inputs.length, outputs.length);
187 + final allAmount = allInputsAmount - allAmountFee;
188 +
189 + var credentialsAmount = 0;
190 + var amount = 0;
191 + var fee = 0;
192 +
193 + if (hasMultiDestination) {
194 + if (outputs.any((item) => item.sendAll
195 + || item.formattedCryptoAmount <= 0)) {
196 + throw BitcoinTransactionWrongBalanceException(currency);
197 + }
198 +
199 + credentialsAmount = outputs.fold(0, (acc, value) =>
200 + acc + value.formattedCryptoAmount);
201 +
202 + if (allAmount - credentialsAmount < minAmount) {
203 + throw BitcoinTransactionWrongBalanceException(currency);
204 + }
205 +
206 + amount = credentialsAmount;
207 +
208 + fee = calculateEstimatedFee(transactionCredentials.priority, amount,
209 + outputsCount: outputs.length + 1);
210 + } else {
211 + final output = outputs.first;
212 +
213 + credentialsAmount = !output.sendAll
214 + ? output.formattedCryptoAmount
215 + : 0;
216 +
217 + if (credentialsAmount > allAmount) {
218 + throw BitcoinTransactionWrongBalanceException(currency);
219 + }
220 +
221 + amount = output.sendAll || allAmount - credentialsAmount < minAmount
222 + ? allAmount
223 + : credentialsAmount;
224 +
225 + fee = output.sendAll || amount == allAmount
226 + ? allAmountFee
227 + : calculateEstimatedFee(transactionCredentials.priority, amount);
228 + }
229 +
230 + if (fee == 0) {
231 + throw BitcoinTransactionWrongBalanceException(currency);
232 + }
233 +
234 + final totalAmount = amount + fee;
235 +
236 + if (totalAmount > balance.confirmed || totalAmount > allInputsAmount) {
237 + throw BitcoinTransactionWrongBalanceException(currency);
238 + }
239 +
240 + final txb = bitcoin.TransactionBuilder(network: networkType);
241 + final changeAddress = walletAddresses.address;
242 + var leftAmount = totalAmount;
243 + var totalInputAmount = 0;
244 +
245 + inputs.clear();
246 +
247 + for (final utx in unspentCoins) {
248 + if (utx.isSending) {
249 + leftAmount = leftAmount - utx.value;
250 + totalInputAmount += utx.value;
251 + inputs.add(utx);
252 +
253 + if (leftAmount <= 0) {
254 + break;
255 + }
256 + }
257 + }
258 +
259 + if (inputs.isEmpty) {
260 + throw BitcoinTransactionNoInputsException();
261 + }
262 +
263 + if (amount <= 0 || totalInputAmount < totalAmount) {
264 + throw BitcoinTransactionWrongBalanceException(currency);
265 + }
266 +
267 + txb.setVersion(1);
268 +
269 + inputs.forEach((input) {
270 + if (input.isP2wpkh) {
271 + final p2wpkh = bitcoin
272 + .P2WPKH(
273 + data: generatePaymentData(hd: hd, index: input.address.index),
274 + network: networkType)
275 + .data;
276 +
277 + txb.addInput(input.hash, input.vout, null, p2wpkh.output);
278 + } else {
279 + txb.addInput(input.hash, input.vout);
280 + }
281 + });
282 +
283 + outputs.forEach((item) {
284 + final outputAmount = hasMultiDestination
285 + ? item.formattedCryptoAmount
286 + : amount;
287 +
288 + final outputAddress = item.isParsedAddress
289 + ? item.extractedAddress
290 + : item.address;
291 +
292 + txb.addOutput(
293 + addressToOutputScript(outputAddress, networkType),
294 + outputAmount);
295 + });
296 +
297 + final estimatedSize =
298 + estimatedTransactionSize(inputs.length, outputs.length + 1);
299 + final feeAmount = feeRate(transactionCredentials.priority) * estimatedSize;
300 + final changeValue = totalInputAmount - amount - feeAmount;
301 +
302 + if (changeValue > minAmount) {
303 + txb.addOutput(changeAddress, changeValue);
304 + }
305 +
306 + for (var i = 0; i < inputs.length; i++) {
307 + final input = inputs[i];
308 + final keyPair = generateKeyPair(
309 + hd: hd, index: input.address.index, network: networkType);
310 + final witnessValue = input.isP2wpkh ? input.value : null;
311 +
312 + txb.sign(vin: i, keyPair: keyPair, witnessValue: witnessValue);
313 + }
314 +
315 + return PendingBitcoinTransaction(txb.build(), type,
316 + electrumClient: electrumClient, amount: amount, fee: fee)
317 + ..addListener((transaction) async {
318 + transactionHistory.addOne(transaction);
319 + await _updateBalance();
320 + });
321 + }
322 +
323 + String toJSON() => json.encode({
324 + 'mnemonic': mnemonic,
325 + 'account_index': walletAddresses.accountIndex.toString(),
326 + 'addresses': walletAddresses.addresses.map((addr) => addr.toJSON()).toList(),
327 + 'balance': balance?.toJSON()
328 + });
329 +
330 + int feeRate(TransactionPriority priority) {
331 + if (priority is BitcoinTransactionPriority) {
332 + return _feeRates[priority.raw];
333 + }
334 +
335 + return 0;
336 + }
337 +
338 + int feeAmountForPriority(BitcoinTransactionPriority priority, int inputsCount,
339 + int outputsCount) =>
340 + feeRate(priority) * estimatedTransactionSize(inputsCount, outputsCount);
341 +
342 + @override
343 + int calculateEstimatedFee(TransactionPriority priority, int amount,
344 + {int outputsCount}) {
345 + if (priority is BitcoinTransactionPriority) {
346 + int inputsCount = 0;
347 +
348 + if (amount != null) {
349 + int totalValue = 0;
350 +
351 + for (final input in unspentCoins) {
352 + if (totalValue >= amount) {
353 + break;
354 + }
355 +
356 + if (input.isSending) {
357 + totalValue += input.value;
358 + inputsCount += 1;
359 + }
360 + }
361 +
362 + if (totalValue < amount) return 0;
363 + } else {
364 + for (final input in unspentCoins) {
365 + if (input.isSending) {
366 + inputsCount += 1;
367 + }
368 + }
369 + }
370 +
371 + // If send all, then we have no change value
372 + final _outputsCount = outputsCount ?? (amount != null ? 2 : 1);
373 +
374 + return feeAmountForPriority(
375 + priority, inputsCount, _outputsCount);
376 + }
377 +
378 + return 0;
379 + }
380 +
381 + @override
382 + Future<void> save() async {
383 + final path = await makePath();
384 + await write(path: path, password: _password, data: toJSON());
385 + await transactionHistory.save();
386 + }
387 +
388 + bitcoin.ECPair keyPairFor({@required int index}) =>
389 + generateKeyPair(hd: hd, index: index, network: networkType);
390 +
391 + @override
392 + Future<void> rescan({int height}) async => throw UnimplementedError();
393 +
394 + @override
395 + Future<void> close() async {
396 + try {
397 + await electrumClient?.close();
398 + } catch (_) {}
399 + }
400 +
401 + Future<String> makePath() async =>
402 + pathForWallet(name: walletInfo.name, type: walletInfo.type);
403 +
404 + Future<void> updateUnspent() async {
405 + final unspent = await Future.wait(walletAddresses
406 + .addresses.map((address) => electrumClient
407 + .getListUnspentWithAddress(address.address, networkType)
408 + .then((unspent) => unspent
409 + .map((unspent) => BitcoinUnspent.fromJSON(address, unspent)))));
410 + unspentCoins = unspent.expand((e) => e).toList();
411 +
412 + if (unspentCoinsInfo.isEmpty) {
413 + unspentCoins.forEach((coin) => _addCoinInfo(coin));
414 + return;
415 + }
416 +
417 + if (unspentCoins.isNotEmpty) {
418 + unspentCoins.forEach((coin) {
419 + final coinInfoList = unspentCoinsInfo.values.where((element) =>
420 + element.walletId.contains(id) && element.hash.contains(coin.hash));
421 +
422 + if (coinInfoList.isNotEmpty) {
423 + final coinInfo = coinInfoList.first;
424 +
425 + coin.isFrozen = coinInfo.isFrozen;
426 + coin.isSending = coinInfo.isSending;
427 + coin.note = coinInfo.note;
428 + } else {
429 + _addCoinInfo(coin);
430 + }
431 + });
432 + }
433 +
434 + await _refreshUnspentCoinsInfo();
435 + }
436 +
437 + Future<void> _addCoinInfo(BitcoinUnspent coin) async {
438 + final newInfo = UnspentCoinsInfo(
439 + walletId: id,
440 + hash: coin.hash,
441 + isFrozen: coin.isFrozen,
442 + isSending: coin.isSending,
443 + note: coin.note
444 + );
445 +
446 + await unspentCoinsInfo.add(newInfo);
447 + }
448 +
449 + Future<void> _refreshUnspentCoinsInfo() async {
450 + try {
451 + final List<dynamic> keys = <dynamic>[];
452 + final currentWalletUnspentCoins = unspentCoinsInfo.values
453 + .where((element) => element.walletId.contains(id));
454 +
455 + if (currentWalletUnspentCoins.isNotEmpty) {
456 + currentWalletUnspentCoins.forEach((element) {
457 + final existUnspentCoins = unspentCoins
458 + ?.where((coin) => element.hash.contains(coin?.hash));
459 +
460 + if (existUnspentCoins?.isEmpty ?? true) {
461 + keys.add(element.key);
462 + }
463 + });
464 + }
465 +
466 + if (keys.isNotEmpty) {
467 + await unspentCoinsInfo.deleteAll(keys);
468 + }
469 + } catch (e) {
470 + print(e.toString());
471 + }
472 + }
473 +
474 + Future<ElectrumTransactionInfo> fetchTransactionInfo(
475 + {@required String hash, @required int height}) async {
476 + final tx = await electrumClient.getTransactionExpanded(hash: hash);
477 + return ElectrumTransactionInfo.fromElectrumVerbose(tx, walletInfo.type,
478 + height: height, addresses: walletAddresses.addresses);
479 + }
480 +
481 + @override
482 + Future<Map<String, ElectrumTransactionInfo>> fetchTransactions() async {
483 + final histories =
484 + publicScriptHashes.map((scriptHash) => electrumClient.getHistory(scriptHash));
485 + final _historiesWithDetails = await Future.wait(histories)
486 + .then((histories) => histories.expand((i) => i).toList())
487 + .then((histories) => histories.map((tx) => fetchTransactionInfo(
488 + hash: tx['tx_hash'] as String, height: tx['height'] as int)));
489 + final historiesWithDetails = await Future.wait(_historiesWithDetails);
490 +
491 + return historiesWithDetails.fold<Map<String, ElectrumTransactionInfo>>(
492 + <String, ElectrumTransactionInfo>{}, (acc, tx) {
493 + acc[tx.id] = acc[tx.id]?.updated(tx) ?? tx;
494 + return acc;
495 + });
496 + }
497 +
498 + Future<void> updateTransactions() async {
499 + try {
500 + if (_isTransactionUpdating) {
501 + return;
502 + }
503 +
504 + _isTransactionUpdating = true;
505 + final transactions = await fetchTransactions();
506 + transactionHistory.addMany(transactions);
507 + await transactionHistory.save();
508 + _isTransactionUpdating = false;
509 + } catch (e) {
510 + print(e);
511 + _isTransactionUpdating = false;
512 + }
513 + }
514 +
515 + void _subscribeForUpdates() {
516 + scriptHashes.forEach((sh) async {
517 + await _scripthashesUpdateSubject[sh]?.close();
518 + _scripthashesUpdateSubject[sh] = electrumClient.scripthashUpdate(sh);
519 + _scripthashesUpdateSubject[sh].listen((event) async {
520 + try {
521 + await _updateBalance();
522 + await updateUnspent();
523 + await updateTransactions();
524 + } catch (e) {
525 + print(e.toString());
526 + }
527 + });
528 + });
529 + }
530 +
531 + Future<ElectrumBalance> _fetchBalances() async {
532 + final balances = await Future.wait(
533 + scriptHashes.map((sh) => electrumClient.getBalance(sh)));
534 + final balance = balances.fold(
535 + ElectrumBalance(confirmed: 0, unconfirmed: 0),
536 + (ElectrumBalance acc, val) => ElectrumBalance(
537 + confirmed: (val['confirmed'] as int ?? 0) + (acc.confirmed ?? 0),
538 + unconfirmed:
539 + (val['unconfirmed'] as int ?? 0) + (acc.unconfirmed ?? 0)));
540 +
541 + return balance;
542 + }
543 +
544 + Future<void> _updateBalance() async {
545 + balance = await _fetchBalances();
546 + await save();
547 + }
548 +}
cw_bitcoin/lib/electrum_wallet_addresses.dart new
+132
@@ -0,0 +1,132 @@
1 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
2 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
3 +import 'package:cw_core/wallet_addresses.dart';
4 +import 'package:cw_core/wallet_info.dart';
5 +import 'package:flutter/foundation.dart';
6 +import 'package:mobx/mobx.dart';
7 +
8 +part 'electrum_wallet_addresses.g.dart';
9 +
10 +class ElectrumWalletAddresses = ElectrumWalletAddressesBase
11 + with _$ElectrumWalletAddresses;
12 +
13 +abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
14 + ElectrumWalletAddressesBase(WalletInfo walletInfo,
15 + {@required List<BitcoinAddressRecord> initialAddresses,
16 + int accountIndex = 0,
17 + this.mainHd,
18 + this.sideHd})
19 + : super(walletInfo) {
20 + this.accountIndex = accountIndex;
21 + addresses = ObservableList<BitcoinAddressRecord>.of(
22 + (initialAddresses ?? []).toSet());
23 + }
24 +
25 + static const regularAddressesCount = 22;
26 + static const hiddenAddressesCount = 17;
27 +
28 + @override
29 + @observable
30 + String address;
31 +
32 + bitcoin.HDWallet mainHd;
33 + bitcoin.HDWallet sideHd;
34 +
35 + ObservableList<BitcoinAddressRecord> addresses;
36 +
37 + int accountIndex;
38 +
39 + @override
40 + Future<void> init() async {
41 + await generateAddresses();
42 + address = addresses[accountIndex].address;
43 + await updateAddressesInBox();
44 + }
45 +
46 + @action
47 + Future<void> nextAddress() async {
48 + accountIndex += 1;
49 +
50 + if (accountIndex >= addresses.length) {
51 + accountIndex = 0;
52 + }
53 +
54 + address = addresses[accountIndex].address;
55 +
56 + await updateAddressesInBox();
57 + }
58 +
59 + Future<void> generateAddresses() async {
60 + final regularAddresses = <BitcoinAddressRecord>[];
61 + final hiddenAddresses = <BitcoinAddressRecord>[];
62 +
63 + addresses.forEach((addr) {
64 + if (addr.isHidden) {
65 + hiddenAddresses.add(addr);
66 + return;
67 + }
68 +
69 + regularAddresses.add(addr);
70 + });
71 +
72 + if (regularAddresses.length < regularAddressesCount) {
73 + final addressesCount = regularAddressesCount - regularAddresses.length;
74 + await generateNewAddresses(addressesCount,
75 + startIndex: regularAddresses.length, hd: mainHd, isHidden: false);
76 + }
77 +
78 + if (hiddenAddresses.length < hiddenAddressesCount) {
79 + final addressesCount = hiddenAddressesCount - hiddenAddresses.length;
80 + await generateNewAddresses(addressesCount,
81 + startIndex: hiddenAddresses.length, hd: sideHd, isHidden: true);
82 + }
83 + }
84 +
85 + Future<BitcoinAddressRecord> generateNewAddress(
86 + {bool isHidden = false, bitcoin.HDWallet hd}) async {
87 + accountIndex += 1;
88 + final address = BitcoinAddressRecord(
89 + getAddress(index: accountIndex, hd: hd),
90 + index: accountIndex,
91 + isHidden: isHidden);
92 + addresses.add(address);
93 + return address;
94 + }
95 +
96 + Future<List<BitcoinAddressRecord>> generateNewAddresses(int count,
97 + {int startIndex = 0, bitcoin.HDWallet hd, bool isHidden = false}) async {
98 + final list = <BitcoinAddressRecord>[];
99 +
100 + for (var i = startIndex; i < count + startIndex; i++) {
101 + final address = BitcoinAddressRecord(getAddress(index: i, hd: hd),
102 + index: i, isHidden: isHidden);
103 + list.add(address);
104 + }
105 +
106 + addresses.addAll(list);
107 + return list;
108 + }
109 +
110 + /*Future<void> updateAddress(String address) async {
111 + for (final addr in addresses) {
112 + if (addr.address == address) {
113 + await save();
114 + break;
115 + }
116 + }
117 + }*/
118 +
119 + String getAddress({@required int index, @required bitcoin.HDWallet hd}) => '';
120 +
121 + @override
122 + Future<void> updateAddressesInBox() async {
123 + try {
124 + addressesMap.clear();
125 + addressesMap[address] = '';
126 +
127 + await saveAddressesInBox();
128 + } catch (e) {
129 + print(e.toString());
130 + }
131 + }
132 +}
\ No newline at end of file
cw_bitcoin/lib/electrum_wallet_snapshot.dart new
+42
@@ -0,0 +1,42 @@
1 +import 'dart:convert';
2 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
3 +import 'package:cw_bitcoin/electrum_balance.dart';
4 +import 'package:cw_bitcoin/file.dart';
5 +import 'package:cw_core/pathForWallet.dart';
6 +import 'package:cw_core/wallet_type.dart';
7 +
8 +class ElectrumWallletSnapshot {
9 + ElectrumWallletSnapshot(this.name, this.type, this.password);
10 +
11 + final String name;
12 + final String password;
13 + final WalletType type;
14 +
15 + String mnemonic;
16 + List<BitcoinAddressRecord> addresses;
17 + ElectrumBalance balance;
18 + int accountIndex;
19 +
20 + Future<void> load() async {
21 + try {
22 + final path = await pathForWallet(name: name, type: type);
23 + final jsonSource = await read(path: path, password: password);
24 + final data = json.decode(jsonSource) as Map;
25 + final addressesTmp = data['addresses'] as List ?? <Object>[];
26 + mnemonic = data['mnemonic'] as String;
27 + addresses = addressesTmp
28 + .whereType<String>()
29 + .map((addr) => BitcoinAddressRecord.fromJSON(addr))
30 + .toList();
31 + balance = ElectrumBalance.fromJSON(data['balance'] as String) ??
32 + ElectrumBalance(confirmed: 0, unconfirmed: 0);
33 + accountIndex = 0;
34 +
35 + try {
36 + accountIndex = int.parse(data['account_index'] as String);
37 + } catch (_) {}
38 + } catch (e) {
39 + print(e);
40 + }
41 + }
42 +}
cw_bitcoin/lib/file.dart new
+40
@@ -0,0 +1,40 @@
1 +import 'dart:io';
2 +import 'package:cw_core/key.dart';
3 +import 'package:encrypt/encrypt.dart' as encrypt;
4 +import 'package:flutter/foundation.dart';
5 +
6 +Future<void> write(
7 + {@required String path,
8 + @required String password,
9 + @required String data}) async {
10 + final keys = extractKeys(password);
11 + final key = encrypt.Key.fromBase64(keys.first);
12 + final iv = encrypt.IV.fromBase64(keys.last);
13 + final encrypted = await encode(key: key, iv: iv, data: data);
14 + final f = File(path);
15 + f.writeAsStringSync(encrypted);
16 +}
17 +
18 +Future<void> writeData(
19 + {@required String path,
20 + @required String password,
21 + @required String data}) async {
22 + final keys = extractKeys(password);
23 + final key = encrypt.Key.fromBase64(keys.first);
24 + final iv = encrypt.IV.fromBase64(keys.last);
25 + final encrypted = await encode(key: key, iv: iv, data: data);
26 + final f = File(path);
27 + f.writeAsStringSync(encrypted);
28 +}
29 +
30 +Future<String> read({@required String path, @required String password}) async {
31 + final file = File(path);
32 +
33 + if (!file.existsSync()) {
34 + file.createSync();
35 + }
36 +
37 + final encrypted = file.readAsStringSync();
38 +
39 + return decode(password: password, data: encrypted);
40 +}
cw_bitcoin/lib/litecoin_network.dart new
+9
@@ -0,0 +1,9 @@
1 +import 'package:bitcoin_flutter/bitcoin_flutter.dart';
2 +
3 +final litecoinNetwork = NetworkType(
4 + messagePrefix: '\x19Litecoin Signed Message:\n',
5 + bech32: 'ltc',
6 + bip32: Bip32Type(public: 0x0488b21e, private: 0x0488ade4),
7 + pubKeyHash: 0x30,
8 + scriptHash: 0x32,
9 + wif: 0xb0);
cw_bitcoin/lib/litecoin_wallet.dart new
+82
@@ -0,0 +1,82 @@
1 +import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
2 +import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
3 +import 'package:cw_core/unspent_coins_info.dart';
4 +import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
5 +import 'package:cw_core/transaction_priority.dart';
6 +import 'package:flutter/foundation.dart';
7 +import 'package:hive/hive.dart';
8 +import 'package:mobx/mobx.dart';
9 +import 'package:cw_core/wallet_info.dart';
10 +import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
11 +import 'package:cw_bitcoin/electrum_wallet.dart';
12 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
13 +import 'package:cw_bitcoin/electrum_balance.dart';
14 +import 'package:cw_bitcoin/litecoin_network.dart';
15 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
16 +
17 +part 'litecoin_wallet.g.dart';
18 +
19 +class LitecoinWallet = LitecoinWalletBase with _$LitecoinWallet;
20 +
21 +abstract class LitecoinWalletBase extends ElectrumWallet with Store {
22 + LitecoinWalletBase(
23 + {@required String mnemonic,
24 + @required String password,
25 + @required WalletInfo walletInfo,
26 + @required Box<UnspentCoinsInfo> unspentCoinsInfo,
27 + List<BitcoinAddressRecord> initialAddresses,
28 + ElectrumBalance initialBalance,
29 + int accountIndex = 0})
30 + : super(
31 + mnemonic: mnemonic,
32 + password: password,
33 + walletInfo: walletInfo,
34 + unspentCoinsInfo: unspentCoinsInfo,
35 + networkType: litecoinNetwork,
36 + initialAddresses: initialAddresses,
37 + initialBalance: initialBalance) {
38 + walletAddresses = LitecoinWalletAddresses(
39 + walletInfo,
40 + initialAddresses: initialAddresses,
41 + accountIndex: accountIndex,
42 + mainHd: hd,
43 + sideHd: bitcoin.HDWallet
44 + .fromSeed(mnemonicToSeedBytes(mnemonic), network: networkType)
45 + .derivePath("m/0'/1"),
46 + networkType: networkType,);
47 + }
48 +
49 + static Future<LitecoinWallet> open({
50 + @required String name,
51 + @required WalletInfo walletInfo,
52 + @required Box<UnspentCoinsInfo> unspentCoinsInfo,
53 + @required String password,
54 + }) async {
55 + final snp = ElectrumWallletSnapshot(name, walletInfo.type, password);
56 + await snp.load();
57 + return LitecoinWallet(
58 + mnemonic: snp.mnemonic,
59 + password: password,
60 + walletInfo: walletInfo,
61 + unspentCoinsInfo: unspentCoinsInfo,
62 + initialAddresses: snp.addresses,
63 + initialBalance: snp.balance,
64 + accountIndex: snp.accountIndex);
65 + }
66 +
67 + @override
68 + int feeRate(TransactionPriority priority) {
69 + if (priority is LitecoinTransactionPriority) {
70 + switch (priority) {
71 + case LitecoinTransactionPriority.slow:
72 + return 1;
73 + case LitecoinTransactionPriority.medium:
74 + return 2;
75 + case LitecoinTransactionPriority.fast:
76 + return 3;
77 + }
78 + }
79 +
80 + return 0;
81 + }
82 +}
cw_bitcoin/lib/litecoin_wallet_addresses.dart new
+48
@@ -0,0 +1,48 @@
1 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
2 +import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
3 +import 'package:cw_bitcoin/utils.dart';
4 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
5 +import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
6 +import 'package:cw_core/wallet_info.dart';
7 +import 'package:flutter/foundation.dart';
8 +import 'package:mobx/mobx.dart';
9 +
10 +part 'litecoin_wallet_addresses.g.dart';
11 +
12 +class LitecoinWalletAddresses = LitecoinWalletAddressesBase
13 + with _$LitecoinWalletAddresses;
14 +
15 +abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses
16 + with Store {
17 + LitecoinWalletAddressesBase(
18 + WalletInfo walletInfo,
19 + {@required List<BitcoinAddressRecord> initialAddresses,
20 + int accountIndex = 0,
21 + @required bitcoin.HDWallet mainHd,
22 + @required bitcoin.HDWallet sideHd,
23 + @required this.networkType})
24 + : super(
25 + walletInfo,
26 + initialAddresses: initialAddresses,
27 + accountIndex: accountIndex,
28 + mainHd: mainHd,
29 + sideHd: sideHd);
30 +
31 + bitcoin.NetworkType networkType;
32 +
33 +
34 + @override
35 + String getAddress({@required int index, @required bitcoin.HDWallet hd}) =>
36 + generateP2WPKHAddress(hd: hd, index: index, networkType: networkType);
37 +
38 + @override
39 + Future<void> generateAddresses() async {
40 + if (addresses.length < 33) {
41 + final addressesCount = 22 - addresses.length;
42 + await generateNewAddresses(addressesCount,
43 + hd: mainHd, startIndex: addresses.length);
44 + await generateNewAddresses(11,
45 + startIndex: 0, hd: sideHd, isHidden: true);
46 + }
47 + }
48 +}
\ No newline at end of file
cw_bitcoin/lib/litecoin_wallet_service.dart new
+81
@@ -0,0 +1,81 @@
1 +import 'dart:io';
2 +import 'package:cw_core/unspent_coins_info.dart';
3 +import 'package:hive/hive.dart';
4 +import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
5 +import 'package:cw_bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart';
6 +import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
7 +import 'package:cw_bitcoin/litecoin_wallet.dart';
8 +import 'package:cw_core/wallet_service.dart';
9 +import 'package:cw_core/pathForWallet.dart';
10 +import 'package:cw_core/wallet_type.dart';
11 +import 'package:cw_core/wallet_info.dart';
12 +import 'package:cw_core/wallet_base.dart';
13 +
14 +class LitecoinWalletService extends WalletService<
15 + BitcoinNewWalletCredentials,
16 + BitcoinRestoreWalletFromSeedCredentials,
17 + BitcoinRestoreWalletFromWIFCredentials> {
18 + LitecoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
19 +
20 + final Box<WalletInfo> walletInfoSource;
21 + final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
22 +
23 + @override
24 + WalletType getType() => WalletType.litecoin;
25 +
26 + @override
27 + Future<LitecoinWallet> create(BitcoinNewWalletCredentials credentials) async {
28 + final wallet = LitecoinWallet(
29 + mnemonic: await generateMnemonic(),
30 + password: credentials.password,
31 + walletInfo: credentials.walletInfo,
32 + unspentCoinsInfo: unspentCoinsInfoSource);
33 + await wallet.save();
34 + await wallet.init();
35 +
36 + return wallet;
37 + }
38 +
39 + @override
40 + Future<bool> isWalletExit(String name) async =>
41 + File(await pathForWallet(name: name, type: getType())).existsSync();
42 +
43 + @override
44 + Future<LitecoinWallet> openWallet(String name, String password) async {
45 + final walletInfo = walletInfoSource.values.firstWhere(
46 + (info) => info.id == WalletBase.idFor(name, getType()),
47 + orElse: () => null);
48 + final wallet = await LitecoinWalletBase.open(
49 + password: password, name: name, walletInfo: walletInfo,
50 + unspentCoinsInfo: unspentCoinsInfoSource);
51 + await wallet.init();
52 + return wallet;
53 + }
54 +
55 + @override
56 + Future<void> remove(String wallet) async =>
57 + File(await pathForWalletDir(name: wallet, type: getType()))
58 + .delete(recursive: true);
59 +
60 + @override
61 + Future<LitecoinWallet> restoreFromKeys(
62 + BitcoinRestoreWalletFromWIFCredentials credentials) async =>
63 + throw UnimplementedError();
64 +
65 + @override
66 + Future<LitecoinWallet> restoreFromSeed(
67 + BitcoinRestoreWalletFromSeedCredentials credentials) async {
68 + if (!validateMnemonic(credentials.mnemonic)) {
69 + throw BitcoinMnemonicIsIncorrectException();
70 + }
71 +
72 + final wallet = LitecoinWallet(
73 + password: credentials.password,
74 + mnemonic: credentials.mnemonic,
75 + walletInfo: credentials.walletInfo,
76 + unspentCoinsInfo: unspentCoinsInfoSource);
77 + await wallet.save();
78 + await wallet.init();
79 + return wallet;
80 + }
81 +}
cw_bitcoin/lib/pending_bitcoin_transaction.dart new
+60
@@ -0,0 +1,60 @@
1 +import 'package:cw_bitcoin/bitcoin_commit_transaction_exception.dart';
2 +import 'package:flutter/foundation.dart';
3 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
4 +import 'package:cw_core/pending_transaction.dart';
5 +import 'package:cw_bitcoin/electrum.dart';
6 +import 'package:cw_bitcoin/bitcoin_amount_format.dart';
7 +import 'package:cw_bitcoin/electrum_transaction_info.dart';
8 +import 'package:cw_core/transaction_direction.dart';
9 +import 'package:cw_core/wallet_type.dart';
10 +
11 +class PendingBitcoinTransaction with PendingTransaction {
12 + PendingBitcoinTransaction(this._tx, this.type,
13 + {@required this.electrumClient,
14 + @required this.amount,
15 + @required this.fee})
16 + : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];
17 +
18 + final WalletType type;
19 + final bitcoin.Transaction _tx;
20 + final ElectrumClient electrumClient;
21 + final int amount;
22 + final int fee;
23 +
24 + @override
25 + String get id => _tx.getId();
26 +
27 + @override
28 + String get amountFormatted => bitcoinAmountToString(amount: amount);
29 +
30 + @override
31 + String get feeFormatted => bitcoinAmountToString(amount: fee);
32 +
33 + final List<void Function(ElectrumTransactionInfo transaction)> _listeners;
34 +
35 + @override
36 + Future<void> commit() async {
37 + final result =
38 + await electrumClient.broadcastTransaction(transactionRaw: _tx.toHex());
39 +
40 + if (result.isEmpty) {
41 + throw BitcoinCommitTransactionException();
42 + }
43 +
44 + _listeners?.forEach((listener) => listener(transactionInfo()));
45 + }
46 +
47 + void addListener(
48 + void Function(ElectrumTransactionInfo transaction) listener) =>
49 + _listeners.add(listener);
50 +
51 + ElectrumTransactionInfo transactionInfo() => ElectrumTransactionInfo(type,
52 + id: id,
53 + height: 0,
54 + amount: amount,
55 + direction: TransactionDirection.outgoing,
56 + date: DateTime.now(),
57 + isPending: true,
58 + confirmations: 0,
59 + fee: fee);
60 +}
cw_bitcoin/lib/script_hash.dart new
+20
@@ -0,0 +1,20 @@
1 +import 'package:flutter/foundation.dart';
2 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
3 +import 'package:crypto/crypto.dart';
4 +
5 +String scriptHash(String address, {@required bitcoin.NetworkType networkType}) {
6 + final outputScript =
7 + bitcoin.Address.addressToOutputScript(address, networkType);
8 + final parts = sha256.convert(outputScript).toString().split('');
9 + var res = '';
10 +
11 + for (var i = parts.length - 1; i >= 0; i--) {
12 + final char = parts[i];
13 + i--;
14 + final nextChar = parts[i];
15 + res += nextChar;
16 + res += char;
17 + }
18 +
19 + return res;
20 +}
cw_bitcoin/lib/utils.dart new
+55
@@ -0,0 +1,55 @@
1 +import 'dart:typed_data';
2 +import 'package:flutter/foundation.dart';
3 +import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
4 +import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
5 +import 'package:hex/hex.dart';
6 +
7 +bitcoin.PaymentData generatePaymentData(
8 + {@required bitcoin.HDWallet hd, @required int index}) =>
9 + PaymentData(
10 + pubkey: Uint8List.fromList(HEX.decode(hd.derive(index).pubKey)));
11 +
12 +bitcoin.ECPair generateKeyPair(
13 + {@required bitcoin.HDWallet hd,
14 + @required int index,
15 + bitcoin.NetworkType network}) =>
16 + bitcoin.ECPair.fromWIF(hd.derive(index).wif, network: network);
17 +
18 +String generateP2WPKHAddress(
19 + {@required bitcoin.HDWallet hd,
20 + @required int index,
21 + bitcoin.NetworkType networkType}) =>
22 + bitcoin
23 + .P2WPKH(
24 + data: PaymentData(
25 + pubkey:
26 + Uint8List.fromList(HEX.decode(hd.derive(index).pubKey))),
27 + network: networkType)
28 + .data
29 + .address;
30 +
31 +String generateP2WPKHAddressByPath(
32 + {@required bitcoin.HDWallet hd,
33 + @required String path,
34 + bitcoin.NetworkType networkType}) =>
35 + bitcoin
36 + .P2WPKH(
37 + data: PaymentData(
38 + pubkey:
39 + Uint8List.fromList(HEX.decode(hd.derivePath(path).pubKey))),
40 + network: networkType)
41 + .data
42 + .address;
43 +
44 +String generateP2PKHAddress(
45 + {@required bitcoin.HDWallet hd,
46 + @required int index,
47 + bitcoin.NetworkType networkType}) =>
48 + bitcoin
49 + .P2PKH(
50 + data: PaymentData(
51 + pubkey:
52 + Uint8List.fromList(HEX.decode(hd.derive(index).pubKey))),
53 + network: networkType)
54 + .data
55 + .address;
cw_bitcoin/pubspec.lock new
+581
@@ -0,0 +1,581 @@
1 +# Generated by pub
2 +# See https://dart.dev/tools/pub/glossary#lockfile
3 +packages:
4 + _fe_analyzer_shared:
5 + dependency: transitive
6 + description:
7 + name: _fe_analyzer_shared
8 + url: "https://pub.dartlang.org"
9 + source: hosted
10 + version: "14.0.0"
11 + analyzer:
12 + dependency: transitive
13 + description:
14 + name: analyzer
15 + url: "https://pub.dartlang.org"
16 + source: hosted
17 + version: "0.41.2"
18 + args:
19 + dependency: transitive
20 + description:
21 + name: args
22 + url: "https://pub.dartlang.org"
23 + source: hosted
24 + version: "2.3.0"
25 + async:
26 + dependency: transitive
27 + description:
28 + name: async
29 + url: "https://pub.dartlang.org"
30 + source: hosted
31 + version: "2.5.0"
32 + boolean_selector:
33 + dependency: transitive
34 + description:
35 + name: boolean_selector
36 + url: "https://pub.dartlang.org"
37 + source: hosted
38 + version: "2.1.0"
39 + build:
40 + dependency: transitive
41 + description:
42 + name: build
43 + url: "https://pub.dartlang.org"
44 + source: hosted
45 + version: "1.6.2"
46 + build_config:
47 + dependency: transitive
48 + description:
49 + name: build_config
50 + url: "https://pub.dartlang.org"
51 + source: hosted
52 + version: "0.4.6"
53 + build_daemon:
54 + dependency: transitive
55 + description:
56 + name: build_daemon
57 + url: "https://pub.dartlang.org"
58 + source: hosted
59 + version: "2.1.10"
60 + build_resolvers:
61 + dependency: "direct dev"
62 + description:
63 + name: build_resolvers
64 + url: "https://pub.dartlang.org"
65 + source: hosted
66 + version: "1.5.3"
67 + build_runner:
68 + dependency: "direct dev"
69 + description:
70 + name: build_runner
71 + url: "https://pub.dartlang.org"
72 + source: hosted
73 + version: "1.11.5"
74 + build_runner_core:
75 + dependency: transitive
76 + description:
77 + name: build_runner_core
78 + url: "https://pub.dartlang.org"
79 + source: hosted
80 + version: "6.1.10"
81 + built_collection:
82 + dependency: transitive
83 + description:
84 + name: built_collection
85 + url: "https://pub.dartlang.org"
86 + source: hosted
87 + version: "5.1.1"
88 + built_value:
89 + dependency: transitive
90 + description:
91 + name: built_value
92 + url: "https://pub.dartlang.org"
93 + source: hosted
94 + version: "8.1.3"
95 + characters:
96 + dependency: transitive
97 + description:
98 + name: characters
99 + url: "https://pub.dartlang.org"
100 + source: hosted
101 + version: "1.1.0"
102 + charcode:
103 + dependency: transitive
104 + description:
105 + name: charcode
106 + url: "https://pub.dartlang.org"
107 + source: hosted
108 + version: "1.2.0"
109 + checked_yaml:
110 + dependency: transitive
111 + description:
112 + name: checked_yaml
113 + url: "https://pub.dartlang.org"
114 + source: hosted
115 + version: "1.0.4"
116 + cli_util:
117 + dependency: transitive
118 + description:
119 + name: cli_util
120 + url: "https://pub.dartlang.org"
121 + source: hosted
122 + version: "0.3.5"
123 + clock:
124 + dependency: transitive
125 + description:
126 + name: clock
127 + url: "https://pub.dartlang.org"
128 + source: hosted
129 + version: "1.1.0"
130 + code_builder:
131 + dependency: transitive
132 + description:
133 + name: code_builder
134 + url: "https://pub.dartlang.org"
135 + source: hosted
136 + version: "3.7.0"
137 + collection:
138 + dependency: transitive
139 + description:
140 + name: collection
141 + url: "https://pub.dartlang.org"
142 + source: hosted
143 + version: "1.15.0"
144 + convert:
145 + dependency: transitive
146 + description:
147 + name: convert
148 + url: "https://pub.dartlang.org"
149 + source: hosted
150 + version: "3.0.1"
151 + crypto:
152 + dependency: transitive
153 + description:
154 + name: crypto
155 + url: "https://pub.dartlang.org"
156 + source: hosted
157 + version: "3.0.1"
158 + cw_core:
159 + dependency: "direct main"
160 + description:
161 + path: "../cw_core"
162 + relative: true
163 + source: path
164 + version: "0.0.1"
165 + dart_style:
166 + dependency: transitive
167 + description:
168 + name: dart_style
169 + url: "https://pub.dartlang.org"
170 + source: hosted
171 + version: "1.3.12"
172 + dartx:
173 + dependency: transitive
174 + description:
175 + name: dartx
176 + url: "https://pub.dartlang.org"
177 + source: hosted
178 + version: "0.8.0"
179 + fake_async:
180 + dependency: transitive
181 + description:
182 + name: fake_async
183 + url: "https://pub.dartlang.org"
184 + source: hosted
185 + version: "1.2.0"
186 + ffi:
187 + dependency: transitive
188 + description:
189 + name: ffi
190 + url: "https://pub.dartlang.org"
191 + source: hosted
192 + version: "1.1.2"
193 + file:
194 + dependency: transitive
195 + description:
196 + name: file
197 + url: "https://pub.dartlang.org"
198 + source: hosted
199 + version: "6.1.2"
200 + fixnum:
201 + dependency: transitive
202 + description:
203 + name: fixnum
204 + url: "https://pub.dartlang.org"
205 + source: hosted
206 + version: "1.0.0"
207 + flutter:
208 + dependency: "direct main"
209 + description: flutter
210 + source: sdk
211 + version: "0.0.0"
212 + flutter_mobx:
213 + dependency: "direct main"
214 + description:
215 + name: flutter_mobx
216 + url: "https://pub.dartlang.org"
217 + source: hosted
218 + version: "1.1.0+2"
219 + flutter_test:
220 + dependency: "direct dev"
221 + description: flutter
222 + source: sdk
223 + version: "0.0.0"
224 + glob:
225 + dependency: transitive
226 + description:
227 + name: glob
228 + url: "https://pub.dartlang.org"
229 + source: hosted
230 + version: "2.0.1"
231 + graphs:
232 + dependency: transitive
233 + description:
234 + name: graphs
235 + url: "https://pub.dartlang.org"
236 + source: hosted
237 + version: "0.2.0"
238 + hive:
239 + dependency: transitive
240 + description:
241 + name: hive
242 + url: "https://pub.dartlang.org"
243 + source: hosted
244 + version: "1.6.0-nullsafety.2"
245 + hive_generator:
246 + dependency: "direct dev"
247 + description:
248 + name: hive_generator
249 + url: "https://pub.dartlang.org"
250 + source: hosted
251 + version: "0.8.2"
252 + http:
253 + dependency: "direct main"
254 + description:
255 + name: http
256 + url: "https://pub.dartlang.org"
257 + source: hosted
258 + version: "0.12.2"
259 + http_multi_server:
260 + dependency: transitive
261 + description:
262 + name: http_multi_server
263 + url: "https://pub.dartlang.org"
264 + source: hosted
265 + version: "2.2.0"
266 + http_parser:
267 + dependency: transitive
268 + description:
269 + name: http_parser
270 + url: "https://pub.dartlang.org"
271 + source: hosted
272 + version: "3.1.4"
273 + intl:
274 + dependency: "direct main"
275 + description:
276 + name: intl
277 + url: "https://pub.dartlang.org"
278 + source: hosted
279 + version: "0.17.0"
280 + io:
281 + dependency: transitive
282 + description:
283 + name: io
284 + url: "https://pub.dartlang.org"
285 + source: hosted
286 + version: "0.3.5"
287 + js:
288 + dependency: transitive
289 + description:
290 + name: js
291 + url: "https://pub.dartlang.org"
292 + source: hosted
293 + version: "0.6.3"
294 + json_annotation:
295 + dependency: transitive
296 + description:
297 + name: json_annotation
298 + url: "https://pub.dartlang.org"
299 + source: hosted
300 + version: "4.0.1"
301 + logging:
302 + dependency: transitive
303 + description:
304 + name: logging
305 + url: "https://pub.dartlang.org"
306 + source: hosted
307 + version: "1.0.2"
308 + matcher:
309 + dependency: transitive
310 + description:
311 + name: matcher
312 + url: "https://pub.dartlang.org"
313 + source: hosted
314 + version: "0.12.10"
315 + meta:
316 + dependency: transitive
317 + description:
318 + name: meta
319 + url: "https://pub.dartlang.org"
320 + source: hosted
321 + version: "1.3.0"
322 + mime:
323 + dependency: transitive
324 + description:
325 + name: mime
326 + url: "https://pub.dartlang.org"
327 + source: hosted
328 + version: "1.0.1"
329 + mobx:
330 + dependency: "direct main"
331 + description:
332 + name: mobx
333 + url: "https://pub.dartlang.org"
334 + source: hosted
335 + version: "1.2.1+4"
336 + mobx_codegen:
337 + dependency: "direct dev"
338 + description:
339 + name: mobx_codegen
340 + url: "https://pub.dartlang.org"
341 + source: hosted
342 + version: "1.1.2"
343 + package_config:
344 + dependency: transitive
345 + description:
346 + name: package_config
347 + url: "https://pub.dartlang.org"
348 + source: hosted
349 + version: "1.9.3"
350 + path:
351 + dependency: transitive
352 + description:
353 + name: path
354 + url: "https://pub.dartlang.org"
355 + source: hosted
356 + version: "1.8.0"
357 + path_provider:
358 + dependency: "direct main"
359 + description:
360 + name: path_provider
361 + url: "https://pub.dartlang.org"
362 + source: hosted
363 + version: "1.6.28"
364 + path_provider_linux:
365 + dependency: transitive
366 + description:
367 + name: path_provider_linux
368 + url: "https://pub.dartlang.org"
369 + source: hosted
370 + version: "0.0.1+2"
371 + path_provider_macos:
372 + dependency: transitive
373 + description:
374 + name: path_provider_macos
375 + url: "https://pub.dartlang.org"
376 + source: hosted
377 + version: "0.0.4+8"
378 + path_provider_platform_interface:
379 + dependency: transitive
380 + description:
381 + name: path_provider_platform_interface
382 + url: "https://pub.dartlang.org"
383 + source: hosted
384 + version: "1.0.4"
385 + path_provider_windows:
386 + dependency: transitive
387 + description:
388 + name: path_provider_windows
389 + url: "https://pub.dartlang.org"
390 + source: hosted
391 + version: "0.0.5"
392 + pedantic:
393 + dependency: transitive
394 + description:
395 + name: pedantic
396 + url: "https://pub.dartlang.org"
397 + source: hosted
398 + version: "1.11.1"
399 + platform:
400 + dependency: transitive
401 + description:
402 + name: platform
403 + url: "https://pub.dartlang.org"
404 + source: hosted
405 + version: "3.1.0"
406 + plugin_platform_interface:
407 + dependency: transitive
408 + description:
409 + name: plugin_platform_interface
410 + url: "https://pub.dartlang.org"
411 + source: hosted
412 + version: "1.0.3"
413 + pool:
414 + dependency: transitive
415 + description:
416 + name: pool
417 + url: "https://pub.dartlang.org"
418 + source: hosted
419 + version: "1.5.0"
420 + process:
421 + dependency: transitive
422 + description:
423 + name: process
424 + url: "https://pub.dartlang.org"
425 + source: hosted
426 + version: "4.2.3"
427 + pub_semver:
428 + dependency: transitive
429 + description:
430 + name: pub_semver
431 + url: "https://pub.dartlang.org"
432 + source: hosted
433 + version: "2.1.0"
434 + pubspec_parse:
435 + dependency: transitive
436 + description:
437 + name: pubspec_parse
438 + url: "https://pub.dartlang.org"
439 + source: hosted
440 + version: "0.1.8"
441 + shelf:
442 + dependency: transitive
443 + description:
444 + name: shelf
445 + url: "https://pub.dartlang.org"
446 + source: hosted
447 + version: "0.7.9"
448 + shelf_web_socket:
449 + dependency: transitive
450 + description:
451 + name: shelf_web_socket
452 + url: "https://pub.dartlang.org"
453 + source: hosted
454 + version: "0.2.4+1"
455 + sky_engine:
456 + dependency: transitive
457 + description: flutter
458 + source: sdk
459 + version: "0.0.99"
460 + source_gen:
461 + dependency: transitive
462 + description:
463 + name: source_gen
464 + url: "https://pub.dartlang.org"
465 + source: hosted
466 + version: "0.9.10+3"
467 + source_span:
468 + dependency: transitive
469 + description:
470 + name: source_span
471 + url: "https://pub.dartlang.org"
472 + source: hosted
473 + version: "1.8.0"
474 + stack_trace:
475 + dependency: transitive
476 + description:
477 + name: stack_trace
478 + url: "https://pub.dartlang.org"
479 + source: hosted
480 + version: "1.10.0"
481 + stream_channel:
482 + dependency: transitive
483 + description:
484 + name: stream_channel
485 + url: "https://pub.dartlang.org"
486 + source: hosted
487 + version: "2.1.0"
488 + stream_transform:
489 + dependency: transitive
490 + description:
491 + name: stream_transform
492 + url: "https://pub.dartlang.org"
493 + source: hosted
494 + version: "2.0.0"
495 + string_scanner:
496 + dependency: transitive
497 + description:
498 + name: string_scanner
499 + url: "https://pub.dartlang.org"
500 + source: hosted
501 + version: "1.1.0"
502 + term_glyph:
503 + dependency: transitive
504 + description:
505 + name: term_glyph
506 + url: "https://pub.dartlang.org"
507 + source: hosted
508 + version: "1.2.0"
509 + test_api:
510 + dependency: transitive
511 + description:
512 + name: test_api
513 + url: "https://pub.dartlang.org"
514 + source: hosted
515 + version: "0.2.19"
516 + time:
517 + dependency: transitive
518 + description:
519 + name: time
520 + url: "https://pub.dartlang.org"
521 + source: hosted
522 + version: "2.1.0"
523 + timing:
524 + dependency: transitive
525 + description:
526 + name: timing
527 + url: "https://pub.dartlang.org"
528 + source: hosted
529 + version: "0.1.1+3"
530 + typed_data:
531 + dependency: transitive
532 + description:
533 + name: typed_data
534 + url: "https://pub.dartlang.org"
535 + source: hosted
536 + version: "1.3.0"
537 + vector_math:
538 + dependency: transitive
539 + description:
540 + name: vector_math
541 + url: "https://pub.dartlang.org"
542 + source: hosted
543 + version: "2.1.0"
544 + watcher:
545 + dependency: transitive
546 + description:
547 + name: watcher
548 + url: "https://pub.dartlang.org"
549 + source: hosted
550 + version: "1.0.0"
551 + web_socket_channel:
552 + dependency: transitive
553 + description:
554 + name: web_socket_channel
555 + url: "https://pub.dartlang.org"
556 + source: hosted
557 + version: "1.2.0"
558 + win32:
559 + dependency: transitive
560 + description:
561 + name: win32
562 + url: "https://pub.dartlang.org"
563 + source: hosted
564 + version: "2.0.5"
565 + xdg_directories:
566 + dependency: transitive
567 + description:
568 + name: xdg_directories
569 + url: "https://pub.dartlang.org"
570 + source: hosted
571 + version: "0.1.2"
572 + yaml:
573 + dependency: transitive
574 + description:
575 + name: yaml
576 + url: "https://pub.dartlang.org"
577 + source: hosted
578 + version: "3.1.0"
579 +sdks:
580 + dart: ">=2.12.0 <3.0.0"
581 + flutter: ">=1.20.0"
cw_bitcoin/pubspec.yaml new
+65
@@ -0,0 +1,65 @@
1 +name: cw_bitcoin
2 +description: A new Flutter package project.
3 +version: 0.0.1
4 +author:
5 +homepage:
6 +
7 +environment:
8 + sdk: ">=2.7.0 <3.0.0"
9 + flutter: ">=1.17.0"
10 +
11 +dependencies:
12 + flutter:
13 + sdk: flutter
14 + path_provider: ^1.4.0
15 + http: ^0.12.0+2
16 + mobx: ^1.2.1+2
17 + flutter_mobx: ^1.1.0+2
18 + intl: ^0.17.0
19 + cw_core:
20 + path: ../cw_core
21 +
22 +dev_dependencies:
23 + flutter_test:
24 + sdk: flutter
25 + build_runner: ^1.10.3
26 + build_resolvers: ^1.3.10
27 + mobx_codegen: ^1.1.0+1
28 + hive_generator: ^0.8.1
29 +
30 +# For information on the generic Dart part of this file, see the
31 +# following page: https://dart.dev/tools/pub/pubspec
32 +
33 +# The following section is specific to Flutter.
34 +flutter:
35 +
36 + # To add assets to your package, add an assets section, like this:
37 + # assets:
38 + # - images/a_dot_burr.jpeg
39 + # - images/a_dot_ham.jpeg
40 + #
41 + # For details regarding assets in packages, see
42 + # https://flutter.dev/assets-and-images/#from-packages
43 + #
44 + # An image asset can refer to one or more resolution-specific "variants", see
45 + # https://flutter.dev/assets-and-images/#resolution-aware.
46 +
47 + # To add custom fonts to your package, add a fonts section here,
48 + # in this "flutter" section. Each entry in this list should have a
49 + # "family" key with the font family name, and a "fonts" key with a
50 + # list giving the asset and other descriptors for the font. For
51 + # example:
52 + # fonts:
53 + # - family: Schyler
54 + # fonts:
55 + # - asset: fonts/Schyler-Regular.ttf
56 + # - asset: fonts/Schyler-Italic.ttf
57 + # style: italic
58 + # - family: Trajan Pro
59 + # fonts:
60 + # - asset: fonts/TrajanPro.ttf
61 + # - asset: fonts/TrajanPro_Bold.ttf
62 + # weight: 700
63 + #
64 + # For details regarding fonts in packages, see
65 + # https://flutter.dev/custom-fonts/#from-packages
cw_bitcoin/test/cw_bitcoin_test.dart new
+12
@@ -0,0 +1,12 @@
1 +import 'package:flutter_test/flutter_test.dart';
2 +
3 +import 'package:cw_bitcoin/cw_bitcoin.dart';
4 +
5 +void main() {
6 + test('adds one to input values', () {
7 + final calculator = Calculator();
8 + expect(calculator.addOne(2), 3);
9 + expect(calculator.addOne(-7), -6);
10 + expect(calculator.addOne(0), 1);
11 + });
12 +}
cw_core/.gitignore new
+74
@@ -0,0 +1,74 @@
1 +# Miscellaneous
2 +*.class
3 +*.log
4 +*.pyc
5 +*.swp
6 +.DS_Store
7 +.atom/
8 +.buildlog/
9 +.history
10 +.svn/
11 +
12 +# IntelliJ related
13 +*.iml
14 +*.ipr
15 +*.iws
16 +.idea/
17 +
18 +# The .vscode folder contains launch configuration and tasks you configure in
19 +# VS Code which you may wish to be included in version control, so this line
20 +# is commented out by default.
21 +#.vscode/
22 +
23 +# Flutter/Dart/Pub related
24 +**/doc/api/
25 +.dart_tool/
26 +.flutter-plugins
27 +.flutter-plugins-dependencies
28 +.packages
29 +.pub-cache/
30 +.pub/
31 +build/
32 +
33 +# Android related
34 +**/android/**/gradle-wrapper.jar
35 +**/android/.gradle
36 +**/android/captures/
37 +**/android/gradlew
38 +**/android/gradlew.bat
39 +**/android/local.properties
40 +**/android/**/GeneratedPluginRegistrant.java
41 +
42 +# iOS/XCode related
43 +**/ios/**/*.mode1v3
44 +**/ios/**/*.mode2v3
45 +**/ios/**/*.moved-aside
46 +**/ios/**/*.pbxuser
47 +**/ios/**/*.perspectivev3
48 +**/ios/**/*sync/
49 +**/ios/**/.sconsign.dblite
50 +**/ios/**/.tags*
51 +**/ios/**/.vagrant/
52 +**/ios/**/DerivedData/
53 +**/ios/**/Icon?
54 +**/ios/**/Pods/
55 +**/ios/**/.symlinks/
56 +**/ios/**/profile
57 +**/ios/**/xcuserdata
58 +**/ios/.generated/
59 +**/ios/Flutter/App.framework
60 +**/ios/Flutter/Flutter.framework
61 +**/ios/Flutter/Flutter.podspec
62 +**/ios/Flutter/Generated.xcconfig
63 +**/ios/Flutter/app.flx
64 +**/ios/Flutter/app.zip
65 +**/ios/Flutter/flutter_assets/
66 +**/ios/Flutter/flutter_export_environment.sh
67 +**/ios/ServiceDefinitions.json
68 +**/ios/Runner/GeneratedPluginRegistrant.*
69 +
70 +# Exceptions to above rules.
71 +!**/ios/**/default.mode1v3
72 +!**/ios/**/default.mode2v3
73 +!**/ios/**/default.pbxuser
74 +!**/ios/**/default.perspectivev3
cw_core/.metadata new
+10
@@ -0,0 +1,10 @@
1 +# This file tracks properties of this Flutter project.
2 +# Used by Flutter tool to assess capabilities and perform upgrades etc.
3 +#
4 +# This file should be version controlled and should not be manually edited.
5 +
6 +version:
7 + revision: b1395592de68cc8ac4522094ae59956dd21a91db
8 + channel: stable
9 +
10 +project_type: package
cw_core/CHANGELOG.md new
+3
@@ -0,0 +1,3 @@
1 +## [0.0.1] - TODO: Add release date.
2 +
3 +* TODO: Describe initial release.
cw_core/LICENSE new
+1
@@ -0,0 +1 @@
1 +TODO: Add your license here.
cw_core/README.md new
+14
@@ -0,0 +1,14 @@
1 +# cw_core
2 +
3 +A new Flutter package project.
4 +
5 +## Getting Started
6 +
7 +This project is a starting point for a Dart
8 +[package](https://flutter.dev/developing-packages/),
9 +a library module containing code that can be shared easily across
10 +multiple Flutter or Dart projects.
11 +
12 +For help getting started with Flutter, view our
13 +[online documentation](https://flutter.dev/docs), which offers tutorials,
14 +samples, guidance on mobile development, and a full API reference.
cw_core/lib/balance.dart new
+11
@@ -0,0 +1,11 @@
1 +abstract class Balance {
2 + const Balance(this.available, this.additional);
3 +
4 + final int available;
5 +
6 + final int additional;
7 +
8 + String get formattedAvailableBalance;
9 +
10 + String get formattedAdditionalBalance;
11 +}
cw_core/lib/crypto_amount_format.dart new
+1
@@ -0,0 +1 @@
1 +double cryptoAmountToDouble({num amount, num divider}) => amount / divider;
\ No newline at end of file
cw_core/lib/crypto_currency.dart new
+125
@@ -0,0 +1,125 @@
1 +import 'package:cw_core/enumerable_item.dart';
2 +import 'package:hive/hive.dart';
3 +
4 +part 'crypto_currency.g.dart';
5 +
6 +@HiveType(typeId: 0)
7 +class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
8 + const CryptoCurrency({final String title, final int raw})
9 + : super(title: title, raw: raw);
10 +
11 + static const all = [
12 + CryptoCurrency.xmr,
13 + CryptoCurrency.ada,
14 + CryptoCurrency.bch,
15 + CryptoCurrency.bnb,
16 + CryptoCurrency.btc,
17 + CryptoCurrency.dai,
18 + CryptoCurrency.dash,
19 + CryptoCurrency.eos,
20 + CryptoCurrency.eth,
21 + CryptoCurrency.ltc,
22 + CryptoCurrency.trx,
23 + CryptoCurrency.usdt,
24 + CryptoCurrency.usdterc20,
25 + CryptoCurrency.xlm,
26 + CryptoCurrency.xrp
27 + ];
28 + static const xmr = CryptoCurrency(title: 'XMR', raw: 0);
29 + static const ada = CryptoCurrency(title: 'ADA', raw: 1);
30 + static const bch = CryptoCurrency(title: 'BCH', raw: 2);
31 + static const bnb = CryptoCurrency(title: 'BNB BEP2', raw: 3);
32 + static const btc = CryptoCurrency(title: 'BTC', raw: 4);
33 + static const dai = CryptoCurrency(title: 'DAI', raw: 5);
34 + static const dash = CryptoCurrency(title: 'DASH', raw: 6);
35 + static const eos = CryptoCurrency(title: 'EOS', raw: 7);
36 + static const eth = CryptoCurrency(title: 'ETH', raw: 8);
37 + static const ltc = CryptoCurrency(title: 'LTC', raw: 9);
38 + static const nano = CryptoCurrency(title: 'NANO', raw: 10);
39 + static const trx = CryptoCurrency(title: 'TRX', raw: 11);
40 + static const usdt = CryptoCurrency(title: 'USDT', raw: 12);
41 + static const usdterc20 = CryptoCurrency(title: 'USDTERC20', raw: 13);
42 + static const xlm = CryptoCurrency(title: 'XLM', raw: 14);
43 + static const xrp = CryptoCurrency(title: 'XRP', raw: 15);
44 +
45 + static CryptoCurrency deserialize({int raw}) {
46 + switch (raw) {
47 + case 0:
48 + return CryptoCurrency.xmr;
49 + case 1:
50 + return CryptoCurrency.ada;
51 + case 2:
52 + return CryptoCurrency.bch;
53 + case 3:
54 + return CryptoCurrency.bnb;
55 + case 4:
56 + return CryptoCurrency.btc;
57 + case 5:
58 + return CryptoCurrency.dai;
59 + case 6:
60 + return CryptoCurrency.dash;
61 + case 7:
62 + return CryptoCurrency.eos;
63 + case 8:
64 + return CryptoCurrency.eth;
65 + case 9:
66 + return CryptoCurrency.ltc;
67 + case 10:
68 + return CryptoCurrency.nano;
69 + case 11:
70 + return CryptoCurrency.trx;
71 + case 12:
72 + return CryptoCurrency.usdt;
73 + case 13:
74 + return CryptoCurrency.usdterc20;
75 + case 14:
76 + return CryptoCurrency.xlm;
77 + case 15:
78 + return CryptoCurrency.xrp;
79 + default:
80 + return null;
81 + }
82 + }
83 +
84 + static CryptoCurrency fromString(String raw) {
85 + switch (raw.toLowerCase()) {
86 + case 'xmr':
87 + return CryptoCurrency.xmr;
88 + case 'ada':
89 + return CryptoCurrency.ada;
90 + case 'bch':
91 + return CryptoCurrency.bch;
92 + case 'bnbmainnet':
93 + return CryptoCurrency.bnb;
94 + case 'btc':
95 + return CryptoCurrency.btc;
96 + case 'dai':
97 + return CryptoCurrency.dai;
98 + case 'dash':
99 + return CryptoCurrency.dash;
100 + case 'eos':
101 + return CryptoCurrency.eos;
102 + case 'eth':
103 + return CryptoCurrency.eth;
104 + case 'ltc':
105 + return CryptoCurrency.ltc;
106 + case 'nano':
107 + return CryptoCurrency.nano;
108 + case 'trx':
109 + return CryptoCurrency.trx;
110 + case 'usdt':
111 + return CryptoCurrency.usdt;
112 + case 'usdterc20':
113 + return CryptoCurrency.usdterc20;
114 + case 'xlm':
115 + return CryptoCurrency.xlm;
116 + case 'xrp':
117 + return CryptoCurrency.xrp;
118 + default:
119 + return null;
120 + }
121 + }
122 +
123 + @override
124 + String toString() => title;
125 +}
cw_core/lib/currency_for_wallet_type.dart new
+15
@@ -0,0 +1,15 @@
1 +import 'package:cw_core/crypto_currency.dart';
2 +import 'package:cw_core/wallet_type.dart';
3 +
4 +CryptoCurrency currencyForWalletType(WalletType type) {
5 + switch (type) {
6 + case WalletType.bitcoin:
7 + return CryptoCurrency.btc;
8 + case WalletType.monero:
9 + return CryptoCurrency.xmr;
10 + case WalletType.litecoin:
11 + return CryptoCurrency.ltc;
12 + default:
13 + return null;
14 + }
15 +}
cw_core/lib/enumerable_item.dart new
+16
@@ -0,0 +1,16 @@
1 +import 'package:flutter/foundation.dart';
2 +
3 +abstract class EnumerableItem<T> {
4 + const EnumerableItem({@required this.title, @required this.raw});
5 +
6 + final T raw;
7 + final String title;
8 +
9 + @override
10 + String toString() => title;
11 +}
12 +
13 +mixin Serializable<T> on EnumerableItem<T> {
14 + static Serializable deserialize<T>({T raw}) => null;
15 + T serialize() => raw;
16 +}
cw_core/lib/format_amount.dart new
+8
@@ -0,0 +1,8 @@
1 +String formatAmount(String amount) {
2 + if ((!amount.contains('.'))&&(!amount.contains(','))) {
3 + return amount + '.00';
4 + } else if ((amount.endsWith('.'))||(amount.endsWith(','))) {
5 + return amount + '00';
6 + }
7 + return amount;
8 +}
\ No newline at end of file
cw_core/lib/key.dart new
+34
@@ -0,0 +1,34 @@
1 +import 'package:encrypt/encrypt.dart' as encrypt;
2 +
3 +const ivEncodedStringLength = 12;
4 +
5 +String generateKey() {
6 + final key = encrypt.Key.fromSecureRandom(512);
7 + final iv = encrypt.IV.fromSecureRandom(8);
8 +
9 + return key.base64 + iv.base64;
10 +}
11 +
12 +List<String> extractKeys(String key) {
13 + final _key = key.substring(0, key.length - ivEncodedStringLength);
14 + final iv = key.substring(key.length - ivEncodedStringLength);
15 +
16 + return [_key, iv];
17 +}
18 +
19 +Future<String> encode({encrypt.Key key, encrypt.IV iv, String data}) async {
20 + final encrypter = encrypt.Encrypter(encrypt.Salsa20(key));
21 + final encrypted = encrypter.encrypt(data, iv: iv);
22 +
23 + return encrypted.base64;
24 +}
25 +
26 +Future<String> decode({String password, String data}) async {
27 + final keys = extractKeys(password);
28 + final key = encrypt.Key.fromBase64(keys.first);
29 + final iv = encrypt.IV.fromBase64(keys.last);
30 + final encrypter = encrypt.Encrypter(encrypt.Salsa20(key));
31 + final encrypted = encrypter.decrypt64(data, iv: iv);
32 +
33 + return encrypted;
34 +}
cw_core/lib/keyable.dart new
+3
@@ -0,0 +1,3 @@
1 +mixin Keyable {
2 + dynamic keyIndex;
3 +}
\ No newline at end of file
cw_core/lib/node.dart new
+132
@@ -0,0 +1,132 @@
1 +import 'dart:io';
2 +
3 +import 'package:cw_core/keyable.dart';
4 +import 'package:flutter/foundation.dart';
5 +import 'dart:convert';
6 +import 'package:http/http.dart' as http;
7 +import 'package:hive/hive.dart';
8 +import 'package:cw_core/wallet_type.dart';
9 +//import 'package:cake_wallet/entities/digest_request.dart';
10 +
11 +part 'node.g.dart';
12 +
13 +Uri createUriFromElectrumAddress(String address) =>
14 + Uri.tryParse('tcp://$address');
15 +
16 +@HiveType(typeId: Node.typeId)
17 +class Node extends HiveObject with Keyable {
18 + Node(
19 + {@required String uri,
20 + @required WalletType type,
21 + this.login,
22 + this.password,
23 + this.useSSL}) {
24 + uriRaw = uri;
25 + this.type = type;
26 + }
27 +
28 + Node.fromMap(Map map)
29 + : uriRaw = map['uri'] as String ?? '',
30 + login = map['login'] as String,
31 + password = map['password'] as String,
32 + typeRaw = map['typeRaw'] as int,
33 + useSSL = map['useSSL'] as bool;
34 +
35 + static const typeId = 1;
36 + static const boxName = 'Nodes';
37 +
38 + @HiveField(0)
39 + String uriRaw;
40 +
41 + @HiveField(1)
42 + String login;
43 +
44 + @HiveField(2)
45 + String password;
46 +
47 + @HiveField(3)
48 + int typeRaw;
49 +
50 + @HiveField(4)
51 + bool useSSL;
52 +
53 + bool get isSSL => useSSL ?? false;
54 +
55 + Uri get uri {
56 + switch (type) {
57 + case WalletType.monero:
58 + return Uri.http(uriRaw, '');
59 + case WalletType.bitcoin:
60 + return createUriFromElectrumAddress(uriRaw);
61 + case WalletType.litecoin:
62 + return createUriFromElectrumAddress(uriRaw);
63 + default:
64 + return null;
65 + }
66 + }
67 +
68 + @override
69 + dynamic get keyIndex {
70 + _keyIndex ??= key;
71 + return _keyIndex;
72 + }
73 +
74 + WalletType get type => deserializeFromInt(typeRaw);
75 +
76 + set type(WalletType type) => typeRaw = serializeToInt(type);
77 +
78 + dynamic _keyIndex;
79 +
80 + Future<bool> requestNode() async {
81 + try {
82 + switch (type) {
83 + case WalletType.monero:
84 + return requestMoneroNode();
85 + case WalletType.bitcoin:
86 + return requestElectrumServer();
87 + case WalletType.litecoin:
88 + return requestElectrumServer();
89 + default:
90 + return false;
91 + }
92 + } catch (_) {
93 + return false;
94 + }
95 + }
96 +
97 + Future<bool> requestMoneroNode() async {
98 + return false;
99 + //try {
100 + // Map<String, dynamic> resBody;
101 +
102 + // if (login != null && password != null) {
103 + // final digestRequest = DigestRequest();
104 + // final response = await digestRequest.request(
105 + // uri: uri.toString(), login: login, password: password);
106 + // resBody = response.data as Map<String, dynamic>;
107 + // } else {
108 + // final rpcUri = Uri.http(uri.authority, '/json_rpc');
109 + // final headers = {'Content-type': 'application/json'};
110 + // final body =
111 + // json.encode({'jsonrpc': '2.0', 'id': '0', 'method': 'get_info'});
112 + // final response =
113 + // await http.post(rpcUri.toString(), headers: headers, body: body);
114 + // resBody = json.decode(response.body) as Map<String, dynamic>;
115 + // }
116 +
117 + // return !(resBody['result']['offline'] as bool);
118 + //} catch (_) {
119 + // return false;
120 + //}
121 + }
122 +
123 + Future<bool> requestElectrumServer() async {
124 + try {
125 + await SecureSocket.connect(uri.host, uri.port,
126 + timeout: Duration(seconds: 5), onBadCertificate: (_) => true);
127 + return true;
128 + } catch (_) {
129 + return false;
130 + }
131 + }
132 +}
cw_core/lib/output_info.dart new
+20
@@ -0,0 +1,20 @@
1 +class OutputInfo {
2 + const OutputInfo(
3 + {this.fiatAmount,
4 + this.cryptoAmount,
5 + this.address,
6 + this.note,
7 + this.sendAll,
8 + this.extractedAddress,
9 + this.isParsedAddress,
10 + this.formattedCryptoAmount});
11 +
12 + final String fiatAmount;
13 + final String cryptoAmount;
14 + final String address;
15 + final String note;
16 + final String extractedAddress;
17 + final bool sendAll;
18 + final bool isParsedAddress;
19 + final int formattedCryptoAmount;
20 +}
\ No newline at end of file
cw_core/lib/parseBoolFromString.dart new
+3
@@ -0,0 +1,3 @@
1 +bool parseBoolFromString(String string) {
2 + return string.toString() == 'true';
3 +}
\ No newline at end of file
cw_core/lib/pathForWallet.dart new
+28
@@ -0,0 +1,28 @@
1 +import 'dart:io';
2 +import 'package:cw_core/wallet_type.dart';
3 +import 'package:flutter/foundation.dart';
4 +import 'package:path_provider/path_provider.dart';
5 +
6 +Future<String> pathForWalletDir({@required String name, @required WalletType type}) async {
7 + final root = await getApplicationDocumentsDirectory();
8 + final prefix = walletTypeToString(type).toLowerCase();
9 + final walletsDir = Directory('${root.path}/wallets');
10 + final walletDire = Directory('${walletsDir.path}/$prefix/$name');
11 +
12 + if (!walletDire.existsSync()) {
13 + walletDire.createSync(recursive: true);
14 + }
15 +
16 + return walletDire.path;
17 +}
18 +
19 +Future<String> pathForWallet({@required String name, @required WalletType type}) async =>
20 + await pathForWalletDir(name: name, type: type)
21 + .then((path) => path + '/$name');
22 +
23 +Future<String> outdatedAndroidPathForWalletDir({String name}) async {
24 + final directory = await getApplicationDocumentsDirectory();
25 + final pathDir = directory.path + '/$name';
26 +
27 + return pathDir;
28 +}
\ No newline at end of file
cw_core/lib/pending_transaction.dart new
+7
@@ -0,0 +1,7 @@
1 +mixin PendingTransaction {
2 + String get id;
3 + String get amountFormatted;
4 + String get feeFormatted;
5 +
6 + Future<void> commit();
7 +}
\ No newline at end of file
cw_core/lib/sync_status.dart new
+54
@@ -0,0 +1,54 @@
1 +abstract class SyncStatus {
2 + const SyncStatus();
3 + double progress();
4 +}
5 +
6 +class SyncingSyncStatus extends SyncStatus {
7 + SyncingSyncStatus(this.blocksLeft, this.ptc);
8 +
9 + final double ptc;
10 + final int blocksLeft;
11 +
12 + @override
13 + double progress() => ptc;
14 +
15 + @override
16 + String toString() => '$blocksLeft';
17 +}
18 +
19 +class SyncedSyncStatus extends SyncStatus {
20 + @override
21 + double progress() => 1.0;
22 +}
23 +
24 +class NotConnectedSyncStatus extends SyncStatus {
25 + const NotConnectedSyncStatus();
26 +
27 + @override
28 + double progress() => 0.0;
29 +}
30 +
31 +class StartingSyncStatus extends SyncStatus {
32 + @override
33 + double progress() => 0.0;
34 +}
35 +
36 +class FailedSyncStatus extends SyncStatus {
37 + @override
38 + double progress() => 1.0;
39 +}
40 +
41 +class ConnectingSyncStatus extends SyncStatus {
42 + @override
43 + double progress() => 0.0;
44 +}
45 +
46 +class ConnectedSyncStatus extends SyncStatus {
47 + @override
48 + double progress() => 0.0;
49 +}
50 +
51 +class LostConnectionSyncStatus extends SyncStatus {
52 + @override
53 + double progress() => 1.0;
54 +}
\ No newline at end of file
cw_core/lib/transaction_direction.dart new
+17
@@ -0,0 +1,17 @@
1 +enum TransactionDirection { incoming, outgoing }
2 +
3 +TransactionDirection parseTransactionDirectionFromInt(int raw) {
4 + switch (raw) {
5 + case 0: return TransactionDirection.incoming;
6 + case 1: return TransactionDirection.outgoing;
7 + default: return null;
8 + }
9 +}
10 +
11 +TransactionDirection parseTransactionDirectionFromNumber(String raw) {
12 + switch (raw) {
13 + case "0": return TransactionDirection.incoming;
14 + case "1": return TransactionDirection.outgoing;
15 + default: return null;
16 + }
17 +}
\ No newline at end of file
cw_core/lib/transaction_history.dart new
+52
@@ -0,0 +1,52 @@
1 +import 'package:flutter/foundation.dart';
2 +import 'package:mobx/mobx.dart';
3 +import 'package:cw_core/transaction_info.dart';
4 +
5 +abstract class TransactionHistoryBase<TransactionType extends TransactionInfo> {
6 + TransactionHistoryBase();
7 + // : _isUpdating = false;
8 +
9 + @observable
10 + ObservableMap<String, TransactionType> transactions;
11 +
12 + Future<void> save();
13 +
14 + void addOne(TransactionType transaction);
15 +
16 + void addMany(Map<String, TransactionType> transactions);
17 +
18 + // bool _isUpdating;
19 +
20 + // @action
21 + // Future<void> update() async {
22 + // if (_isUpdating) {
23 + // return;
24 + // }
25 +
26 + // try {
27 + // _isUpdating = true;
28 + // final _transactions = await fetchTransactions();
29 + // transactions.keys
30 + // .toSet()
31 + // .difference(_transactions.keys.toSet())
32 + // .forEach((k) => transactions.remove(k));
33 + // _transactions.forEach((key, value) => transactions[key] = value);
34 + // _isUpdating = false;
35 + // } catch (e) {
36 + // _isUpdating = false;
37 + // rethrow;
38 + // }
39 + // }
40 +
41 + // void updateAsync({void Function() onFinished}) {
42 + // fetchTransactionsAsync(
43 + // (transaction) => transactions[transaction.id] = transaction,
44 + // onFinished: onFinished);
45 + // }
46 +
47 + // void fetchTransactionsAsync(
48 + // void Function(TransactionType transaction) onTransactionLoaded,
49 + // {void Function() onFinished});
50 +
51 + // Future<Map<String, TransactionType>> fetchTransactions();
52 +}
cw_core/lib/transaction_info.dart new
+21
@@ -0,0 +1,21 @@
1 +import 'package:cw_core/transaction_direction.dart';
2 +import 'package:cake_wallet/utils/mobx.dart';
3 +import 'package:cw_core/keyable.dart';
4 +
5 +abstract class TransactionInfo extends Object with Keyable {
6 + String id;
7 + int amount;
8 + int fee;
9 + TransactionDirection direction;
10 + bool isPending;
11 + DateTime date;
12 + int height;
13 + int confirmations;
14 + String amountFormatted();
15 + String fiatAmount();
16 + String feeFormatted();
17 + void changeFiatAmount(String amount);
18 +
19 + @override
20 + dynamic get keyIndex => id;
21 +}
\ No newline at end of file
cw_core/lib/transaction_priority.dart new
+6
@@ -0,0 +1,6 @@
1 +import 'package:cw_core/enumerable_item.dart';
2 +
3 +abstract class TransactionPriority extends EnumerableItem<int>
4 + with Serializable<int> {
5 + const TransactionPriority({String title, int raw}) : super(title: title, raw: raw);
6 +}
cw_core/lib/unspent_coins_info.dart new
+32
@@ -0,0 +1,32 @@
1 +import 'package:hive/hive.dart';
2 +
3 +part 'unspent_coins_info.g.dart';
4 +
5 +@HiveType(typeId: UnspentCoinsInfo.typeId)
6 +class UnspentCoinsInfo extends HiveObject {
7 + UnspentCoinsInfo({
8 + this.walletId,
9 + this.hash,
10 + this.isFrozen,
11 + this.isSending,
12 + this.note});
13 +
14 + static const typeId = 9;
15 + static const boxName = 'Unspent';
16 + static const boxKey = 'unspentBoxKey';
17 +
18 + @HiveField(0)
19 + String walletId;
20 +
21 + @HiveField(1)
22 + String hash;
23 +
24 + @HiveField(2)
25 + bool isFrozen;
26 +
27 + @HiveField(3)
28 + bool isSending;
29 +
30 + @HiveField(4)
31 + String note;
32 +}
\ No newline at end of file
cw_core/lib/wallet_addresses.dart new
+36
@@ -0,0 +1,36 @@
1 +import 'package:cw_core/wallet_info.dart';
2 +
3 +abstract class WalletAddresses {
4 + WalletAddresses(this.walletInfo) {
5 + addressesMap = {};
6 + }
7 +
8 + final WalletInfo walletInfo;
9 +
10 + String get address;
11 +
12 + set address(String address);
13 +
14 + Map<String, String> addressesMap;
15 +
16 + Future<void> init();
17 +
18 + Future<void> updateAddressesInBox();
19 +
20 + Future<void> saveAddressesInBox() async {
21 + try {
22 + if (walletInfo == null) {
23 + return;
24 + }
25 +
26 + walletInfo.address = address;
27 + walletInfo.addresses = addressesMap;
28 +
29 + if (walletInfo.isInBox) {
30 + await walletInfo.save();
31 + }
32 + } catch (e) {
33 + print(e.toString());
34 + }
35 + }
36 +}
\ No newline at end of file
cw_core/lib/wallet_base.dart new
+71
@@ -0,0 +1,71 @@
1 +import 'package:cw_core/balance.dart';
2 +import 'package:cw_core/transaction_info.dart';
3 +import 'package:cw_core/transaction_priority.dart';
4 +import 'package:cw_core/wallet_addresses.dart';
5 +import 'package:flutter/foundation.dart';
6 +import 'package:cw_core/wallet_info.dart';
7 +import 'package:cw_core/pending_transaction.dart';
8 +import 'package:cw_core/transaction_history.dart';
9 +import 'package:cw_core/currency_for_wallet_type.dart';
10 +import 'package:cw_core/crypto_currency.dart';
11 +import 'package:cw_core/sync_status.dart';
12 +import 'package:cw_core/node.dart';
13 +import 'package:cw_core/wallet_type.dart';
14 +
15 +abstract class WalletBase<
16 + BalanceType extends Balance,
17 + HistoryType extends TransactionHistoryBase,
18 + TransactionType extends TransactionInfo> {
19 + WalletBase(this.walletInfo);
20 +
21 + static String idFor(String name, WalletType type) =>
22 + walletTypeToString(type).toLowerCase() + '_' + name;
23 +
24 + WalletInfo walletInfo;
25 +
26 + WalletType get type => walletInfo.type;
27 +
28 + CryptoCurrency get currency => currencyForWalletType(type);
29 +
30 + String get id => walletInfo.id;
31 +
32 + String get name => walletInfo.name;
33 +
34 + //String get address;
35 +
36 + //set address(String address);
37 +
38 + BalanceType get balance;
39 +
40 + SyncStatus get syncStatus;
41 +
42 + set syncStatus(SyncStatus status);
43 +
44 + String get seed;
45 +
46 + Object get keys;
47 +
48 + WalletAddresses get walletAddresses;
49 +
50 + HistoryType transactionHistory;
51 +
52 + Future<void> connectToNode({@required Node node});
53 +
54 + Future<void> startSync();
55 +
56 + Future<PendingTransaction> createTransaction(Object credentials);
57 +
58 + int calculateEstimatedFee(TransactionPriority priority, int amount);
59 +
60 + // void fetchTransactionsAsync(
61 + // void Function(TransactionType transaction) onTransactionLoaded,
62 + // {void Function() onFinished});
63 +
64 + Future<Map<String, TransactionType>> fetchTransactions();
65 +
66 + Future<void> save();
67 +
68 + Future<void> rescan({int height});
69 +
70 + void close();
71 +}
cw_core/lib/wallet_credentials.dart new
+10
@@ -0,0 +1,10 @@
1 +import 'package:cw_core/wallet_info.dart';
2 +
3 +abstract class WalletCredentials {
4 + WalletCredentials({this.name, this.password, this.height, this.walletInfo});
5 +
6 + final String name;
7 + final int height;
8 + String password;
9 + WalletInfo walletInfo;
10 +}
cw_core/lib/wallet_info.dart new
+85
@@ -0,0 +1,85 @@
1 +import 'package:flutter/foundation.dart';
2 +import 'package:hive/hive.dart';
3 +import 'package:cw_core/wallet_type.dart';
4 +import 'dart:async';
5 +
6 +part 'wallet_info.g.dart';
7 +
8 +@HiveType(typeId: WalletInfo.typeId)
9 +class WalletInfo extends HiveObject {
10 + WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight,
11 + this.timestamp, this.dirPath, this.path, this.address, this.yatEid,
12 + this.yatLastUsedAddressRaw)
13 + : _yatLastUsedAddressController = StreamController<String>.broadcast();
14 +
15 + factory WalletInfo.external(
16 + {@required String id,
17 + @required String name,
18 + @required WalletType type,
19 + @required bool isRecovery,
20 + @required int restoreHeight,
21 + @required DateTime date,
22 + @required String dirPath,
23 + @required String path,
24 + @required String address,
25 + String yatEid ='',
26 + String yatLastUsedAddressRaw = ''}) {
27 + return WalletInfo(id, name, type, isRecovery, restoreHeight,
28 + date.millisecondsSinceEpoch ?? 0, dirPath, path, address,
29 + yatEid, yatLastUsedAddressRaw);
30 + }
31 +
32 + static const typeId = 4;
33 + static const boxName = 'WalletInfo';
34 +
35 + @HiveField(0)
36 + String id;
37 +
38 + @HiveField(1)
39 + String name;
40 +
41 + @HiveField(2)
42 + WalletType type;
43 +
44 + @HiveField(3)
45 + bool isRecovery;
46 +
47 + @HiveField(4)
48 + int restoreHeight;
49 +
50 + @HiveField(5)
51 + int timestamp;
52 +
53 + @HiveField(6)
54 + String dirPath;
55 +
56 + @HiveField(7)
57 + String path;
58 +
59 + @HiveField(8)
60 + String address;
61 +
62 + @HiveField(10)
63 + Map<String, String> addresses;
64 +
65 + @HiveField(11)
66 + String yatEid;
67 +
68 + @HiveField(12)
69 + String yatLastUsedAddressRaw;
70 +
71 + String get yatLastUsedAddress => yatLastUsedAddressRaw;
72 +
73 + set yatLastUsedAddress(String address) {
74 + yatLastUsedAddressRaw = address;
75 + _yatLastUsedAddressController.add(address);
76 + }
77 +
78 + String get yatEmojiId => yatEid ?? '';
79 +
80 + DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp);
81 +
82 + Stream<String> get yatLastUsedAddressStream => _yatLastUsedAddressController.stream;
83 +
84 + StreamController<String> _yatLastUsedAddressController;
85 +}
cw_core/lib/wallet_service.dart new
+20
@@ -0,0 +1,20 @@
1 +import 'package:cw_core/wallet_base.dart';
2 +import 'package:cw_core/wallet_credentials.dart';
3 +import 'package:cw_core/wallet_type.dart';
4 +
5 +abstract class WalletService<N extends WalletCredentials,
6 + RFS extends WalletCredentials, RFK extends WalletCredentials> {
7 + WalletType getType();
8 +
9 + Future<WalletBase> create(N credentials);
10 +
11 + Future<WalletBase> restoreFromSeed(RFS credentials);
12 +
13 + Future<WalletBase> restoreFromKeys(RFK credentials);
14 +
15 + Future<WalletBase> openWallet(String name, String password);
16 +
17 + Future<bool> isWalletExit(String name);
18 +
19 + Future<void> remove(String wallet);
20 +}
cw_core/lib/wallet_type.dart new
+91
@@ -0,0 +1,91 @@
1 +import 'package:cw_core/crypto_currency.dart';
2 +import 'package:hive/hive.dart';
3 +
4 +part 'wallet_type.g.dart';
5 +
6 +const walletTypes = [
7 + WalletType.monero,
8 + WalletType.bitcoin,
9 + WalletType.litecoin
10 +];
11 +const walletTypeTypeId = 5;
12 +
13 +@HiveType(typeId: walletTypeTypeId)
14 +enum WalletType {
15 + @HiveField(0)
16 + monero,
17 +
18 + @HiveField(1)
19 + none,
20 +
21 + @HiveField(2)
22 + bitcoin,
23 +
24 + @HiveField(3)
25 + litecoin
26 +}
27 +
28 +int serializeToInt(WalletType type) {
29 + switch (type) {
30 + case WalletType.monero:
31 + return 0;
32 + case WalletType.bitcoin:
33 + return 1;
34 + case WalletType.litecoin:
35 + return 2;
36 + default:
37 + return -1;
38 + }
39 +}
40 +
41 +WalletType deserializeFromInt(int raw) {
42 + switch (raw) {
43 + case 0:
44 + return WalletType.monero;
45 + case 1:
46 + return WalletType.bitcoin;
47 + case 2:
48 + return WalletType.litecoin;
49 + default:
50 + return null;
51 + }
52 +}
53 +
54 +String walletTypeToString(WalletType type) {
55 + switch (type) {
56 + case WalletType.monero:
57 + return 'Monero';
58 + case WalletType.bitcoin:
59 + return 'Bitcoin';
60 + case WalletType.litecoin:
61 + return 'Litecoin';
62 + default:
63 + return '';
64 + }
65 +}
66 +
67 +String walletTypeToDisplayName(WalletType type) {
68 + switch (type) {
69 + case WalletType.monero:
70 + return 'Monero';
71 + case WalletType.bitcoin:
72 + return 'Bitcoin (Electrum)';
73 + case WalletType.litecoin:
74 + return 'Litecoin (Electrum)';
75 + default:
76 + return '';
77 + }
78 +}
79 +
80 +CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
81 + switch (type) {
82 + case WalletType.monero:
83 + return CryptoCurrency.xmr;
84 + case WalletType.bitcoin:
85 + return CryptoCurrency.btc;
86 + case WalletType.litecoin:
87 + return CryptoCurrency.ltc;
88 + default:
89 + return null;
90 + }
91 +}
cw_core/pubspec.lock new
+574
@@ -0,0 +1,574 @@
1 +# Generated by pub
2 +# See https://dart.dev/tools/pub/glossary#lockfile
3 +packages:
4 + _fe_analyzer_shared:
5 + dependency: transitive
6 + description:
7 + name: _fe_analyzer_shared
8 + url: "https://pub.dartlang.org"
9 + source: hosted
10 + version: "14.0.0"
11 + analyzer:
12 + dependency: transitive
13 + description:
14 + name: analyzer
15 + url: "https://pub.dartlang.org"
16 + source: hosted
17 + version: "0.41.2"
18 + args:
19 + dependency: transitive
20 + description:
21 + name: args
22 + url: "https://pub.dartlang.org"
23 + source: hosted
24 + version: "2.3.0"
25 + async:
26 + dependency: transitive
27 + description:
28 + name: async
29 + url: "https://pub.dartlang.org"
30 + source: hosted
31 + version: "2.5.0"
32 + boolean_selector:
33 + dependency: transitive
34 + description:
35 + name: boolean_selector
36 + url: "https://pub.dartlang.org"
37 + source: hosted
38 + version: "2.1.0"
39 + build:
40 + dependency: transitive
41 + description:
42 + name: build
43 + url: "https://pub.dartlang.org"
44 + source: hosted
45 + version: "1.6.2"
46 + build_config:
47 + dependency: transitive
48 + description:
49 + name: build_config
50 + url: "https://pub.dartlang.org"
51 + source: hosted
52 + version: "0.4.6"
53 + build_daemon:
54 + dependency: transitive
55 + description:
56 + name: build_daemon
57 + url: "https://pub.dartlang.org"
58 + source: hosted
59 + version: "2.1.10"
60 + build_resolvers:
61 + dependency: "direct dev"
62 + description:
63 + name: build_resolvers
64 + url: "https://pub.dartlang.org"
65 + source: hosted
66 + version: "1.5.3"
67 + build_runner:
68 + dependency: "direct dev"
69 + description:
70 + name: build_runner
71 + url: "https://pub.dartlang.org"
72 + source: hosted
73 + version: "1.11.5"
74 + build_runner_core:
75 + dependency: transitive
76 + description:
77 + name: build_runner_core
78 + url: "https://pub.dartlang.org"
79 + source: hosted
80 + version: "6.1.10"
81 + built_collection:
82 + dependency: transitive
83 + description:
84 + name: built_collection
85 + url: "https://pub.dartlang.org"
86 + source: hosted
87 + version: "5.1.1"
88 + built_value:
89 + dependency: transitive
90 + description:
91 + name: built_value
92 + url: "https://pub.dartlang.org"
93 + source: hosted
94 + version: "8.1.3"
95 + characters:
96 + dependency: transitive
97 + description:
98 + name: characters
99 + url: "https://pub.dartlang.org"
100 + source: hosted
101 + version: "1.1.0"
102 + charcode:
103 + dependency: transitive
104 + description:
105 + name: charcode
106 + url: "https://pub.dartlang.org"
107 + source: hosted
108 + version: "1.2.0"
109 + checked_yaml:
110 + dependency: transitive
111 + description:
112 + name: checked_yaml
113 + url: "https://pub.dartlang.org"
114 + source: hosted
115 + version: "1.0.4"
116 + cli_util:
117 + dependency: transitive
118 + description:
119 + name: cli_util
120 + url: "https://pub.dartlang.org"
121 + source: hosted
122 + version: "0.3.5"
123 + clock:
124 + dependency: transitive
125 + description:
126 + name: clock
127 + url: "https://pub.dartlang.org"
128 + source: hosted
129 + version: "1.1.0"
130 + code_builder:
131 + dependency: transitive
132 + description:
133 + name: code_builder
134 + url: "https://pub.dartlang.org"
135 + source: hosted
136 + version: "3.7.0"
137 + collection:
138 + dependency: transitive
139 + description:
140 + name: collection
141 + url: "https://pub.dartlang.org"
142 + source: hosted
143 + version: "1.15.0"
144 + convert:
145 + dependency: transitive
146 + description:
147 + name: convert
148 + url: "https://pub.dartlang.org"
149 + source: hosted
150 + version: "3.0.1"
151 + crypto:
152 + dependency: transitive
153 + description:
154 + name: crypto
155 + url: "https://pub.dartlang.org"
156 + source: hosted
157 + version: "3.0.1"
158 + dart_style:
159 + dependency: transitive
160 + description:
161 + name: dart_style
162 + url: "https://pub.dartlang.org"
163 + source: hosted
164 + version: "1.3.12"
165 + dartx:
166 + dependency: transitive
167 + description:
168 + name: dartx
169 + url: "https://pub.dartlang.org"
170 + source: hosted
171 + version: "0.8.0"
172 + fake_async:
173 + dependency: transitive
174 + description:
175 + name: fake_async
176 + url: "https://pub.dartlang.org"
177 + source: hosted
178 + version: "1.2.0"
179 + ffi:
180 + dependency: transitive
181 + description:
182 + name: ffi
183 + url: "https://pub.dartlang.org"
184 + source: hosted
185 + version: "1.1.2"
186 + file:
187 + dependency: transitive
188 + description:
189 + name: file
190 + url: "https://pub.dartlang.org"
191 + source: hosted
192 + version: "6.1.2"
193 + fixnum:
194 + dependency: transitive
195 + description:
196 + name: fixnum
197 + url: "https://pub.dartlang.org"
198 + source: hosted
199 + version: "1.0.0"
200 + flutter:
201 + dependency: "direct main"
202 + description: flutter
203 + source: sdk
204 + version: "0.0.0"
205 + flutter_mobx:
206 + dependency: "direct main"
207 + description:
208 + name: flutter_mobx
209 + url: "https://pub.dartlang.org"
210 + source: hosted
211 + version: "1.1.0+2"
212 + flutter_test:
213 + dependency: "direct dev"
214 + description: flutter
215 + source: sdk
216 + version: "0.0.0"
217 + glob:
218 + dependency: transitive
219 + description:
220 + name: glob
221 + url: "https://pub.dartlang.org"
222 + source: hosted
223 + version: "2.0.1"
224 + graphs:
225 + dependency: transitive
226 + description:
227 + name: graphs
228 + url: "https://pub.dartlang.org"
229 + source: hosted
230 + version: "0.2.0"
231 + hive:
232 + dependency: transitive
233 + description:
234 + name: hive
235 + url: "https://pub.dartlang.org"
236 + source: hosted
237 + version: "1.6.0-nullsafety.2"
238 + hive_generator:
239 + dependency: "direct dev"
240 + description:
241 + name: hive_generator
242 + url: "https://pub.dartlang.org"
243 + source: hosted
244 + version: "0.8.2"
245 + http:
246 + dependency: "direct main"
247 + description:
248 + name: http
249 + url: "https://pub.dartlang.org"
250 + source: hosted
251 + version: "0.12.2"
252 + http_multi_server:
253 + dependency: transitive
254 + description:
255 + name: http_multi_server
256 + url: "https://pub.dartlang.org"
257 + source: hosted
258 + version: "2.2.0"
259 + http_parser:
260 + dependency: transitive
261 + description:
262 + name: http_parser
263 + url: "https://pub.dartlang.org"
264 + source: hosted
265 + version: "3.1.4"
266 + intl:
267 + dependency: "direct main"
268 + description:
269 + name: intl
270 + url: "https://pub.dartlang.org"
271 + source: hosted
272 + version: "0.17.0"
273 + io:
274 + dependency: transitive
275 + description:
276 + name: io
277 + url: "https://pub.dartlang.org"
278 + source: hosted
279 + version: "0.3.5"
280 + js:
281 + dependency: transitive
282 + description:
283 + name: js
284 + url: "https://pub.dartlang.org"
285 + source: hosted
286 + version: "0.6.3"
287 + json_annotation:
288 + dependency: transitive
289 + description:
290 + name: json_annotation
291 + url: "https://pub.dartlang.org"
292 + source: hosted
293 + version: "4.0.1"
294 + logging:
295 + dependency: transitive
296 + description:
297 + name: logging
298 + url: "https://pub.dartlang.org"
299 + source: hosted
300 + version: "1.0.2"
301 + matcher:
302 + dependency: transitive
303 + description:
304 + name: matcher
305 + url: "https://pub.dartlang.org"
306 + source: hosted
307 + version: "0.12.10"
308 + meta:
309 + dependency: transitive
310 + description:
311 + name: meta
312 + url: "https://pub.dartlang.org"
313 + source: hosted
314 + version: "1.3.0"
315 + mime:
316 + dependency: transitive
317 + description:
318 + name: mime
319 + url: "https://pub.dartlang.org"
320 + source: hosted
321 + version: "1.0.1"
322 + mobx:
323 + dependency: "direct main"
324 + description:
325 + name: mobx
326 + url: "https://pub.dartlang.org"
327 + source: hosted
328 + version: "1.2.1+4"
329 + mobx_codegen:
330 + dependency: "direct dev"
331 + description:
332 + name: mobx_codegen
333 + url: "https://pub.dartlang.org"
334 + source: hosted
335 + version: "1.1.2"
336 + package_config:
337 + dependency: transitive
338 + description:
339 + name: package_config
340 + url: "https://pub.dartlang.org"
341 + source: hosted
342 + version: "1.9.3"
343 + path:
344 + dependency: transitive
345 + description:
346 + name: path
347 + url: "https://pub.dartlang.org"
348 + source: hosted
349 + version: "1.8.0"
350 + path_provider:
351 + dependency: "direct main"
352 + description:
353 + name: path_provider
354 + url: "https://pub.dartlang.org"
355 + source: hosted
356 + version: "1.6.28"
357 + path_provider_linux:
358 + dependency: transitive
359 + description:
360 + name: path_provider_linux
361 + url: "https://pub.dartlang.org"
362 + source: hosted
363 + version: "0.0.1+2"
364 + path_provider_macos:
365 + dependency: transitive
366 + description:
367 + name: path_provider_macos
368 + url: "https://pub.dartlang.org"
369 + source: hosted
370 + version: "0.0.4+8"
371 + path_provider_platform_interface:
372 + dependency: transitive
373 + description:
374 + name: path_provider_platform_interface
375 + url: "https://pub.dartlang.org"
376 + source: hosted
377 + version: "1.0.4"
378 + path_provider_windows:
379 + dependency: transitive
380 + description:
381 + name: path_provider_windows
382 + url: "https://pub.dartlang.org"
383 + source: hosted
384 + version: "0.0.5"
385 + pedantic:
386 + dependency: transitive
387 + description:
388 + name: pedantic
389 + url: "https://pub.dartlang.org"
390 + source: hosted
391 + version: "1.11.1"
392 + platform:
393 + dependency: transitive
394 + description:
395 + name: platform
396 + url: "https://pub.dartlang.org"
397 + source: hosted
398 + version: "3.1.0"
399 + plugin_platform_interface:
400 + dependency: transitive
401 + description:
402 + name: plugin_platform_interface
403 + url: "https://pub.dartlang.org"
404 + source: hosted
405 + version: "1.0.3"
406 + pool:
407 + dependency: transitive
408 + description:
409 + name: pool
410 + url: "https://pub.dartlang.org"
411 + source: hosted
412 + version: "1.5.0"
413 + process:
414 + dependency: transitive
415 + description:
416 + name: process
417 + url: "https://pub.dartlang.org"
418 + source: hosted
419 + version: "4.2.3"
420 + pub_semver:
421 + dependency: transitive
422 + description:
423 + name: pub_semver
424 + url: "https://pub.dartlang.org"
425 + source: hosted
426 + version: "2.1.0"
427 + pubspec_parse:
428 + dependency: transitive
429 + description:
430 + name: pubspec_parse
431 + url: "https://pub.dartlang.org"
432 + source: hosted
433 + version: "0.1.8"
434 + shelf:
435 + dependency: transitive
436 + description:
437 + name: shelf
438 + url: "https://pub.dartlang.org"
439 + source: hosted
440 + version: "0.7.9"
441 + shelf_web_socket:
442 + dependency: transitive
443 + description:
444 + name: shelf_web_socket
445 + url: "https://pub.dartlang.org"
446 + source: hosted
447 + version: "0.2.4+1"
448 + sky_engine:
449 + dependency: transitive
450 + description: flutter
451 + source: sdk
452 + version: "0.0.99"
453 + source_gen:
454 + dependency: transitive
455 + description:
456 + name: source_gen
457 + url: "https://pub.dartlang.org"
458 + source: hosted
459 + version: "0.9.10+3"
460 + source_span:
461 + dependency: transitive
462 + description:
463 + name: source_span
464 + url: "https://pub.dartlang.org"
465 + source: hosted
466 + version: "1.8.0"
467 + stack_trace:
468 + dependency: transitive
469 + description:
470 + name: stack_trace
471 + url: "https://pub.dartlang.org"
472 + source: hosted
473 + version: "1.10.0"
474 + stream_channel:
475 + dependency: transitive
476 + description:
477 + name: stream_channel
478 + url: "https://pub.dartlang.org"
479 + source: hosted
480 + version: "2.1.0"
481 + stream_transform:
482 + dependency: transitive
483 + description:
484 + name: stream_transform
485 + url: "https://pub.dartlang.org"
486 + source: hosted
487 + version: "2.0.0"
488 + string_scanner:
489 + dependency: transitive
490 + description:
491 + name: string_scanner
492 + url: "https://pub.dartlang.org"
493 + source: hosted
494 + version: "1.1.0"
495 + term_glyph:
496 + dependency: transitive
497 + description:
498 + name: term_glyph
499 + url: "https://pub.dartlang.org"
500 + source: hosted
501 + version: "1.2.0"
502 + test_api:
503 + dependency: transitive
504 + description:
505 + name: test_api
506 + url: "https://pub.dartlang.org"
507 + source: hosted
508 + version: "0.2.19"
509 + time:
510 + dependency: transitive
511 + description:
512 + name: time
513 + url: "https://pub.dartlang.org"
514 + source: hosted
515 + version: "2.1.0"
516 + timing:
517 + dependency: transitive
518 + description:
519 + name: timing
520 + url: "https://pub.dartlang.org"
521 + source: hosted
522 + version: "0.1.1+3"
523 + typed_data:
524 + dependency: transitive
525 + description:
526 + name: typed_data
527 + url: "https://pub.dartlang.org"
528 + source: hosted
529 + version: "1.3.0"
530 + vector_math:
531 + dependency: transitive
532 + description:
533 + name: vector_math
534 + url: "https://pub.dartlang.org"
535 + source: hosted
536 + version: "2.1.0"
537 + watcher:
538 + dependency: transitive
539 + description:
540 + name: watcher
541 + url: "https://pub.dartlang.org"
542 + source: hosted
543 + version: "1.0.0"
544 + web_socket_channel:
545 + dependency: transitive
546 + description:
547 + name: web_socket_channel
548 + url: "https://pub.dartlang.org"
549 + source: hosted
550 + version: "1.2.0"
551 + win32:
552 + dependency: transitive
553 + description:
554 + name: win32
555 + url: "https://pub.dartlang.org"
556 + source: hosted
557 + version: "2.0.5"
558 + xdg_directories:
559 + dependency: transitive
560 + description:
561 + name: xdg_directories
562 + url: "https://pub.dartlang.org"
563 + source: hosted
564 + version: "0.1.2"
565 + yaml:
566 + dependency: transitive
567 + description:
568 + name: yaml
569 + url: "https://pub.dartlang.org"
570 + source: hosted
571 + version: "3.1.0"
572 +sdks:
573 + dart: ">=2.12.0 <3.0.0"
574 + flutter: ">=1.20.0"
cw_core/pubspec.yaml new
+63
@@ -0,0 +1,63 @@
1 +name: cw_core
2 +description: A new Flutter package project.
3 +version: 0.0.1
4 +author:
5 +homepage:
6 +
7 +environment:
8 + sdk: ">=2.7.0 <3.0.0"
9 + flutter: ">=1.17.0"
10 +
11 +dependencies:
12 + flutter:
13 + sdk: flutter
14 + http: ^0.12.0+2
15 + path_provider: ^1.3.0
16 + mobx: ^1.2.1+2
17 + flutter_mobx: ^1.1.0+2
18 + intl: ^0.17.0
19 +
20 +dev_dependencies:
21 + flutter_test:
22 + sdk: flutter
23 + build_runner: ^1.10.3
24 + build_resolvers: ^1.3.10
25 + mobx_codegen: ^1.1.0+1
26 + hive_generator: ^0.8.1
27 +
28 +# For information on the generic Dart part of this file, see the
29 +# following page: https://dart.dev/tools/pub/pubspec
30 +
31 +# The following section is specific to Flutter.
32 +flutter:
33 +
34 + # To add assets to your package, add an assets section, like this:
35 + # assets:
36 + # - images/a_dot_burr.jpeg
37 + # - images/a_dot_ham.jpeg
38 + #
39 + # For details regarding assets in packages, see
40 + # https://flutter.dev/assets-and-images/#from-packages
41 + #
42 + # An image asset can refer to one or more resolution-specific "variants", see
43 + # https://flutter.dev/assets-and-images/#resolution-aware.
44 +
45 + # To add custom fonts to your package, add a fonts section here,
46 + # in this "flutter" section. Each entry in this list should have a
47 + # "family" key with the font family name, and a "fonts" key with a
48 + # list giving the asset and other descriptors for the font. For
49 + # example:
50 + # fonts:
51 + # - family: Schyler
52 + # fonts:
53 + # - asset: fonts/Schyler-Regular.ttf
54 + # - asset: fonts/Schyler-Italic.ttf
55 + # style: italic
56 + # - family: Trajan Pro
57 + # fonts:
58 + # - asset: fonts/TrajanPro.ttf
59 + # - asset: fonts/TrajanPro_Bold.ttf
60 + # weight: 700
61 + #
62 + # For details regarding fonts in packages, see
63 + # https://flutter.dev/custom-fonts/#from-packages
cw_monero/lib/account.dart new
+16
@@ -0,0 +1,16 @@
1 +import 'package:cw_monero/api/structs/account_row.dart';
2 +
3 +class Account {
4 + Account({this.id, this.label});
5 +
6 + Account.fromMap(Map map)
7 + : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
8 + this.label = (map['label'] ?? '') as String;
9 +
10 + Account.fromRow(AccountRow row)
11 + : this.id = row.getId(),
12 + this.label = row.getLabel();
13 +
14 + final int id;
15 + final String label;
16 +}
cw_monero/lib/api/account_list.dart new
+83
@@ -0,0 +1,83 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +import 'package:cw_monero/api/signatures.dart';
4 +import 'package:cw_monero/api/types.dart';
5 +import 'package:cw_monero/api/monero_api.dart';
6 +import 'package:cw_monero/api/structs/account_row.dart';
7 +import 'package:flutter/foundation.dart';
8 +import 'package:cw_monero/api/wallet.dart';
9 +
10 +final accountSizeNative = moneroApi
11 + .lookup<NativeFunction<account_size>>('account_size')
12 + .asFunction<SubaddressSize>();
13 +
14 +final accountRefreshNative = moneroApi
15 + .lookup<NativeFunction<account_refresh>>('account_refresh')
16 + .asFunction<AccountRefresh>();
17 +
18 +final accountGetAllNative = moneroApi
19 + .lookup<NativeFunction<account_get_all>>('account_get_all')
20 + .asFunction<AccountGetAll>();
21 +
22 +final accountAddNewNative = moneroApi
23 + .lookup<NativeFunction<account_add_new>>('account_add_row')
24 + .asFunction<AccountAddNew>();
25 +
26 +final accountSetLabelNative = moneroApi
27 + .lookup<NativeFunction<account_set_label>>('account_set_label_row')
28 + .asFunction<AccountSetLabel>();
29 +
30 +bool isUpdating = false;
31 +
32 +void refreshAccounts() {
33 + try {
34 + isUpdating = true;
35 + accountRefreshNative();
36 + isUpdating = false;
37 + } catch (e) {
38 + isUpdating = false;
39 + rethrow;
40 + }
41 +}
42 +
43 +List<AccountRow> getAllAccount() {
44 + final size = accountSizeNative();
45 + final accountAddressesPointer = accountGetAllNative();
46 + final accountAddresses = accountAddressesPointer.asTypedList(size);
47 +
48 + return accountAddresses
49 + .map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
50 + .toList();
51 +}
52 +
53 +void addAccountSync({String label}) {
54 + final labelPointer = Utf8.toUtf8(label);
55 + accountAddNewNative(labelPointer);
56 + free(labelPointer);
57 +}
58 +
59 +void setLabelForAccountSync({int accountIndex, String label}) {
60 + final labelPointer = Utf8.toUtf8(label);
61 + accountSetLabelNative(accountIndex, labelPointer);
62 + free(labelPointer);
63 +}
64 +
65 +void _addAccount(String label) => addAccountSync(label: label);
66 +
67 +void _setLabelForAccount(Map<String, dynamic> args) {
68 + final label = args['label'] as String;
69 + final accountIndex = args['accountIndex'] as int;
70 +
71 + setLabelForAccountSync(label: label, accountIndex: accountIndex);
72 +}
73 +
74 +Future<void> addAccount({String label}) async {
75 + await compute(_addAccount, label);
76 + await store();
77 +}
78 +
79 +Future<void> setLabelForAccount({int accountIndex, String label}) async {
80 + await compute(
81 + _setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
82 + await store();
83 +}
\ No newline at end of file
cw_monero/lib/api/convert_utf8_to_string.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +String convertUTF8ToString({Pointer<Utf8> pointer}) {
5 + final str = Utf8.fromUtf8(pointer);
6 + free(pointer);
7 + return str;
8 +}
\ No newline at end of file
cw_monero/lib/api/exceptions/connection_to_node_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class ConnectionToNodeException implements Exception {
2 + ConnectionToNodeException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_monero/lib/api/exceptions/creation_transaction_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class CreationTransactionException implements Exception {
2 + CreationTransactionException({this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_monero/lib/api/exceptions/setup_wallet_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class SetupWalletException implements Exception {
2 + SetupWalletException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_monero/lib/api/exceptions/wallet_creation_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WalletCreationException implements Exception {
2 + WalletCreationException({this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_monero/lib/api/exceptions/wallet_opening_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class WalletOpeningException implements Exception {
2 + WalletOpeningException({this.message});
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_monero/lib/api/exceptions/wallet_restore_from_keys_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class WalletRestoreFromKeysException implements Exception {
2 + WalletRestoreFromKeysException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_monero/lib/api/exceptions/wallet_restore_from_seed_exception.dart new
+5
@@ -0,0 +1,5 @@
1 +class WalletRestoreFromSeedException implements Exception {
2 + WalletRestoreFromSeedException({this.message});
3 +
4 + final String message;
5 +}
\ No newline at end of file
cw_monero/lib/api/monero_api.dart new
+6
@@ -0,0 +1,6 @@
1 +import 'dart:ffi';
2 +import 'dart:io';
3 +
4 +final DynamicLibrary moneroApi = Platform.isAndroid
5 + ? DynamicLibrary.open("libcw_monero.so")
6 + : DynamicLibrary.open("cw_monero.framework/cw_monero");
\ No newline at end of file
cw_monero/lib/api/monero_output.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'package:flutter/foundation.dart';
2 +
3 +class MoneroOutput {
4 + MoneroOutput({@required this.address, @required this.amount});
5 +
6 + final String address;
7 + final String amount;
8 +}
\ No newline at end of file
cw_monero/lib/api/signatures.dart new
+122
@@ -0,0 +1,122 @@
1 +import 'dart:ffi';
2 +import 'package:cw_monero/api/structs/pending_transaction.dart';
3 +import 'package:cw_monero/api/structs/ut8_box.dart';
4 +import 'package:ffi/ffi.dart';
5 +
6 +typedef create_wallet = Int8 Function(
7 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Pointer<Utf8>);
8 +
9 +typedef restore_wallet_from_seed = Int8 Function(
10 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
11 +
12 +typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>,
13 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
14 +
15 +typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
16 +
17 +typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
18 +
19 +typedef error_string = Pointer<Utf8> Function();
20 +
21 +typedef get_filename = Pointer<Utf8> Function();
22 +
23 +typedef get_seed = Pointer<Utf8> Function();
24 +
25 +typedef get_address = Pointer<Utf8> Function(Int32, Int32);
26 +
27 +typedef get_full_balanace = Int64 Function(Int32);
28 +
29 +typedef get_unlocked_balanace = Int64 Function(Int32);
30 +
31 +typedef get_current_height = Int64 Function();
32 +
33 +typedef get_node_height = Int64 Function();
34 +
35 +typedef is_connected = Int8 Function();
36 +
37 +typedef setup_node = Int8 Function(
38 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int8, Int8, Pointer<Utf8>);
39 +
40 +typedef start_refresh = Void Function();
41 +
42 +typedef connect_to_node = Int8 Function();
43 +
44 +typedef set_refresh_from_block_height = Void Function(Int64);
45 +
46 +typedef set_recovering_from_seed = Void Function(Int8);
47 +
48 +typedef store_c = Void Function(Pointer<Utf8>);
49 +
50 +typedef set_listener = Void Function();
51 +
52 +typedef get_syncing_height = Int64 Function();
53 +
54 +typedef is_needed_to_refresh = Int8 Function();
55 +
56 +typedef is_new_transaction_exist = Int8 Function();
57 +
58 +typedef subaddrress_size = Int32 Function();
59 +
60 +typedef subaddrress_refresh = Void Function(Int32);
61 +
62 +typedef subaddress_get_all = Pointer<Int64> Function();
63 +
64 +typedef subaddress_add_new = Void Function(
65 + Int32 accountIndex, Pointer<Utf8> label);
66 +
67 +typedef subaddress_set_label = Void Function(
68 + Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
69 +
70 +typedef account_size = Int32 Function();
71 +
72 +typedef account_refresh = Void Function();
73 +
74 +typedef account_get_all = Pointer<Int64> Function();
75 +
76 +typedef account_add_new = Void Function(Pointer<Utf8> label);
77 +
78 +typedef account_set_label = Void Function(
79 + Int32 accountIndex, Pointer<Utf8> label);
80 +
81 +typedef transactions_refresh = Void Function();
82 +
83 +typedef get_tx_key = Pointer<Utf8> Function(Pointer<Utf8> txId);
84 +
85 +typedef transactions_count = Int64 Function();
86 +
87 +typedef transactions_get_all = Pointer<Int64> Function();
88 +
89 +typedef transaction_create = Int8 Function(
90 + Pointer<Utf8> address,
91 + Pointer<Utf8> paymentId,
92 + Pointer<Utf8> amount,
93 + Int8 priorityRaw,
94 + Int32 subaddrAccount,
95 + Pointer<Utf8Box> error,
96 + Pointer<PendingTransactionRaw> pendingTransaction);
97 +
98 +typedef transaction_create_mult_dest = Int8 Function(
99 + Pointer<Pointer<Utf8>> addresses,
100 + Pointer<Utf8> paymentId,
101 + Pointer<Pointer<Utf8>> amounts,
102 + Int32 size,
103 + Int8 priorityRaw,
104 + Int32 subaddrAccount,
105 + Pointer<Utf8Box> error,
106 + Pointer<PendingTransactionRaw> pendingTransaction);
107 +
108 +typedef transaction_commit = Int8 Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
109 +
110 +typedef secret_view_key = Pointer<Utf8> Function();
111 +
112 +typedef public_view_key = Pointer<Utf8> Function();
113 +
114 +typedef secret_spend_key = Pointer<Utf8> Function();
115 +
116 +typedef public_spend_key = Pointer<Utf8> Function();
117 +
118 +typedef close_current_wallet = Void Function();
119 +
120 +typedef on_startup = Void Function();
121 +
122 +typedef rescan_blockchain = Void Function();
cw_monero/lib/api/structs/account_row.dart new
+11
@@ -0,0 +1,11 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class AccountRow extends Struct {
5 + @Int64()
6 + int id;
7 + Pointer<Utf8> label;
8 +
9 + String getLabel() => Utf8.fromUtf8(label);
10 + int getId() => id;
11 +}
cw_monero/lib/api/structs/pending_transaction.dart new
+23
@@ -0,0 +1,23 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class PendingTransactionRaw extends Struct {
5 + @Int64()
6 + int amount;
7 +
8 + @Int64()
9 + int fee;
10 +
11 + Pointer<Utf8> hash;
12 +
13 + String getHash() => Utf8.fromUtf8(hash);
14 +}
15 +
16 +class PendingTransactionDescription {
17 + PendingTransactionDescription({this.amount, this.fee, this.hash, this.pointerAddress});
18 +
19 + final int amount;
20 + final int fee;
21 + final String hash;
22 + final int pointerAddress;
23 +}
\ No newline at end of file
cw_monero/lib/api/structs/subaddress_row.dart new
+13
@@ -0,0 +1,13 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class SubaddressRow extends Struct {
5 + @Int64()
6 + int id;
7 + Pointer<Utf8> address;
8 + Pointer<Utf8> label;
9 +
10 + String getLabel() => Utf8.fromUtf8(label);
11 + String getAddress() => Utf8.fromUtf8(address);
12 + int getId() => id;
13 +}
\ No newline at end of file
cw_monero/lib/api/structs/transaction_info_row.dart new
+41
@@ -0,0 +1,41 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class TransactionInfoRow extends Struct {
5 + @Uint64()
6 + int amount;
7 +
8 + @Uint64()
9 + int fee;
10 +
11 + @Uint64()
12 + int blockHeight;
13 +
14 + @Uint64()
15 + int confirmations;
16 +
17 + @Uint32()
18 + int subaddrAccount;
19 +
20 + @Int8()
21 + int direction;
22 +
23 + @Int8()
24 + int isPending;
25 +
26 + @Uint32()
27 + int subaddrIndex;
28 +
29 + Pointer<Utf8> hash;
30 +
31 + Pointer<Utf8> paymentId;
32 +
33 + @Int64()
34 + int datetime;
35 +
36 + int getDatetime() => datetime;
37 + int getAmount() => amount >= 0 ? amount : amount * -1;
38 + bool getIsPending() => isPending != 0;
39 + String getHash() => Utf8.fromUtf8(hash);
40 + String getPaymentId() => Utf8.fromUtf8(paymentId);
41 +}
cw_monero/lib/api/structs/ut8_box.dart new
+8
@@ -0,0 +1,8 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +
4 +class Utf8Box extends Struct {
5 + Pointer<Utf8> value;
6 +
7 + String getValue() => Utf8.fromUtf8(value);
8 +}
cw_monero/lib/api/subaddress_list.dart new
+97
@@ -0,0 +1,97 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +import 'package:flutter/foundation.dart';
4 +import 'package:cw_monero/api/signatures.dart';
5 +import 'package:cw_monero/api/types.dart';
6 +import 'package:cw_monero/api/monero_api.dart';
7 +import 'package:cw_monero/api/structs/subaddress_row.dart';
8 +import 'package:cw_monero/api/wallet.dart';
9 +
10 +final subaddressSizeNative = moneroApi
11 + .lookup<NativeFunction<subaddrress_size>>('subaddrress_size')
12 + .asFunction<SubaddressSize>();
13 +
14 +final subaddressRefreshNative = moneroApi
15 + .lookup<NativeFunction<subaddrress_refresh>>('subaddress_refresh')
16 + .asFunction<SubaddressRefresh>();
17 +
18 +final subaddrressGetAllNative = moneroApi
19 + .lookup<NativeFunction<subaddress_get_all>>('subaddrress_get_all')
20 + .asFunction<SubaddressGetAll>();
21 +
22 +final subaddrressAddNewNative = moneroApi
23 + .lookup<NativeFunction<subaddress_add_new>>('subaddress_add_row')
24 + .asFunction<SubaddressAddNew>();
25 +
26 +final subaddrressSetLabelNative = moneroApi
27 + .lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
28 + .asFunction<SubaddressSetLabel>();
29 +
30 +bool isUpdating = false;
31 +
32 +void refreshSubaddresses({@required int accountIndex}) {
33 + try {
34 + isUpdating = true;
35 + subaddressRefreshNative(accountIndex);
36 + isUpdating = false;
37 + } catch (e) {
38 + isUpdating = false;
39 + rethrow;
40 + }
41 +}
42 +
43 +List<SubaddressRow> getAllSubaddresses() {
44 + final size = subaddressSizeNative();
45 + final subaddressAddressesPointer = subaddrressGetAllNative();
46 + final subaddressAddresses = subaddressAddressesPointer.asTypedList(size);
47 +
48 + return subaddressAddresses
49 + .map((addr) => Pointer<SubaddressRow>.fromAddress(addr).ref)
50 + .toList();
51 +}
52 +
53 +void addSubaddressSync({int accountIndex, String label}) {
54 + final labelPointer = Utf8.toUtf8(label);
55 + subaddrressAddNewNative(accountIndex, labelPointer);
56 + free(labelPointer);
57 +}
58 +
59 +void setLabelForSubaddressSync(
60 + {int accountIndex, int addressIndex, String label}) {
61 + final labelPointer = Utf8.toUtf8(label);
62 +
63 + subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
64 + free(labelPointer);
65 +}
66 +
67 +void _addSubaddress(Map<String, dynamic> args) {
68 + final label = args['label'] as String;
69 + final accountIndex = args['accountIndex'] as int;
70 +
71 + addSubaddressSync(accountIndex: accountIndex, label: label);
72 +}
73 +
74 +void _setLabelForSubaddress(Map<String, dynamic> args) {
75 + final label = args['label'] as String;
76 + final accountIndex = args['accountIndex'] as int;
77 + final addressIndex = args['addressIndex'] as int;
78 +
79 + setLabelForSubaddressSync(
80 + accountIndex: accountIndex, addressIndex: addressIndex, label: label);
81 +}
82 +
83 +Future addSubaddress({int accountIndex, String label}) async {
84 + await compute<Map<String, Object>, void>(
85 + _addSubaddress, {'accountIndex': accountIndex, 'label': label});
86 + await store();
87 +}
88 +
89 +Future setLabelForSubaddress(
90 + {int accountIndex, int addressIndex, String label}) async {
91 + await compute<Map<String, Object>, void>(_setLabelForSubaddress, {
92 + 'accountIndex': accountIndex,
93 + 'addressIndex': addressIndex,
94 + 'label': label
95 + });
96 + await store();
97 +}
cw_monero/lib/api/transaction_history.dart new
+230
@@ -0,0 +1,230 @@
1 +import 'dart:ffi';
2 +import 'package:cw_monero/api/convert_utf8_to_string.dart';
3 +import 'package:cw_monero/api/monero_output.dart';
4 +import 'package:cw_monero/api/structs/ut8_box.dart';
5 +import 'package:ffi/ffi.dart';
6 +import 'package:flutter/foundation.dart';
7 +import 'package:cw_monero/api/signatures.dart';
8 +import 'package:cw_monero/api/types.dart';
9 +import 'package:cw_monero/api/monero_api.dart';
10 +import 'package:cw_monero/api/structs/transaction_info_row.dart';
11 +import 'package:cw_monero/api/structs/pending_transaction.dart';
12 +import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart';
13 +
14 +final transactionsRefreshNative = moneroApi
15 + .lookup<NativeFunction<transactions_refresh>>('transactions_refresh')
16 + .asFunction<TransactionsRefresh>();
17 +
18 +final transactionsCountNative = moneroApi
19 + .lookup<NativeFunction<transactions_count>>('transactions_count')
20 + .asFunction<TransactionsCount>();
21 +
22 +final transactionsGetAllNative = moneroApi
23 + .lookup<NativeFunction<transactions_get_all>>('transactions_get_all')
24 + .asFunction<TransactionsGetAll>();
25 +
26 +final transactionCreateNative = moneroApi
27 + .lookup<NativeFunction<transaction_create>>('transaction_create')
28 + .asFunction<TransactionCreate>();
29 +
30 +final transactionCreateMultDestNative = moneroApi
31 + .lookup<NativeFunction<transaction_create_mult_dest>>('transaction_create_mult_dest')
32 + .asFunction<TransactionCreateMultDest>();
33 +
34 +final transactionCommitNative = moneroApi
35 + .lookup<NativeFunction<transaction_commit>>('transaction_commit')
36 + .asFunction<TransactionCommit>();
37 +
38 +final getTxKeyNative = moneroApi
39 + .lookup<NativeFunction<get_tx_key>>('get_tx_key')
40 + .asFunction<GetTxKey>();
41 +
42 +String getTxKey(String txId) {
43 + final txIdPointer = Utf8.toUtf8(txId);
44 + final keyPointer = getTxKeyNative(txIdPointer);
45 +
46 + free(txIdPointer);
47 +
48 + if (keyPointer != null) {
49 + return convertUTF8ToString(pointer: keyPointer);
50 + }
51 +
52 + return null;
53 +}
54 +
55 +void refreshTransactions() => transactionsRefreshNative();
56 +
57 +int countOfTransactions() => transactionsCountNative();
58 +
59 +List<TransactionInfoRow> getAllTransations() {
60 + final size = transactionsCountNative();
61 + final transactionsPointer = transactionsGetAllNative();
62 + final transactionsAddresses = transactionsPointer.asTypedList(size);
63 +
64 + return transactionsAddresses
65 + .map((addr) => Pointer<TransactionInfoRow>.fromAddress(addr).ref)
66 + .toList();
67 +}
68 +
69 +PendingTransactionDescription createTransactionSync(
70 + {String address,
71 + String paymentId,
72 + String amount,
73 + int priorityRaw,
74 + int accountIndex = 0}) {
75 + final addressPointer = Utf8.toUtf8(address);
76 + final paymentIdPointer = Utf8.toUtf8(paymentId);
77 + final amountPointer = amount != null ? Utf8.toUtf8(amount) : nullptr;
78 + final errorMessagePointer = allocate<Utf8Box>();
79 + final pendingTransactionRawPointer = allocate<PendingTransactionRaw>();
80 + final created = transactionCreateNative(
81 + addressPointer,
82 + paymentIdPointer,
83 + amountPointer,
84 + priorityRaw,
85 + accountIndex,
86 + errorMessagePointer,
87 + pendingTransactionRawPointer) !=
88 + 0;
89 +
90 + free(addressPointer);
91 + free(paymentIdPointer);
92 +
93 + if (amountPointer != nullptr) {
94 + free(amountPointer);
95 + }
96 +
97 + if (!created) {
98 + final message = errorMessagePointer.ref.getValue();
99 + free(errorMessagePointer);
100 + throw CreationTransactionException(message: message);
101 + }
102 +
103 + return PendingTransactionDescription(
104 + amount: pendingTransactionRawPointer.ref.amount,
105 + fee: pendingTransactionRawPointer.ref.fee,
106 + hash: pendingTransactionRawPointer.ref.getHash(),
107 + pointerAddress: pendingTransactionRawPointer.address);
108 +}
109 +
110 +PendingTransactionDescription createTransactionMultDestSync(
111 + {List<MoneroOutput> outputs,
112 + String paymentId,
113 + int priorityRaw,
114 + int accountIndex = 0}) {
115 + final int size = outputs.length;
116 + final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
117 + Utf8.toUtf8(output.address)).toList();
118 + final Pointer<Pointer<Utf8>> addressesPointerPointer = allocate(count: size);
119 + final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
120 + Utf8.toUtf8(output.amount)).toList();
121 + final Pointer<Pointer<Utf8>> amountsPointerPointer = allocate(count: size);
122 +
123 + for (int i = 0; i < size; i++) {
124 + addressesPointerPointer[i] = addressesPointers[i];
125 + amountsPointerPointer[i] = amountsPointers[i];
126 + }
127 +
128 + final paymentIdPointer = Utf8.toUtf8(paymentId);
129 + final errorMessagePointer = allocate<Utf8Box>();
130 + final pendingTransactionRawPointer = allocate<PendingTransactionRaw>();
131 + final created = transactionCreateMultDestNative(
132 + addressesPointerPointer,
133 + paymentIdPointer,
134 + amountsPointerPointer,
135 + size,
136 + priorityRaw,
137 + accountIndex,
138 + errorMessagePointer,
139 + pendingTransactionRawPointer) !=
140 + 0;
141 +
142 + free(addressesPointerPointer);
143 + free(amountsPointerPointer);
144 +
145 + addressesPointers.forEach((element) => free(element));
146 + amountsPointers.forEach((element) => free(element));
147 +
148 + free(paymentIdPointer);
149 +
150 + if (!created) {
151 + final message = errorMessagePointer.ref.getValue();
152 + free(errorMessagePointer);
153 + throw CreationTransactionException(message: message);
154 + }
155 +
156 + return PendingTransactionDescription(
157 + amount: pendingTransactionRawPointer.ref.amount,
158 + fee: pendingTransactionRawPointer.ref.fee,
159 + hash: pendingTransactionRawPointer.ref.getHash(),
160 + pointerAddress: pendingTransactionRawPointer.address);
161 +}
162 +
163 +void commitTransactionFromPointerAddress({int address}) => commitTransaction(
164 + transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
165 +
166 +void commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
167 + final errorMessagePointer = allocate<Utf8Box>();
168 + final isCommited =
169 + transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
170 +
171 + if (!isCommited) {
172 + final message = errorMessagePointer.ref.getValue();
173 + free(errorMessagePointer);
174 + throw CreationTransactionException(message: message);
175 + }
176 +}
177 +
178 +PendingTransactionDescription _createTransactionSync(Map args) {
179 + final address = args['address'] as String;
180 + final paymentId = args['paymentId'] as String;
181 + final amount = args['amount'] as String;
182 + final priorityRaw = args['priorityRaw'] as int;
183 + final accountIndex = args['accountIndex'] as int;
184 +
185 + return createTransactionSync(
186 + address: address,
187 + paymentId: paymentId,
188 + amount: amount,
189 + priorityRaw: priorityRaw,
190 + accountIndex: accountIndex);
191 +}
192 +
193 +PendingTransactionDescription _createTransactionMultDestSync(Map args) {
194 + final outputs = args['outputs'] as List<MoneroOutput>;
195 + final paymentId = args['paymentId'] as String;
196 + final priorityRaw = args['priorityRaw'] as int;
197 + final accountIndex = args['accountIndex'] as int;
198 +
199 + return createTransactionMultDestSync(
200 + outputs: outputs,
201 + paymentId: paymentId,
202 + priorityRaw: priorityRaw,
203 + accountIndex: accountIndex);
204 +}
205 +
206 +Future<PendingTransactionDescription> createTransaction(
207 + {String address,
208 + String paymentId = '',
209 + String amount,
210 + int priorityRaw,
211 + int accountIndex = 0}) =>
212 + compute(_createTransactionSync, {
213 + 'address': address,
214 + 'paymentId': paymentId,
215 + 'amount': amount,
216 + 'priorityRaw': priorityRaw,
217 + 'accountIndex': accountIndex
218 + });
219 +
220 +Future<PendingTransactionDescription> createTransactionMultDest(
221 + {List<MoneroOutput> outputs,
222 + String paymentId = '',
223 + int priorityRaw,
224 + int accountIndex = 0}) =>
225 + compute(_createTransactionMultDestSync, {
226 + 'outputs': outputs,
227 + 'paymentId': paymentId,
228 + 'priorityRaw': priorityRaw,
229 + 'accountIndex': accountIndex
230 + });
cw_monero/lib/api/types.dart new
+120
@@ -0,0 +1,120 @@
1 +import 'dart:ffi';
2 +import 'package:cw_monero/api/structs/pending_transaction.dart';
3 +import 'package:cw_monero/api/structs/ut8_box.dart';
4 +import 'package:ffi/ffi.dart';
5 +
6 +typedef CreateWallet = int Function(
7 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, Pointer<Utf8>);
8 +
9 +typedef RestoreWalletFromSeed = int Function(
10 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
11 +
12 +typedef RestoreWalletFromKeys = int Function(Pointer<Utf8>, Pointer<Utf8>,
13 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
14 +
15 +typedef IsWalletExist = int Function(Pointer<Utf8>);
16 +
17 +typedef LoadWallet = int Function(Pointer<Utf8>, Pointer<Utf8>, int);
18 +
19 +typedef ErrorString = Pointer<Utf8> Function();
20 +
21 +typedef GetFilename = Pointer<Utf8> Function();
22 +
23 +typedef GetSeed = Pointer<Utf8> Function();
24 +
25 +typedef GetAddress = Pointer<Utf8> Function(int, int);
26 +
27 +typedef GetFullBalance = int Function(int);
28 +
29 +typedef GetUnlockedBalance = int Function(int);
30 +
31 +typedef GetCurrentHeight = int Function();
32 +
33 +typedef GetNodeHeight = int Function();
34 +
35 +typedef IsConnected = int Function();
36 +
37 +typedef SetupNode = int Function(
38 + Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
39 +
40 +typedef StartRefresh = void Function();
41 +
42 +typedef ConnectToNode = int Function();
43 +
44 +typedef SetRefreshFromBlockHeight = void Function(int);
45 +
46 +typedef SetRecoveringFromSeed = void Function(int);
47 +
48 +typedef Store = void Function(Pointer<Utf8>);
49 +
50 +typedef SetListener = void Function();
51 +
52 +typedef GetSyncingHeight = int Function();
53 +
54 +typedef IsNeededToRefresh = int Function();
55 +
56 +typedef IsNewTransactionExist = int Function();
57 +
58 +typedef SubaddressSize = int Function();
59 +
60 +typedef SubaddressRefresh = void Function(int);
61 +
62 +typedef SubaddressGetAll = Pointer<Int64> Function();
63 +
64 +typedef SubaddressAddNew = void Function(int accountIndex, Pointer<Utf8> label);
65 +
66 +typedef SubaddressSetLabel = void Function(
67 + int accountIndex, int addressIndex, Pointer<Utf8> label);
68 +
69 +typedef AccountSize = int Function();
70 +
71 +typedef AccountRefresh = void Function();
72 +
73 +typedef AccountGetAll = Pointer<Int64> Function();
74 +
75 +typedef AccountAddNew = void Function(Pointer<Utf8> label);
76 +
77 +typedef AccountSetLabel = void Function(int accountIndex, Pointer<Utf8> label);
78 +
79 +typedef TransactionsRefresh = void Function();
80 +
81 +typedef GetTxKey = Pointer<Utf8> Function(Pointer<Utf8> txId);
82 +
83 +typedef TransactionsCount = int Function();
84 +
85 +typedef TransactionsGetAll = Pointer<Int64> Function();
86 +
87 +typedef TransactionCreate = int Function(
88 + Pointer<Utf8> address,
89 + Pointer<Utf8> paymentId,
90 + Pointer<Utf8> amount,
91 + int priorityRaw,
92 + int subaddrAccount,
93 + Pointer<Utf8Box> error,
94 + Pointer<PendingTransactionRaw> pendingTransaction);
95 +
96 +typedef TransactionCreateMultDest = int Function(
97 + Pointer<Pointer<Utf8>> addresses,
98 + Pointer<Utf8> paymentId,
99 + Pointer<Pointer<Utf8>> amounts,
100 + int size,
101 + int priorityRaw,
102 + int subaddrAccount,
103 + Pointer<Utf8Box> error,
104 + Pointer<PendingTransactionRaw> pendingTransaction);
105 +
106 +typedef TransactionCommit = int Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
107 +
108 +typedef SecretViewKey = Pointer<Utf8> Function();
109 +
110 +typedef PublicViewKey = Pointer<Utf8> Function();
111 +
112 +typedef SecretSpendKey = Pointer<Utf8> Function();
113 +
114 +typedef PublicSpendKey = Pointer<Utf8> Function();
115 +
116 +typedef CloseCurrentWallet = void Function();
117 +
118 +typedef OnStartup = void Function();
119 +
120 +typedef RescanBlockchainAsync = void Function();
\ No newline at end of file
cw_monero/lib/api/wallet.dart new
+329
@@ -0,0 +1,329 @@
1 +import 'dart:async';
2 +import 'dart:ffi';
3 +import 'package:ffi/ffi.dart';
4 +import 'package:cw_monero/api/convert_utf8_to_string.dart';
5 +import 'package:cw_monero/api/signatures.dart';
6 +import 'package:cw_monero/api/types.dart';
7 +import 'package:cw_monero/api/monero_api.dart';
8 +import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
9 +import 'package:flutter/foundation.dart';
10 +import 'package:flutter/services.dart';
11 +
12 +int _boolToInt(bool value) => value ? 1 : 0;
13 +
14 +final getFileNameNative = moneroApi
15 + .lookup<NativeFunction<get_filename>>('get_filename')
16 + .asFunction<GetFilename>();
17 +
18 +final getSeedNative =
19 + moneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
20 +
21 +final getAddressNative = moneroApi
22 + .lookup<NativeFunction<get_address>>('get_address')
23 + .asFunction<GetAddress>();
24 +
25 +final getFullBalanceNative = moneroApi
26 + .lookup<NativeFunction<get_full_balanace>>('get_full_balance')
27 + .asFunction<GetFullBalance>();
28 +
29 +final getUnlockedBalanceNative = moneroApi
30 + .lookup<NativeFunction<get_unlocked_balanace>>('get_unlocked_balance')
31 + .asFunction<GetUnlockedBalance>();
32 +
33 +final getCurrentHeightNative = moneroApi
34 + .lookup<NativeFunction<get_current_height>>('get_current_height')
35 + .asFunction<GetCurrentHeight>();
36 +
37 +final getNodeHeightNative = moneroApi
38 + .lookup<NativeFunction<get_node_height>>('get_node_height')
39 + .asFunction<GetNodeHeight>();
40 +
41 +final isConnectedNative = moneroApi
42 + .lookup<NativeFunction<is_connected>>('is_connected')
43 + .asFunction<IsConnected>();
44 +
45 +final setupNodeNative = moneroApi
46 + .lookup<NativeFunction<setup_node>>('setup_node')
47 + .asFunction<SetupNode>();
48 +
49 +final startRefreshNative = moneroApi
50 + .lookup<NativeFunction<start_refresh>>('start_refresh')
51 + .asFunction<StartRefresh>();
52 +
53 +final connecToNodeNative = moneroApi
54 + .lookup<NativeFunction<connect_to_node>>('connect_to_node')
55 + .asFunction<ConnectToNode>();
56 +
57 +final setRefreshFromBlockHeightNative = moneroApi
58 + .lookup<NativeFunction<set_refresh_from_block_height>>(
59 + 'set_refresh_from_block_height')
60 + .asFunction<SetRefreshFromBlockHeight>();
61 +
62 +final setRecoveringFromSeedNative = moneroApi
63 + .lookup<NativeFunction<set_recovering_from_seed>>(
64 + 'set_recovering_from_seed')
65 + .asFunction<SetRecoveringFromSeed>();
66 +
67 +final storeNative =
68 + moneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
69 +
70 +final setListenerNative = moneroApi
71 + .lookup<NativeFunction<set_listener>>('set_listener')
72 + .asFunction<SetListener>();
73 +
74 +final getSyncingHeightNative = moneroApi
75 + .lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
76 + .asFunction<GetSyncingHeight>();
77 +
78 +final isNeededToRefreshNative = moneroApi
79 + .lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
80 + .asFunction<IsNeededToRefresh>();
81 +
82 +final isNewTransactionExistNative = moneroApi
83 + .lookup<NativeFunction<is_new_transaction_exist>>(
84 + 'is_new_transaction_exist')
85 + .asFunction<IsNewTransactionExist>();
86 +
87 +final getSecretViewKeyNative = moneroApi
88 + .lookup<NativeFunction<secret_view_key>>('secret_view_key')
89 + .asFunction<SecretViewKey>();
90 +
91 +final getPublicViewKeyNative = moneroApi
92 + .lookup<NativeFunction<public_view_key>>('public_view_key')
93 + .asFunction<PublicViewKey>();
94 +
95 +final getSecretSpendKeyNative = moneroApi
96 + .lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
97 + .asFunction<SecretSpendKey>();
98 +
99 +final getPublicSpendKeyNative = moneroApi
100 + .lookup<NativeFunction<secret_view_key>>('public_spend_key')
101 + .asFunction<PublicSpendKey>();
102 +
103 +final closeCurrentWalletNative = moneroApi
104 + .lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
105 + .asFunction<CloseCurrentWallet>();
106 +
107 +final onStartupNative = moneroApi
108 + .lookup<NativeFunction<on_startup>>('on_startup')
109 + .asFunction<OnStartup>();
110 +
111 +final rescanBlockchainAsyncNative = moneroApi
112 + .lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
113 + .asFunction<RescanBlockchainAsync>();
114 +
115 +int getSyncingHeight() => getSyncingHeightNative();
116 +
117 +bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
118 +
119 +bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
120 +
121 +String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
122 +
123 +String getSeed() => convertUTF8ToString(pointer: getSeedNative());
124 +
125 +String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
126 + convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
127 +
128 +int getFullBalance({int accountIndex = 0}) =>
129 + getFullBalanceNative(accountIndex);
130 +
131 +int getUnlockedBalance({int accountIndex = 0}) =>
132 + getUnlockedBalanceNative(accountIndex);
133 +
134 +int getCurrentHeight() => getCurrentHeightNative();
135 +
136 +int getNodeHeightSync() => getNodeHeightNative();
137 +
138 +bool isConnectedSync() => isConnectedNative() != 0;
139 +
140 +bool setupNodeSync(
141 + {String address,
142 + String login,
143 + String password,
144 + bool useSSL = false,
145 + bool isLightWallet = false}) {
146 + final addressPointer = Utf8.toUtf8(address);
147 + Pointer<Utf8> loginPointer;
148 + Pointer<Utf8> passwordPointer;
149 +
150 + if (login != null) {
151 + loginPointer = Utf8.toUtf8(login);
152 + }
153 +
154 + if (password != null) {
155 + passwordPointer = Utf8.toUtf8(password);
156 + }
157 +
158 + final errorMessagePointer = allocate<Utf8>();
159 + final isSetupNode = setupNodeNative(
160 + addressPointer,
161 + loginPointer,
162 + passwordPointer,
163 + _boolToInt(useSSL),
164 + _boolToInt(isLightWallet),
165 + errorMessagePointer) !=
166 + 0;
167 +
168 + free(addressPointer);
169 + free(loginPointer);
170 + free(passwordPointer);
171 +
172 + if (!isSetupNode) {
173 + throw SetupWalletException(
174 + message: convertUTF8ToString(pointer: errorMessagePointer));
175 + }
176 +
177 + return isSetupNode;
178 +}
179 +
180 +void startRefreshSync() => startRefreshNative();
181 +
182 +Future<bool> connectToNode() async => connecToNodeNative() != 0;
183 +
184 +void setRefreshFromBlockHeight({int height}) =>
185 + setRefreshFromBlockHeightNative(height);
186 +
187 +void setRecoveringFromSeed({bool isRecovery}) =>
188 + setRecoveringFromSeedNative(_boolToInt(isRecovery));
189 +
190 +void storeSync() {
191 + final pathPointer = Utf8.toUtf8('');
192 + storeNative(pathPointer);
193 + free(pathPointer);
194 +}
195 +
196 +void closeCurrentWallet() => closeCurrentWalletNative();
197 +
198 +String getSecretViewKey() =>
199 + convertUTF8ToString(pointer: getSecretViewKeyNative());
200 +
201 +String getPublicViewKey() =>
202 + convertUTF8ToString(pointer: getPublicViewKeyNative());
203 +
204 +String getSecretSpendKey() =>
205 + convertUTF8ToString(pointer: getSecretSpendKeyNative());
206 +
207 +String getPublicSpendKey() =>
208 + convertUTF8ToString(pointer: getPublicSpendKeyNative());
209 +
210 +class SyncListener {
211 + SyncListener(this.onNewBlock, this.onNewTransaction) {
212 + _cachedBlockchainHeight = 0;
213 + _lastKnownBlockHeight = 0;
214 + _initialSyncHeight = 0;
215 + }
216 +
217 + void Function(int, int, double) onNewBlock;
218 + void Function() onNewTransaction;
219 +
220 + Timer _updateSyncInfoTimer;
221 + int _cachedBlockchainHeight;
222 + int _lastKnownBlockHeight;
223 + int _initialSyncHeight;
224 +
225 + Future<int> getNodeHeightOrUpdate(int baseHeight) async {
226 + if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
227 + _cachedBlockchainHeight = await getNodeHeight();
228 + }
229 +
230 + return _cachedBlockchainHeight;
231 + }
232 +
233 + void start() {
234 + _cachedBlockchainHeight = 0;
235 + _lastKnownBlockHeight = 0;
236 + _initialSyncHeight = 0;
237 + _updateSyncInfoTimer ??=
238 + Timer.periodic(Duration(milliseconds: 1200), (_) async {
239 + if (isNewTransactionExist()) {
240 + onNewTransaction?.call();
241 + }
242 +
243 + var syncHeight = getSyncingHeight();
244 +
245 + if (syncHeight <= 0) {
246 + syncHeight = getCurrentHeight();
247 + }
248 +
249 + if (_initialSyncHeight <= 0) {
250 + _initialSyncHeight = syncHeight;
251 + }
252 +
253 + final bchHeight = await getNodeHeightOrUpdate(syncHeight);
254 +
255 + if (_lastKnownBlockHeight == syncHeight || syncHeight == null) {
256 + return;
257 + }
258 +
259 + _lastKnownBlockHeight = syncHeight;
260 + final track = bchHeight - _initialSyncHeight;
261 + final diff = track - (bchHeight - syncHeight);
262 + final ptc = diff <= 0 ? 0.0 : diff / track;
263 + final left = bchHeight - syncHeight;
264 +
265 + if (syncHeight < 0 || left < 0) {
266 + return;
267 + }
268 +
269 + // 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
270 + onNewBlock?.call(syncHeight, left, ptc);
271 + });
272 + }
273 +
274 + void stop() => _updateSyncInfoTimer?.cancel();
275 +}
276 +
277 +SyncListener setListeners(void Function(int, int, double) onNewBlock,
278 + void Function() onNewTransaction) {
279 + final listener = SyncListener(onNewBlock, onNewTransaction);
280 + setListenerNative();
281 + return listener;
282 +}
283 +
284 +void onStartup() => onStartupNative();
285 +
286 +void _storeSync(Object _) => storeSync();
287 +
288 +bool _setupNodeSync(Map args) {
289 + final address = args['address'] as String;
290 + final login = (args['login'] ?? '') as String;
291 + final password = (args['password'] ?? '') as String;
292 + final useSSL = args['useSSL'] as bool;
293 + final isLightWallet = args['isLightWallet'] as bool;
294 +
295 + return setupNodeSync(
296 + address: address,
297 + login: login,
298 + password: password,
299 + useSSL: useSSL,
300 + isLightWallet: isLightWallet);
301 +}
302 +
303 +bool _isConnected(Object _) => isConnectedSync();
304 +
305 +int _getNodeHeight(Object _) => getNodeHeightSync();
306 +
307 +void startRefresh() => startRefreshSync();
308 +
309 +Future setupNode(
310 + {String address,
311 + String login,
312 + String password,
313 + bool useSSL = false,
314 + bool isLightWallet = false}) =>
315 + compute<Map<String, Object>, void>(_setupNodeSync, {
316 + 'address': address,
317 + 'login': login,
318 + 'password': password,
319 + 'useSSL': useSSL,
320 + 'isLightWallet': isLightWallet
321 + });
322 +
323 +Future store() => compute<int, void>(_storeSync, 0);
324 +
325 +Future<bool> isConnected() => compute(_isConnected, 0);
326 +
327 +Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
328 +
329 +void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
cw_monero/lib/api/wallet_manager.dart new
+248
@@ -0,0 +1,248 @@
1 +import 'dart:ffi';
2 +import 'package:ffi/ffi.dart';
3 +import 'package:flutter/foundation.dart';
4 +import 'package:cw_monero/api/convert_utf8_to_string.dart';
5 +import 'package:cw_monero/api/signatures.dart';
6 +import 'package:cw_monero/api/types.dart';
7 +import 'package:cw_monero/api/monero_api.dart';
8 +import 'package:cw_monero/api/wallet.dart';
9 +import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
10 +import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart';
11 +import 'package:cw_monero/api/exceptions/wallet_restore_from_keys_exception.dart';
12 +import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart';
13 +
14 +final createWalletNative = moneroApi
15 + .lookup<NativeFunction<create_wallet>>('create_wallet')
16 + .asFunction<CreateWallet>();
17 +
18 +final restoreWalletFromSeedNative = moneroApi
19 + .lookup<NativeFunction<restore_wallet_from_seed>>(
20 + 'restore_wallet_from_seed')
21 + .asFunction<RestoreWalletFromSeed>();
22 +
23 +final restoreWalletFromKeysNative = moneroApi
24 + .lookup<NativeFunction<restore_wallet_from_keys>>(
25 + 'restore_wallet_from_keys')
26 + .asFunction<RestoreWalletFromKeys>();
27 +
28 +final isWalletExistNative = moneroApi
29 + .lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
30 + .asFunction<IsWalletExist>();
31 +
32 +final loadWalletNative = moneroApi
33 + .lookup<NativeFunction<load_wallet>>('load_wallet')
34 + .asFunction<LoadWallet>();
35 +
36 +final errorStringNative = moneroApi
37 + .lookup<NativeFunction<error_string>>('error_string')
38 + .asFunction<ErrorString>();
39 +
40 +void createWalletSync(
41 + {String path, String password, String language, int nettype = 0}) {
42 + final pathPointer = Utf8.toUtf8(path);
43 + final passwordPointer = Utf8.toUtf8(password);
44 + final languagePointer = Utf8.toUtf8(language);
45 + final errorMessagePointer = allocate<Utf8>();
46 + final isWalletCreated = createWalletNative(pathPointer, passwordPointer,
47 + languagePointer, nettype, errorMessagePointer) !=
48 + 0;
49 +
50 + free(pathPointer);
51 + free(passwordPointer);
52 + free(languagePointer);
53 +
54 + if (!isWalletCreated) {
55 + throw WalletCreationException(
56 + message: convertUTF8ToString(pointer: errorMessagePointer));
57 + }
58 +
59 + // setupNodeSync(address: "node.moneroworld.com:18089");
60 +}
61 +
62 +bool isWalletExistSync({String path}) {
63 + final pathPointer = Utf8.toUtf8(path);
64 + final isExist = isWalletExistNative(pathPointer) != 0;
65 +
66 + free(pathPointer);
67 +
68 + return isExist;
69 +}
70 +
71 +void restoreWalletFromSeedSync(
72 + {String path,
73 + String password,
74 + String seed,
75 + int nettype = 0,
76 + int restoreHeight = 0}) {
77 + final pathPointer = Utf8.toUtf8(path);
78 + final passwordPointer = Utf8.toUtf8(password);
79 + final seedPointer = Utf8.toUtf8(seed);
80 + final errorMessagePointer = allocate<Utf8>();
81 + final isWalletRestored = restoreWalletFromSeedNative(
82 + pathPointer,
83 + passwordPointer,
84 + seedPointer,
85 + nettype,
86 + restoreHeight,
87 + errorMessagePointer) !=
88 + 0;
89 +
90 + free(pathPointer);
91 + free(passwordPointer);
92 + free(seedPointer);
93 +
94 + if (!isWalletRestored) {
95 + throw WalletRestoreFromSeedException(
96 + message: convertUTF8ToString(pointer: errorMessagePointer));
97 + }
98 +}
99 +
100 +void restoreWalletFromKeysSync(
101 + {String path,
102 + String password,
103 + String language,
104 + String address,
105 + String viewKey,
106 + String spendKey,
107 + int nettype = 0,
108 + int restoreHeight = 0}) {
109 + final pathPointer = Utf8.toUtf8(path);
110 + final passwordPointer = Utf8.toUtf8(password);
111 + final languagePointer = Utf8.toUtf8(language);
112 + final addressPointer = Utf8.toUtf8(address);
113 + final viewKeyPointer = Utf8.toUtf8(viewKey);
114 + final spendKeyPointer = Utf8.toUtf8(spendKey);
115 + final errorMessagePointer = allocate<Utf8>();
116 + final isWalletRestored = restoreWalletFromKeysNative(
117 + pathPointer,
118 + passwordPointer,
119 + languagePointer,
120 + addressPointer,
121 + viewKeyPointer,
122 + spendKeyPointer,
123 + nettype,
124 + restoreHeight,
125 + errorMessagePointer) !=
126 + 0;
127 +
128 + free(pathPointer);
129 + free(passwordPointer);
130 + free(languagePointer);
131 + free(addressPointer);
132 + free(viewKeyPointer);
133 + free(spendKeyPointer);
134 +
135 + if (!isWalletRestored) {
136 + throw WalletRestoreFromKeysException(
137 + message: convertUTF8ToString(pointer: errorMessagePointer));
138 + }
139 +}
140 +
141 +void loadWallet({String path, String password, int nettype = 0}) {
142 + final pathPointer = Utf8.toUtf8(path);
143 + final passwordPointer = Utf8.toUtf8(password);
144 + final loaded = loadWalletNative(pathPointer, passwordPointer, nettype) != 0;
145 + free(pathPointer);
146 + free(passwordPointer);
147 +
148 + if (!loaded) {
149 + throw WalletOpeningException(
150 + message: convertUTF8ToString(pointer: errorStringNative()));
151 + }
152 +}
153 +
154 +void _createWallet(Map<String, dynamic> args) {
155 + final path = args['path'] as String;
156 + final password = args['password'] as String;
157 + final language = args['language'] as String;
158 +
159 + createWalletSync(path: path, password: password, language: language);
160 +}
161 +
162 +void _restoreFromSeed(Map<String, dynamic> args) {
163 + final path = args['path'] as String;
164 + final password = args['password'] as String;
165 + final seed = args['seed'] as String;
166 + final restoreHeight = args['restoreHeight'] as int;
167 +
168 + restoreWalletFromSeedSync(
169 + path: path, password: password, seed: seed, restoreHeight: restoreHeight);
170 +}
171 +
172 +void _restoreFromKeys(Map<String, dynamic> args) {
173 + final path = args['path'] as String;
174 + final password = args['password'] as String;
175 + final language = args['language'] as String;
176 + final restoreHeight = args['restoreHeight'] as int;
177 + final address = args['address'] as String;
178 + final viewKey = args['viewKey'] as String;
179 + final spendKey = args['spendKey'] as String;
180 +
181 + restoreWalletFromKeysSync(
182 + path: path,
183 + password: password,
184 + language: language,
185 + restoreHeight: restoreHeight,
186 + address: address,
187 + viewKey: viewKey,
188 + spendKey: spendKey);
189 +}
190 +
191 +Future<void> _openWallet(Map<String, String> args) async =>
192 + loadWallet(path: args['path'], password: args['password']);
193 +
194 +bool _isWalletExist(String path) => isWalletExistSync(path: path);
195 +
196 +void openWallet({String path, String password, int nettype = 0}) async =>
197 + loadWallet(path: path, password: password, nettype: nettype);
198 +
199 +Future<void> openWalletAsync(Map<String, String> args) async =>
200 + compute(_openWallet, args);
201 +
202 +Future<void> createWallet(
203 + {String path,
204 + String password,
205 + String language,
206 + int nettype = 0}) async =>
207 + compute(_createWallet, {
208 + 'path': path,
209 + 'password': password,
210 + 'language': language,
211 + 'nettype': nettype
212 + });
213 +
214 +Future restoreFromSeed(
215 + {String path,
216 + String password,
217 + String seed,
218 + int nettype = 0,
219 + int restoreHeight = 0}) async =>
220 + compute<Map<String, Object>, void>(_restoreFromSeed, {
221 + 'path': path,
222 + 'password': password,
223 + 'seed': seed,
224 + 'nettype': nettype,
225 + 'restoreHeight': restoreHeight
226 + });
227 +
228 +Future restoreFromKeys(
229 + {String path,
230 + String password,
231 + String language,
232 + String address,
233 + String viewKey,
234 + String spendKey,
235 + int nettype = 0,
236 + int restoreHeight = 0}) async =>
237 + compute<Map<String, Object>, void>(_restoreFromKeys, {
238 + 'path': path,
239 + 'password': password,
240 + 'language': language,
241 + 'address': address,
242 + 'viewKey': viewKey,
243 + 'spendKey': spendKey,
244 + 'nettype': nettype,
245 + 'restoreHeight': restoreHeight
246 + });
247 +
248 +Future<bool> isWalletExist({String path}) => compute(_isWalletExist, path);
cw_monero/lib/get_height_by_date.dart new
+120
@@ -0,0 +1,120 @@
1 +import 'package:intl/intl.dart';
2 +
3 +// FIXME: Hardcoded values; Works only for monero
4 +
5 +final dateFormat = DateFormat('yyyy-MM');
6 +final dates = {
7 + "2014-5": 18844,
8 + "2014-6": 65406,
9 + "2014-7": 108882,
10 + "2014-8": 153594,
11 + "2014-9": 198072,
12 + "2014-10": 241088,
13 + "2014-11": 285305,
14 + "2014-12": 328069,
15 + "2015-1": 372369,
16 + "2015-2": 416505,
17 + "2015-3": 456631,
18 + "2015-4": 501084,
19 + "2015-5": 543973,
20 + "2015-6": 588326,
21 + "2015-7": 631187,
22 + "2015-8": 675484,
23 + "2015-9": 719725,
24 + "2015-10": 762463,
25 + "2015-11": 806528,
26 + "2015-12": 849041,
27 + "2016-1": 892866,
28 + "2016-2": 936736,
29 + "2016-3": 977691,
30 + "2016-4": 1015848,
31 + "2016-5": 1037417,
32 + "2016-6": 1059651,
33 + "2016-7": 1081269,
34 + "2016-8": 1103630,
35 + "2016-9": 1125983,
36 + "2016-10": 1147617,
37 + "2016-11": 1169779,
38 + "2016-12": 1191402,
39 + "2017-1": 1213861,
40 + "2017-2": 1236197,
41 + "2017-3": 1256358,
42 + "2017-4": 1278622,
43 + "2017-5": 1300239,
44 + "2017-6": 1322564,
45 + "2017-7": 1344225,
46 + "2017-8": 1366664,
47 + "2017-9": 1389113,
48 + "2017-10": 1410738,
49 + "2017-11": 1433039,
50 + "2017-12": 1454639,
51 + "2018-1": 1477201,
52 + "2018-2": 1499599,
53 + "2018-3": 1519796,
54 + "2018-4": 1542067,
55 + "2018-5": 1562861,
56 + "2018-6": 1585135,
57 + "2018-7": 1606715,
58 + "2018-8": 1629017,
59 + "2018-9": 1651347,
60 + "2018-10": 1673031,
61 + "2018-11": 1695128,
62 + "2018-12": 1716687,
63 + "2019-1": 1738923,
64 + "2019-2": 1761435,
65 + "2019-3": 1781681,
66 + "2019-4": 1803081,
67 + "2019-5": 1824671,
68 + "2019-6": 1847005,
69 + "2019-7": 1868590,
70 + "2019-8": 1890552,
71 + "2019-9": 1912212,
72 + "2019-10": 1932200,
73 + "2019-11": 1957040,
74 + "2019-12": 1978090,
75 + "2020-1": 2001290,
76 + "2020-2": 2022688,
77 + "2020-3": 2043987,
78 + "2020-4": 2066536,
79 + "2020-5": 2090797,
80 + "2020-6": 2111633,
81 + "2020-7": 2131433,
82 + "2020-8": 2153983,
83 + "2020-9": 2176466,
84 + "2020-10": 2198453,
85 + "2020-11": 2220000
86 +};
87 +
88 +int getHeigthByDate({DateTime date}) {
89 + final raw = '${date.year}' + '-' + '${date.month}';
90 + final lastHeight = dates.values.last;
91 + int startHeight;
92 + int endHeight;
93 + int height = 0;
94 +
95 + try {
96 + if ((dates[raw] == null)||(dates[raw] == lastHeight)) {
97 + startHeight = dates.values.toList()[dates.length - 2];
98 + endHeight = dates.values.toList()[dates.length - 1];
99 + final heightPerDay = (endHeight - startHeight) / 31;
100 + final endDateRaw = dates.keys.toList()[dates.length - 1].split('-');
101 + final endYear = int.parse(endDateRaw[0]);
102 + final endMonth = int.parse(endDateRaw[1]);
103 + final endDate = DateTime(endYear, endMonth);
104 + final differenceInDays = date.difference(endDate).inDays;
105 + final daysHeight = (differenceInDays * heightPerDay).round();
106 + height = endHeight + daysHeight;
107 + } else {
108 + startHeight = dates[raw];
109 + final index = dates.values.toList().indexOf(startHeight);
110 + endHeight = dates.values.toList()[index + 1];
111 + final heightPerDay = ((endHeight - startHeight) / 31).round();
112 + final daysHeight = (date.day - 1) * heightPerDay;
113 + height = startHeight + daysHeight - heightPerDay;
114 + }
115 + } catch (e) {
116 + print(e.toString());
117 + }
118 +
119 + return height;
120 +}
cw_monero/lib/mnemonics/chinese_simplified.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class ChineseSimplifiedMnemonics {
2 + static const words = [
3 + "的",
4 + "一",
5 + "是",
6 + "在",
7 + "不",
8 + "了",
9 + "有",
10 + "和",
11 + "人",
12 + "这",
13 + "中",
14 + "大",
15 + "为",
16 + "上",
17 + "个",
18 + "国",
19 + "我",
20 + "以",
21 + "要",
22 + "他",
23 + "时",
24 + "来",
25 + "用",
26 + "们",
27 + "生",
28 + "到",
29 + "作",
30 + "地",
31 + "于",
32 + "出",
33 + "就",
34 + "分",
35 + "对",
36 + "成",
37 + "会",
38 + "可",
39 + "主",
40 + "发",
41 + "年",
42 + "动",
43 + "同",
44 + "工",
45 + "也",
46 + "能",
47 + "下",
48 + "过",
49 + "子",
50 + "说",
51 + "产",
52 + "种",
53 + "面",
54 + "而",
55 + "方",
56 + "后",
57 + "多",
58 + "定",
59 + "行",
60 + "学",
61 + "法",
62 + "所",
63 + "民",
64 + "得",
65 + "经",
66 + "十",
67 + "三",
68 + "之",
69 + "进",
70 + "着",
71 + "等",
72 + "部",
73 + "度",
74 + "家",
75 + "电",
76 + "力",
77 + "里",
78 + "如",
79 + "水",
80 + "化",
81 + "高",
82 + "自",
83 + "二",
84 + "理",
85 + "起",
86 + "小",
87 + "物",
88 + "现",
89 + "实",
90 + "加",
91 + "量",
92 + "都",
93 + "两",
94 + "体",
95 + "制",
96 + "机",
97 + "当",
98 + "使",
99 + "点",
100 + "从",
101 + "业",
102 + "本",
103 + "去",
104 + "把",
105 + "性",
106 + "好",
107 + "应",
108 + "开",
109 + "它",
110 + "合",
111 + "还",
112 + "因",
113 + "由",
114 + "其",
115 + "些",
116 + "然",
117 + "前",
118 + "外",
119 + "天",
120 + "政",
121 + "四",
122 + "日",
123 + "那",
124 + "社",
125 + "义",
126 + "事",
127 + "平",
128 + "形",
129 + "相",
130 + "全",
131 + "表",
132 + "间",
133 + "样",
134 + "与",
135 + "关",
136 + "各",
137 + "重",
138 + "新",
139 + "线",
140 + "内",
141 + "数",
142 + "正",
143 + "心",
144 + "反",
145 + "你",
146 + "明",
147 + "看",
148 + "原",
149 + "又",
150 + "么",
151 + "利",
152 + "比",
153 + "或",
154 + "但",
155 + "质",
156 + "气",
157 + "第",
158 + "向",
159 + "道",
160 + "命",
161 + "此",
162 + "变",
163 + "条",
164 + "只",
165 + "没",
166 + "结",
167 + "解",
168 + "问",
169 + "意",
170 + "建",
171 + "月",
172 + "公",
173 + "无",
174 + "系",
175 + "军",
176 + "很",
177 + "情",
178 + "者",
179 + "最",
180 + "立",
181 + "代",
182 + "想",
183 + "已",
184 + "通",
185 + "并",
186 + "提",
187 + "直",
188 + "题",
189 + "党",
190 + "程",
191 + "展",
192 + "五",
193 + "果",
194 + "料",
195 + "象",
196 + "员",
197 + "革",
198 + "位",
199 + "入",
200 + "常",
201 + "文",
202 + "总",
203 + "次",
204 + "品",
205 + "式",
206 + "活",
207 + "设",
208 + "及",
209 + "管",
210 + "特",
211 + "件",
212 + "长",
213 + "求",
214 + "老",
215 + "头",
216 + "基",
217 + "资",
218 + "边",
219 + "流",
220 + "路",
221 + "级",
222 + "少",
223 + "图",
224 + "山",
225 + "统",
226 + "接",
227 + "知",
228 + "较",
229 + "将",
230 + "组",
231 + "见",
232 + "计",
233 + "别",
234 + "她",
235 + "手",
236 + "角",
237 + "期",
238 + "根",
239 + "论",
240 + "运",
241 + "农",
242 + "指",
243 + "几",
244 + "九",
245 + "区",
246 + "强",
247 + "放",
248 + "决",
249 + "西",
250 + "被",
251 + "干",
252 + "做",
253 + "必",
254 + "战",
255 + "先",
256 + "回",
257 + "则",
258 + "任",
259 + "取",
260 + "据",
261 + "处",
262 + "队",
263 + "南",
264 + "给",
265 + "色",
266 + "光",
267 + "门",
268 + "即",
269 + "保",
270 + "治",
271 + "北",
272 + "造",
273 + "百",
274 + "规",
275 + "热",
276 + "领",
277 + "七",
278 + "海",
279 + "口",
280 + "东",
281 + "导",
282 + "器",
283 + "压",
284 + "志",
285 + "世",
286 + "金",
287 + "增",
288 + "争",
289 + "济",
290 + "阶",
291 + "油",
292 + "思",
293 + "术",
294 + "极",
295 + "交",
296 + "受",
297 + "联",
298 + "什",
299 + "认",
300 + "六",
301 + "共",
302 + "权",
303 + "收",
304 + "证",
305 + "改",
306 + "清",
307 + "美",
308 + "再",
309 + "采",
310 + "转",
311 + "更",
312 + "单",
313 + "风",
314 + "切",
315 + "打",
316 + "白",
317 + "教",
318 + "速",
319 + "花",
320 + "带",
321 + "安",
322 + "场",
323 + "身",
324 + "车",
325 + "例",
326 + "真",
327 + "务",
328 + "具",
329 + "万",
330 + "每",
331 + "目",
332 + "至",
333 + "达",
334 + "走",
335 + "积",
336 + "示",
337 + "议",
338 + "声",
339 + "报",
340 + "斗",
341 + "完",
342 + "类",
343 + "八",
344 + "离",
345 + "华",
346 + "名",
347 + "确",
348 + "才",
349 + "科",
350 + "张",
351 + "信",
352 + "马",
353 + "节",
354 + "话",
355 + "米",
356 + "整",
357 + "空",
358 + "元",
359 + "况",
360 + "今",
361 + "集",
362 + "温",
363 + "传",
364 + "土",
365 + "许",
366 + "步",
367 + "群",
368 + "广",
369 + "石",
370 + "记",
371 + "需",
372 + "段",
373 + "研",
374 + "界",
375 + "拉",
376 + "林",
377 + "律",
378 + "叫",
379 + "且",
380 + "究",
381 + "观",
382 + "越",
383 + "织",
384 + "装",
385 + "影",
386 + "算",
387 + "低",
388 + "持",
389 + "音",
390 + "众",
391 + "书",
392 + "布",
393 + "复",
394 + "容",
395 + "儿",
396 + "须",
397 + "际",
398 + "商",
399 + "非",
400 + "验",
401 + "连",
402 + "断",
403 + "深",
404 + "难",
405 + "近",
406 + "矿",
407 + "千",
408 + "周",
409 + "委",
410 + "素",
411 + "技",
412 + "备",
413 + "半",
414 + "办",
415 + "青",
416 + "省",
417 + "列",
418 + "习",
419 + "响",
420 + "约",
421 + "支",
422 + "般",
423 + "史",
424 + "感",
425 + "劳",
426 + "便",
427 + "团",
428 + "往",
429 + "酸",
430 + "历",
431 + "市",
432 + "克",
433 + "何",
434 + "除",
435 + "消",
436 + "构",
437 + "府",
438 + "称",
439 + "太",
440 + "准",
441 + "精",
442 + "值",
443 + "号",
444 + "率",
445 + "族",
446 + "维",
447 + "划",
448 + "选",
449 + "标",
450 + "写",
451 + "存",
452 + "候",
453 + "毛",
454 + "亲",
455 + "快",
456 + "效",
457 + "斯",
458 + "院",
459 + "查",
460 + "江",
461 + "型",
462 + "眼",
463 + "王",
464 + "按",
465 + "格",
466 + "养",
467 + "易",
468 + "置",
469 + "派",
470 + "层",
471 + "片",
472 + "始",
473 + "却",
474 + "专",
475 + "状",
476 + "育",
477 + "厂",
478 + "京",
479 + "识",
480 + "适",
481 + "属",
482 + "圆",
483 + "包",
484 + "火",
485 + "住",
486 + "调",
487 + "满",
488 + "县",
489 + "局",
490 + "照",
491 + "参",
492 + "红",
493 + "细",
494 + "引",
495 + "听",
496 + "该",
497 + "铁",
498 + "价",
499 + "严",
500 + "首",
501 + "底",
502 + "液",
503 + "官",
504 + "德",
505 + "随",
506 + "病",
507 + "苏",
508 + "失",
509 + "尔",
510 + "死",
511 + "讲",
512 + "配",
513 + "女",
514 + "黄",
515 + "推",
516 + "显",
517 + "谈",
518 + "罪",
519 + "神",
520 + "艺",
521 + "呢",
522 + "席",
523 + "含",
524 + "企",
525 + "望",
526 + "密",
527 + "批",
528 + "营",
529 + "项",
530 + "防",
531 + "举",
532 + "球",
533 + "英",
534 + "氧",
535 + "势",
536 + "告",
537 + "李",
538 + "台",
539 + "落",
540 + "木",
541 + "帮",
542 + "轮",
543 + "破",
544 + "亚",
545 + "师",
546 + "围",
547 + "注",
548 + "远",
549 + "字",
550 + "材",
551 + "排",
552 + "供",
553 + "河",
554 + "态",
555 + "封",
556 + "另",
557 + "施",
558 + "减",
559 + "树",
560 + "溶",
561 + "怎",
562 + "止",
563 + "案",
564 + "言",
565 + "士",
566 + "均",
567 + "武",
568 + "固",
569 + "叶",
570 + "鱼",
571 + "波",
572 + "视",
573 + "仅",
574 + "费",
575 + "紧",
576 + "爱",
577 + "左",
578 + "章",
579 + "早",
580 + "朝",
581 + "害",
582 + "续",
583 + "轻",
584 + "服",
585 + "试",
586 + "食",
587 + "充",
588 + "兵",
589 + "源",
590 + "判",
591 + "护",
592 + "司",
593 + "足",
594 + "某",
595 + "练",
596 + "差",
597 + "致",
598 + "板",
599 + "田",
600 + "降",
601 + "黑",
602 + "犯",
603 + "负",
604 + "击",
605 + "范",
606 + "继",
607 + "兴",
608 + "似",
609 + "余",
610 + "坚",
611 + "曲",
612 + "输",
613 + "修",
614 + "故",
615 + "城",
616 + "夫",
617 + "够",
618 + "送",
619 + "笔",
620 + "船",
621 + "占",
622 + "右",
623 + "财",
624 + "吃",
625 + "富",
626 + "春",
627 + "职",
628 + "觉",
629 + "汉",
630 + "画",
631 + "功",
632 + "巴",
633 + "跟",
634 + "虽",
635 + "杂",
636 + "飞",
637 + "检",
638 + "吸",
639 + "助",
640 + "升",
641 + "阳",
642 + "互",
643 + "初",
644 + "创",
645 + "抗",
646 + "考",
647 + "投",
648 + "坏",
649 + "策",
650 + "古",
651 + "径",
652 + "换",
653 + "未",
654 + "跑",
655 + "留",
656 + "钢",
657 + "曾",
658 + "端",
659 + "责",
660 + "站",
661 + "简",
662 + "述",
663 + "钱",
664 + "副",
665 + "尽",
666 + "帝",
667 + "射",
668 + "草",
669 + "冲",
670 + "承",
671 + "独",
672 + "令",
673 + "限",
674 + "阿",
675 + "宣",
676 + "环",
677 + "双",
678 + "请",
679 + "超",
680 + "微",
681 + "让",
682 + "控",
683 + "州",
684 + "良",
685 + "轴",
686 + "找",
687 + "否",
688 + "纪",
689 + "益",
690 + "依",
691 + "优",
692 + "顶",
693 + "础",
694 + "载",
695 + "倒",
696 + "房",
697 + "突",
698 + "坐",
699 + "粉",
700 + "敌",
701 + "略",
702 + "客",
703 + "袁",
704 + "冷",
705 + "胜",
706 + "绝",
707 + "析",
708 + "块",
709 + "剂",
710 + "测",
711 + "丝",
712 + "协",
713 + "诉",
714 + "念",
715 + "陈",
716 + "仍",
717 + "罗",
718 + "盐",
719 + "友",
720 + "洋",
721 + "错",
722 + "苦",
723 + "夜",
724 + "刑",
725 + "移",
726 + "频",
727 + "逐",
728 + "靠",
729 + "混",
730 + "母",
731 + "短",
732 + "皮",
733 + "终",
734 + "聚",
735 + "汽",
736 + "村",
737 + "云",
738 + "哪",
739 + "既",
740 + "距",
741 + "卫",
742 + "停",
743 + "烈",
744 + "央",
745 + "察",
746 + "烧",
747 + "迅",
748 + "境",
749 + "若",
750 + "印",
751 + "洲",
752 + "刻",
753 + "括",
754 + "激",
755 + "孔",
756 + "搞",
757 + "甚",
758 + "室",
759 + "待",
760 + "核",
761 + "校",
762 + "散",
763 + "侵",
764 + "吧",
765 + "甲",
766 + "游",
767 + "久",
768 + "菜",
769 + "味",
770 + "旧",
771 + "模",
772 + "湖",
773 + "货",
774 + "损",
775 + "预",
776 + "阻",
777 + "毫",
778 + "普",
779 + "稳",
780 + "乙",
781 + "妈",
782 + "植",
783 + "息",
784 + "扩",
785 + "银",
786 + "语",
787 + "挥",
788 + "酒",
789 + "守",
790 + "拿",
791 + "序",
792 + "纸",
793 + "医",
794 + "缺",
795 + "雨",
796 + "吗",
797 + "针",
798 + "刘",
799 + "啊",
800 + "急",
801 + "唱",
802 + "误",
803 + "训",
804 + "愿",
805 + "审",
806 + "附",
807 + "获",
808 + "茶",
809 + "鲜",
810 + "粮",
811 + "斤",
812 + "孩",
813 + "脱",
814 + "硫",
815 + "肥",
816 + "善",
817 + "龙",
818 + "演",
819 + "父",
820 + "渐",
821 + "血",
822 + "欢",
823 + "械",
824 + "掌",
825 + "歌",
826 + "沙",
827 + "刚",
828 + "攻",
829 + "谓",
830 + "盾",
831 + "讨",
832 + "晚",
833 + "粒",
834 + "乱",
835 + "燃",
836 + "矛",
837 + "乎",
838 + "杀",
839 + "药",
840 + "宁",
841 + "鲁",
842 + "贵",
843 + "钟",
844 + "煤",
845 + "读",
846 + "班",
847 + "伯",
848 + "香",
849 + "介",
850 + "迫",
851 + "句",
852 + "丰",
853 + "培",
854 + "握",
855 + "兰",
856 + "担",
857 + "弦",
858 + "蛋",
859 + "沉",
860 + "假",
861 + "穿",
862 + "执",
863 + "答",
864 + "乐",
865 + "谁",
866 + "顺",
867 + "烟",
868 + "缩",
869 + "征",
870 + "脸",
871 + "喜",
872 + "松",
873 + "脚",
874 + "困",
875 + "异",
876 + "免",
877 + "背",
878 + "星",
879 + "福",
880 + "买",
881 + "染",
882 + "井",
883 + "概",
884 + "慢",
885 + "怕",
886 + "磁",
887 + "倍",
888 + "祖",
889 + "皇",
890 + "促",
891 + "静",
892 + "补",
893 + "评",
894 + "翻",
895 + "肉",
896 + "践",
897 + "尼",
898 + "衣",
899 + "宽",
900 + "扬",
901 + "棉",
902 + "希",
903 + "伤",
904 + "操",
905 + "垂",
906 + "秋",
907 + "宜",
908 + "氢",
909 + "套",
910 + "督",
911 + "振",
912 + "架",
913 + "亮",
914 + "末",
915 + "宪",
916 + "庆",
917 + "编",
918 + "牛",
919 + "触",
920 + "映",
921 + "雷",
922 + "销",
923 + "诗",
924 + "座",
925 + "居",
926 + "抓",
927 + "裂",
928 + "胞",
929 + "呼",
930 + "娘",
931 + "景",
932 + "威",
933 + "绿",
934 + "晶",
935 + "厚",
936 + "盟",
937 + "衡",
938 + "鸡",
939 + "孙",
940 + "延",
941 + "危",
942 + "胶",
943 + "屋",
944 + "乡",
945 + "临",
946 + "陆",
947 + "顾",
948 + "掉",
949 + "呀",
950 + "灯",
951 + "岁",
952 + "措",
953 + "束",
954 + "耐",
955 + "剧",
956 + "玉",
957 + "赵",
958 + "跳",
959 + "哥",
960 + "季",
961 + "课",
962 + "凯",
963 + "胡",
964 + "额",
965 + "款",
966 + "绍",
967 + "卷",
968 + "齐",
969 + "伟",
970 + "蒸",
971 + "殖",
972 + "永",
973 + "宗",
974 + "苗",
975 + "川",
976 + "炉",
977 + "岩",
978 + "弱",
979 + "零",
980 + "杨",
981 + "奏",
982 + "沿",
983 + "露",
984 + "杆",
985 + "探",
986 + "滑",
987 + "镇",
988 + "饭",
989 + "浓",
990 + "航",
991 + "怀",
992 + "赶",
993 + "库",
994 + "夺",
995 + "伊",
996 + "灵",
997 + "税",
998 + "途",
999 + "灭",
1000 + "赛",
1001 + "归",
1002 + "召",
1003 + "鼓",
1004 + "播",
1005 + "盘",
1006 + "裁",
1007 + "险",
1008 + "康",
1009 + "唯",
1010 + "录",
1011 + "菌",
1012 + "纯",
1013 + "借",
1014 + "糖",
1015 + "盖",
1016 + "横",
1017 + "符",
1018 + "私",
1019 + "努",
1020 + "堂",
1021 + "域",
1022 + "枪",
1023 + "润",
1024 + "幅",
1025 + "哈",
1026 + "竟",
1027 + "熟",
1028 + "虫",
1029 + "泽",
1030 + "脑",
1031 + "壤",
1032 + "碳",
1033 + "欧",
1034 + "遍",
1035 + "侧",
1036 + "寨",
1037 + "敢",
1038 + "彻",
1039 + "虑",
1040 + "斜",
1041 + "薄",
1042 + "庭",
1043 + "纳",
1044 + "弹",
1045 + "饲",
1046 + "伸",
1047 + "折",
1048 + "麦",
1049 + "湿",
1050 + "暗",
1051 + "荷",
1052 + "瓦",
1053 + "塞",
1054 + "床",
1055 + "筑",
1056 + "恶",
1057 + "户",
1058 + "访",
1059 + "塔",
1060 + "奇",
1061 + "透",
1062 + "梁",
1063 + "刀",
1064 + "旋",
1065 + "迹",
1066 + "卡",
1067 + "氯",
1068 + "遇",
1069 + "份",
1070 + "毒",
1071 + "泥",
1072 + "退",
1073 + "洗",
1074 + "摆",
1075 + "灰",
1076 + "彩",
1077 + "卖",
1078 + "耗",
1079 + "夏",
1080 + "择",
1081 + "忙",
1082 + "铜",
1083 + "献",
1084 + "硬",
1085 + "予",
1086 + "繁",
1087 + "圈",
1088 + "雪",
1089 + "函",
1090 + "亦",
1091 + "抽",
1092 + "篇",
1093 + "阵",
1094 + "阴",
1095 + "丁",
1096 + "尺",
1097 + "追",
1098 + "堆",
1099 + "雄",
1100 + "迎",
1101 + "泛",
1102 + "爸",
1103 + "楼",
1104 + "避",
1105 + "谋",
1106 + "吨",
1107 + "野",
1108 + "猪",
1109 + "旗",
1110 + "累",
1111 + "偏",
1112 + "典",
1113 + "馆",
1114 + "索",
1115 + "秦",
1116 + "脂",
1117 + "潮",
1118 + "爷",
1119 + "豆",
1120 + "忽",
1121 + "托",
1122 + "惊",
1123 + "塑",
1124 + "遗",
1125 + "愈",
1126 + "朱",
1127 + "替",
1128 + "纤",
1129 + "粗",
1130 + "倾",
1131 + "尚",
1132 + "痛",
1133 + "楚",
1134 + "谢",
1135 + "奋",
1136 + "购",
1137 + "磨",
1138 + "君",
1139 + "池",
1140 + "旁",
1141 + "碎",
1142 + "骨",
1143 + "监",
1144 + "捕",
1145 + "弟",
1146 + "暴",
1147 + "割",
1148 + "贯",
1149 + "殊",
1150 + "释",
1151 + "词",
1152 + "亡",
1153 + "壁",
1154 + "顿",
1155 + "宝",
1156 + "午",
1157 + "尘",
1158 + "闻",
1159 + "揭",
1160 + "炮",
1161 + "残",
1162 + "冬",
1163 + "桥",
1164 + "妇",
1165 + "警",
1166 + "综",
1167 + "招",
1168 + "吴",
1169 + "付",
1170 + "浮",
1171 + "遭",
1172 + "徐",
1173 + "您",
1174 + "摇",
1175 + "谷",
1176 + "赞",
1177 + "箱",
1178 + "隔",
1179 + "订",
1180 + "男",
1181 + "吹",
1182 + "园",
1183 + "纷",
1184 + "唐",
1185 + "败",
1186 + "宋",
1187 + "玻",
1188 + "巨",
1189 + "耕",
1190 + "坦",
1191 + "荣",
1192 + "闭",
1193 + "湾",
1194 + "键",
1195 + "凡",
1196 + "驻",
1197 + "锅",
1198 + "救",
1199 + "恩",
1200 + "剥",
1201 + "凝",
1202 + "碱",
1203 + "齿",
1204 + "截",
1205 + "炼",
1206 + "麻",
1207 + "纺",
1208 + "禁",
1209 + "废",
1210 + "盛",
1211 + "版",
1212 + "缓",
1213 + "净",
1214 + "睛",
1215 + "昌",
1216 + "婚",
1217 + "涉",
1218 + "筒",
1219 + "嘴",
1220 + "插",
1221 + "岸",
1222 + "朗",
1223 + "庄",
1224 + "街",
1225 + "藏",
1226 + "姑",
1227 + "贸",
1228 + "腐",
1229 + "奴",
1230 + "啦",
1231 + "惯",
1232 + "乘",
1233 + "伙",
1234 + "恢",
1235 + "匀",
1236 + "纱",
1237 + "扎",
1238 + "辩",
1239 + "耳",
1240 + "彪",
1241 + "臣",
1242 + "亿",
1243 + "璃",
1244 + "抵",
1245 + "脉",
1246 + "秀",
1247 + "萨",
1248 + "俄",
1249 + "网",
1250 + "舞",
1251 + "店",
1252 + "喷",
1253 + "纵",
1254 + "寸",
1255 + "汗",
1256 + "挂",
1257 + "洪",
1258 + "贺",
1259 + "闪",
1260 + "柬",
1261 + "爆",
1262 + "烯",
1263 + "津",
1264 + "稻",
1265 + "墙",
1266 + "软",
1267 + "勇",
1268 + "像",
1269 + "滚",
1270 + "厘",
1271 + "蒙",
1272 + "芳",
1273 + "肯",
1274 + "坡",
1275 + "柱",
1276 + "荡",
1277 + "腿",
1278 + "仪",
1279 + "旅",
1280 + "尾",
1281 + "轧",
1282 + "冰",
1283 + "贡",
1284 + "登",
1285 + "黎",
1286 + "削",
1287 + "钻",
1288 + "勒",
1289 + "逃",
1290 + "障",
1291 + "氨",
1292 + "郭",
1293 + "峰",
1294 + "币",
1295 + "港",
1296 + "伏",
1297 + "轨",
1298 + "亩",
1299 + "毕",
1300 + "擦",
1301 + "莫",
1302 + "刺",
1303 + "浪",
1304 + "秘",
1305 + "援",
1306 + "株",
1307 + "健",
1308 + "售",
1309 + "股",
1310 + "岛",
1311 + "甘",
1312 + "泡",
1313 + "睡",
1314 + "童",
1315 + "铸",
1316 + "汤",
1317 + "阀",
1318 + "休",
1319 + "汇",
1320 + "舍",
1321 + "牧",
1322 + "绕",
1323 + "炸",
1324 + "哲",
1325 + "磷",
1326 + "绩",
1327 + "朋",
1328 + "淡",
1329 + "尖",
1330 + "启",
1331 + "陷",
1332 + "柴",
1333 + "呈",
1334 + "徒",
1335 + "颜",
1336 + "泪",
1337 + "稍",
1338 + "忘",
1339 + "泵",
1340 + "蓝",
1341 + "拖",
1342 + "洞",
1343 + "授",
1344 + "镜",
1345 + "辛",
1346 + "壮",
1347 + "锋",
1348 + "贫",
1349 + "虚",
1350 + "弯",
1351 + "摩",
1352 + "泰",
1353 + "幼",
1354 + "廷",
1355 + "尊",
1356 + "窗",
1357 + "纲",
1358 + "弄",
1359 + "隶",
1360 + "疑",
1361 + "氏",
1362 + "宫",
1363 + "姐",
1364 + "震",
1365 + "瑞",
1366 + "怪",
1367 + "尤",
1368 + "琴",
1369 + "循",
1370 + "描",
1371 + "膜",
1372 + "违",
1373 + "夹",
1374 + "腰",
1375 + "缘",
1376 + "珠",
1377 + "穷",
1378 + "森",
1379 + "枝",
1380 + "竹",
1381 + "沟",
1382 + "催",
1383 + "绳",
1384 + "忆",
1385 + "邦",
1386 + "剩",
1387 + "幸",
1388 + "浆",
1389 + "栏",
1390 + "拥",
1391 + "牙",
1392 + "贮",
1393 + "礼",
1394 + "滤",
1395 + "钠",
1396 + "纹",
1397 + "罢",
1398 + "拍",
1399 + "咱",
1400 + "喊",
1401 + "袖",
1402 + "埃",
1403 + "勤",
1404 + "罚",
1405 + "焦",
1406 + "潜",
1407 + "伍",
1408 + "墨",
1409 + "欲",
1410 + "缝",
1411 + "姓",
1412 + "刊",
1413 + "饱",
1414 + "仿",
1415 + "奖",
1416 + "铝",
1417 + "鬼",
1418 + "丽",
1419 + "跨",
1420 + "默",
1421 + "挖",
1422 + "链",
1423 + "扫",
1424 + "喝",
1425 + "袋",
1426 + "炭",
1427 + "污",
1428 + "幕",
1429 + "诸",
1430 + "弧",
1431 + "励",
1432 + "梅",
1433 + "奶",
1434 + "洁",
1435 + "灾",
1436 + "舟",
1437 + "鉴",
1438 + "苯",
1439 + "讼",
1440 + "抱",
1441 + "毁",
1442 + "懂",
1443 + "寒",
1444 + "智",
1445 + "埔",
1446 + "寄",
1447 + "届",
1448 + "跃",
1449 + "渡",
1450 + "挑",
1451 + "丹",
1452 + "艰",
1453 + "贝",
1454 + "碰",
1455 + "拔",
1456 + "爹",
1457 + "戴",
1458 + "码",
1459 + "梦",
1460 + "芽",
1461 + "熔",
1462 + "赤",
1463 + "渔",
1464 + "哭",
1465 + "敬",
1466 + "颗",
1467 + "奔",
1468 + "铅",
1469 + "仲",
1470 + "虎",
1471 + "稀",
1472 + "妹",
1473 + "乏",
1474 + "珍",
1475 + "申",
1476 + "桌",
1477 + "遵",
1478 + "允",
1479 + "隆",
1480 + "螺",
1481 + "仓",
1482 + "魏",
1483 + "锐",
1484 + "晓",
1485 + "氮",
1486 + "兼",
1487 + "隐",
1488 + "碍",
1489 + "赫",
1490 + "拨",
1491 + "忠",
1492 + "肃",
1493 + "缸",
1494 + "牵",
1495 + "抢",
1496 + "博",
1497 + "巧",
1498 + "壳",
1499 + "兄",
1500 + "杜",
1501 + "讯",
1502 + "诚",
1503 + "碧",
1504 + "祥",
1505 + "柯",
1506 + "页",
1507 + "巡",
1508 + "矩",
1509 + "悲",
1510 + "灌",
1511 + "龄",
1512 + "伦",
1513 + "票",
1514 + "寻",
1515 + "桂",
1516 + "铺",
1517 + "圣",
1518 + "恐",
1519 + "恰",
1520 + "郑",
1521 + "趣",
1522 + "抬",
1523 + "荒",
1524 + "腾",
1525 + "贴",
1526 + "柔",
1527 + "滴",
1528 + "猛",
1529 + "阔",
1530 + "辆",
1531 + "妻",
1532 + "填",
1533 + "撤",
1534 + "储",
1535 + "签",
1536 + "闹",
1537 + "扰",
1538 + "紫",
1539 + "砂",
1540 + "递",
1541 + "戏",
1542 + "吊",
1543 + "陶",
1544 + "伐",
1545 + "喂",
1546 + "疗",
1547 + "瓶",
1548 + "婆",
1549 + "抚",
1550 + "臂",
1551 + "摸",
1552 + "忍",
1553 + "虾",
1554 + "蜡",
1555 + "邻",
1556 + "胸",
1557 + "巩",
1558 + "挤",
1559 + "偶",
1560 + "弃",
1561 + "槽",
1562 + "劲",
1563 + "乳",
1564 + "邓",
1565 + "吉",
1566 + "仁",
1567 + "烂",
1568 + "砖",
1569 + "租",
1570 + "乌",
1571 + "舰",
1572 + "伴",
1573 + "瓜",
1574 + "浅",
1575 + "丙",
1576 + "暂",
1577 + "燥",
1578 + "橡",
1579 + "柳",
1580 + "迷",
1581 + "暖",
1582 + "牌",
1583 + "秧",
1584 + "胆",
1585 + "详",
1586 + "簧",
1587 + "踏",
1588 + "瓷",
1589 + "谱",
1590 + "呆",
1591 + "宾",
1592 + "糊",
1593 + "洛",
1594 + "辉",
1595 + "愤",
1596 + "竞",
1597 + "隙",
1598 + "怒",
1599 + "粘",
1600 + "乃",
1601 + "绪",
1602 + "肩",
1603 + "籍",
1604 + "敏",
1605 + "涂",
1606 + "熙",
1607 + "皆",
1608 + "侦",
1609 + "悬",
1610 + "掘",
1611 + "享",
1612 + "纠",
1613 + "醒",
1614 + "狂",
1615 + "锁",
1616 + "淀",
1617 + "恨",
1618 + "牲",
1619 + "霸",
1620 + "爬",
1621 + "赏",
1622 + "逆",
1623 + "玩",
1624 + "陵",
1625 + "祝",
1626 + "秒",
1627 + "浙",
1628 + "貌"
1629 + ];
1630 +}
\ No newline at end of file
cw_monero/lib/mnemonics/dutch.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class DutchMnemonics {
2 + static const words = [
3 + "aalglad",
4 + "aalscholver",
5 + "aambeeld",
6 + "aangeef",
7 + "aanlandig",
8 + "aanvaard",
9 + "aanwakker",
10 + "aapmens",
11 + "aarten",
12 + "abdicatie",
13 + "abnormaal",
14 + "abrikoos",
15 + "accu",
16 + "acuut",
17 + "adjudant",
18 + "admiraal",
19 + "advies",
20 + "afbidding",
21 + "afdracht",
22 + "affaire",
23 + "affiche",
24 + "afgang",
25 + "afkick",
26 + "afknap",
27 + "aflees",
28 + "afmijner",
29 + "afname",
30 + "afpreekt",
31 + "afrader",
32 + "afspeel",
33 + "aftocht",
34 + "aftrek",
35 + "afzijdig",
36 + "ahornboom",
37 + "aktetas",
38 + "akzo",
39 + "alchemist",
40 + "alcohol",
41 + "aldaar",
42 + "alexander",
43 + "alfabet",
44 + "alfredo",
45 + "alice",
46 + "alikruik",
47 + "allrisk",
48 + "altsax",
49 + "alufolie",
50 + "alziend",
51 + "amai",
52 + "ambacht",
53 + "ambieer",
54 + "amina",
55 + "amnestie",
56 + "amok",
57 + "ampul",
58 + "amuzikaal",
59 + "angela",
60 + "aniek",
61 + "antje",
62 + "antwerpen",
63 + "anya",
64 + "aorta",
65 + "apache",
66 + "apekool",
67 + "appelaar",
68 + "arganolie",
69 + "argeloos",
70 + "armoede",
71 + "arrenslee",
72 + "artritis",
73 + "arubaan",
74 + "asbak",
75 + "ascii",
76 + "asgrauw",
77 + "asjes",
78 + "asml",
79 + "aspunt",
80 + "asurn",
81 + "asveld",
82 + "aterling",
83 + "atomair",
84 + "atrium",
85 + "atsma",
86 + "atypisch",
87 + "auping",
88 + "aura",
89 + "avifauna",
90 + "axiaal",
91 + "azoriaan",
92 + "azteek",
93 + "azuur",
94 + "bachelor",
95 + "badderen",
96 + "badhotel",
97 + "badmantel",
98 + "badsteden",
99 + "balie",
100 + "ballans",
101 + "balvers",
102 + "bamibal",
103 + "banneling",
104 + "barracuda",
105 + "basaal",
106 + "batelaan",
107 + "batje",
108 + "beambte",
109 + "bedlamp",
110 + "bedwelmd",
111 + "befaamd",
112 + "begierd",
113 + "begraaf",
114 + "behield",
115 + "beijaard",
116 + "bejaagd",
117 + "bekaaid",
118 + "beks",
119 + "bektas",
120 + "belaad",
121 + "belboei",
122 + "belderbos",
123 + "beloerd",
124 + "beluchten",
125 + "bemiddeld",
126 + "benadeeld",
127 + "benijd",
128 + "berechten",
129 + "beroemd",
130 + "besef",
131 + "besseling",
132 + "best",
133 + "betichten",
134 + "bevind",
135 + "bevochten",
136 + "bevraagd",
137 + "bewust",
138 + "bidplaats",
139 + "biefstuk",
140 + "biemans",
141 + "biezen",
142 + "bijbaan",
143 + "bijeenkom",
144 + "bijfiguur",
145 + "bijkaart",
146 + "bijlage",
147 + "bijpaard",
148 + "bijtgaar",
149 + "bijweg",
150 + "bimmel",
151 + "binck",
152 + "bint",
153 + "biobak",
154 + "biotisch",
155 + "biseks",
156 + "bistro",
157 + "bitter",
158 + "bitumen",
159 + "bizar",
160 + "blad",
161 + "bleken",
162 + "blender",
163 + "bleu",
164 + "blief",
165 + "blijven",
166 + "blozen",
167 + "bock",
168 + "boef",
169 + "boei",
170 + "boks",
171 + "bolder",
172 + "bolus",
173 + "bolvormig",
174 + "bomaanval",
175 + "bombarde",
176 + "bomma",
177 + "bomtapijt",
178 + "bookmaker",
179 + "boos",
180 + "borg",
181 + "bosbes",
182 + "boshuizen",
183 + "bosloop",
184 + "botanicus",
185 + "bougie",
186 + "bovag",
187 + "boxspring",
188 + "braad",
189 + "brasem",
190 + "brevet",
191 + "brigade",
192 + "brinckman",
193 + "bruid",
194 + "budget",
195 + "buffel",
196 + "buks",
197 + "bulgaar",
198 + "buma",
199 + "butaan",
200 + "butler",
201 + "buuf",
202 + "cactus",
203 + "cafeetje",
204 + "camcorder",
205 + "cannabis",
206 + "canyon",
207 + "capoeira",
208 + "capsule",
209 + "carkit",
210 + "casanova",
211 + "catalaan",
212 + "ceintuur",
213 + "celdeling",
214 + "celplasma",
215 + "cement",
216 + "censeren",
217 + "ceramisch",
218 + "cerberus",
219 + "cerebraal",
220 + "cesium",
221 + "cirkel",
222 + "citeer",
223 + "civiel",
224 + "claxon",
225 + "clenbuterol",
226 + "clicheren",
227 + "clijsen",
228 + "coalitie",
229 + "coassistentschap",
230 + "coaxiaal",
231 + "codetaal",
232 + "cofinanciering",
233 + "cognac",
234 + "coltrui",
235 + "comfort",
236 + "commandant",
237 + "condensaat",
238 + "confectie",
239 + "conifeer",
240 + "convector",
241 + "copier",
242 + "corfu",
243 + "correct",
244 + "coup",
245 + "couvert",
246 + "creatie",
247 + "credit",
248 + "crematie",
249 + "cricket",
250 + "croupier",
251 + "cruciaal",
252 + "cruijff",
253 + "cuisine",
254 + "culemborg",
255 + "culinair",
256 + "curve",
257 + "cyrano",
258 + "dactylus",
259 + "dading",
260 + "dagblind",
261 + "dagje",
262 + "daglicht",
263 + "dagprijs",
264 + "dagranden",
265 + "dakdekker",
266 + "dakpark",
267 + "dakterras",
268 + "dalgrond",
269 + "dambord",
270 + "damkat",
271 + "damlengte",
272 + "damman",
273 + "danenberg",
274 + "debbie",
275 + "decibel",
276 + "defect",
277 + "deformeer",
278 + "degelijk",
279 + "degradant",
280 + "dejonghe",
281 + "dekken",
282 + "deppen",
283 + "derek",
284 + "derf",
285 + "derhalve",
286 + "detineren",
287 + "devalueer",
288 + "diaken",
289 + "dicht",
290 + "dictaat",
291 + "dief",
292 + "digitaal",
293 + "dijbreuk",
294 + "dijkmans",
295 + "dimbaar",
296 + "dinsdag",
297 + "diode",
298 + "dirigeer",
299 + "disbalans",
300 + "dobermann",
301 + "doenbaar",
302 + "doerak",
303 + "dogma",
304 + "dokhaven",
305 + "dokwerker",
306 + "doling",
307 + "dolphijn",
308 + "dolven",
309 + "dombo",
310 + "dooraderd",
311 + "dopeling",
312 + "doping",
313 + "draderig",
314 + "drama",
315 + "drenkbak",
316 + "dreumes",
317 + "drol",
318 + "drug",
319 + "duaal",
320 + "dublin",
321 + "duplicaat",
322 + "durven",
323 + "dusdanig",
324 + "dutchbat",
325 + "dutje",
326 + "dutten",
327 + "duur",
328 + "duwwerk",
329 + "dwaal",
330 + "dweil",
331 + "dwing",
332 + "dyslexie",
333 + "ecostroom",
334 + "ecotaks",
335 + "educatie",
336 + "eeckhout",
337 + "eede",
338 + "eemland",
339 + "eencellig",
340 + "eeneiig",
341 + "eenruiter",
342 + "eenwinter",
343 + "eerenberg",
344 + "eerrover",
345 + "eersel",
346 + "eetmaal",
347 + "efteling",
348 + "egaal",
349 + "egtberts",
350 + "eickhoff",
351 + "eidooier",
352 + "eiland",
353 + "eind",
354 + "eisden",
355 + "ekster",
356 + "elburg",
357 + "elevatie",
358 + "elfkoppig",
359 + "elfrink",
360 + "elftal",
361 + "elimineer",
362 + "elleboog",
363 + "elma",
364 + "elodie",
365 + "elsa",
366 + "embleem",
367 + "embolie",
368 + "emoe",
369 + "emonds",
370 + "emplooi",
371 + "enduro",
372 + "enfin",
373 + "engageer",
374 + "entourage",
375 + "entstof",
376 + "epileer",
377 + "episch",
378 + "eppo",
379 + "erasmus",
380 + "erboven",
381 + "erebaan",
382 + "erelijst",
383 + "ereronden",
384 + "ereteken",
385 + "erfhuis",
386 + "erfwet",
387 + "erger",
388 + "erica",
389 + "ermitage",
390 + "erna",
391 + "ernie",
392 + "erts",
393 + "ertussen",
394 + "eruitzien",
395 + "ervaar",
396 + "erven",
397 + "erwt",
398 + "esbeek",
399 + "escort",
400 + "esdoorn",
401 + "essing",
402 + "etage",
403 + "eter",
404 + "ethanol",
405 + "ethicus",
406 + "etholoog",
407 + "eufonisch",
408 + "eurocent",
409 + "evacuatie",
410 + "exact",
411 + "examen",
412 + "executant",
413 + "exen",
414 + "exit",
415 + "exogeen",
416 + "exotherm",
417 + "expeditie",
418 + "expletief",
419 + "expres",
420 + "extase",
421 + "extinctie",
422 + "faal",
423 + "faam",
424 + "fabel",
425 + "facultair",
426 + "fakir",
427 + "fakkel",
428 + "faliekant",
429 + "fallisch",
430 + "famke",
431 + "fanclub",
432 + "fase",
433 + "fatsoen",
434 + "fauna",
435 + "federaal",
436 + "feedback",
437 + "feest",
438 + "feilbaar",
439 + "feitelijk",
440 + "felblauw",
441 + "figurante",
442 + "fiod",
443 + "fitheid",
444 + "fixeer",
445 + "flap",
446 + "fleece",
447 + "fleur",
448 + "flexibel",
449 + "flits",
450 + "flos",
451 + "flow",
452 + "fluweel",
453 + "foezelen",
454 + "fokkelman",
455 + "fokpaard",
456 + "fokvee",
457 + "folder",
458 + "follikel",
459 + "folmer",
460 + "folteraar",
461 + "fooi",
462 + "foolen",
463 + "forfait",
464 + "forint",
465 + "formule",
466 + "fornuis",
467 + "fosfaat",
468 + "foxtrot",
469 + "foyer",
470 + "fragiel",
471 + "frater",
472 + "freak",
473 + "freddie",
474 + "fregat",
475 + "freon",
476 + "frijnen",
477 + "fructose",
478 + "frunniken",
479 + "fuiven",
480 + "funshop",
481 + "furieus",
482 + "fysica",
483 + "gadget",
484 + "galder",
485 + "galei",
486 + "galg",
487 + "galvlieg",
488 + "galzuur",
489 + "ganesh",
490 + "gaswet",
491 + "gaza",
492 + "gazelle",
493 + "geaaid",
494 + "gebiecht",
495 + "gebufferd",
496 + "gedijd",
497 + "geef",
498 + "geflanst",
499 + "gefreesd",
500 + "gegaan",
501 + "gegijzeld",
502 + "gegniffel",
503 + "gegraaid",
504 + "gehikt",
505 + "gehobbeld",
506 + "gehucht",
507 + "geiser",
508 + "geiten",
509 + "gekaakt",
510 + "gekheid",
511 + "gekijf",
512 + "gekmakend",
513 + "gekocht",
514 + "gekskap",
515 + "gekte",
516 + "gelubberd",
517 + "gemiddeld",
518 + "geordend",
519 + "gepoederd",
520 + "gepuft",
521 + "gerda",
522 + "gerijpt",
523 + "geseald",
524 + "geshockt",
525 + "gesierd",
526 + "geslaagd",
527 + "gesnaaid",
528 + "getracht",
529 + "getwijfel",
530 + "geuit",
531 + "gevecht",
532 + "gevlagd",
533 + "gewicht",
534 + "gezaagd",
535 + "gezocht",
536 + "ghanees",
537 + "giebelen",
538 + "giechel",
539 + "giepmans",
540 + "gips",
541 + "giraal",
542 + "gistachtig",
543 + "gitaar",
544 + "glaasje",
545 + "gletsjer",
546 + "gleuf",
547 + "glibberen",
548 + "glijbaan",
549 + "gloren",
550 + "gluipen",
551 + "gluren",
552 + "gluur",
553 + "gnoe",
554 + "goddelijk",
555 + "godgans",
556 + "godschalk",
557 + "godzalig",
558 + "goeierd",
559 + "gogme",
560 + "goklustig",
561 + "gokwereld",
562 + "gonggrijp",
563 + "gonje",
564 + "goor",
565 + "grabbel",
566 + "graf",
567 + "graveer",
568 + "grif",
569 + "grolleman",
570 + "grom",
571 + "groosman",
572 + "grubben",
573 + "gruijs",
574 + "grut",
575 + "guacamole",
576 + "guido",
577 + "guppy",
578 + "haazen",
579 + "hachelijk",
580 + "haex",
581 + "haiku",
582 + "hakhout",
583 + "hakken",
584 + "hanegem",
585 + "hans",
586 + "hanteer",
587 + "harrie",
588 + "hazebroek",
589 + "hedonist",
590 + "heil",
591 + "heineken",
592 + "hekhuis",
593 + "hekman",
594 + "helbig",
595 + "helga",
596 + "helwegen",
597 + "hengelaar",
598 + "herkansen",
599 + "hermafrodiet",
600 + "hertaald",
601 + "hiaat",
602 + "hikspoors",
603 + "hitachi",
604 + "hitparade",
605 + "hobo",
606 + "hoeve",
607 + "holocaust",
608 + "hond",
609 + "honnepon",
610 + "hoogacht",
611 + "hotelbed",
612 + "hufter",
613 + "hugo",
614 + "huilbier",
615 + "hulk",
616 + "humus",
617 + "huwbaar",
618 + "huwelijk",
619 + "hype",
620 + "iconisch",
621 + "idema",
622 + "ideogram",
623 + "idolaat",
624 + "ietje",
625 + "ijker",
626 + "ijkheid",
627 + "ijklijn",
628 + "ijkmaat",
629 + "ijkwezen",
630 + "ijmuiden",
631 + "ijsbox",
632 + "ijsdag",
633 + "ijselijk",
634 + "ijskoud",
635 + "ilse",
636 + "immuun",
637 + "impliceer",
638 + "impuls",
639 + "inbijten",
640 + "inbuigen",
641 + "indijken",
642 + "induceer",
643 + "indy",
644 + "infecteer",
645 + "inhaak",
646 + "inkijk",
647 + "inluiden",
648 + "inmijnen",
649 + "inoefenen",
650 + "inpolder",
651 + "inrijden",
652 + "inslaan",
653 + "invitatie",
654 + "inwaaien",
655 + "ionisch",
656 + "isaac",
657 + "isolatie",
658 + "isotherm",
659 + "isra",
660 + "italiaan",
661 + "ivoor",
662 + "jacobs",
663 + "jakob",
664 + "jammen",
665 + "jampot",
666 + "jarig",
667 + "jehova",
668 + "jenever",
669 + "jezus",
670 + "joana",
671 + "jobdienst",
672 + "josua",
673 + "joule",
674 + "juich",
675 + "jurk",
676 + "juut",
677 + "kaas",
678 + "kabelaar",
679 + "kabinet",
680 + "kagenaar",
681 + "kajuit",
682 + "kalebas",
683 + "kalm",
684 + "kanjer",
685 + "kapucijn",
686 + "karregat",
687 + "kart",
688 + "katvanger",
689 + "katwijk",
690 + "kegelaar",
691 + "keiachtig",
692 + "keizer",
693 + "kenletter",
694 + "kerdijk",
695 + "keus",
696 + "kevlar",
697 + "kezen",
698 + "kickback",
699 + "kieviet",
700 + "kijken",
701 + "kikvors",
702 + "kilheid",
703 + "kilobit",
704 + "kilsdonk",
705 + "kipschnitzel",
706 + "kissebis",
707 + "klad",
708 + "klagelijk",
709 + "klak",
710 + "klapbaar",
711 + "klaver",
712 + "klene",
713 + "klets",
714 + "klijnhout",
715 + "klit",
716 + "klok",
717 + "klonen",
718 + "klotefilm",
719 + "kluif",
720 + "klumper",
721 + "klus",
722 + "knabbel",
723 + "knagen",
724 + "knaven",
725 + "kneedbaar",
726 + "knmi",
727 + "knul",
728 + "knus",
729 + "kokhals",
730 + "komiek",
731 + "komkommer",
732 + "kompaan",
733 + "komrij",
734 + "komvormig",
735 + "koning",
736 + "kopbal",
737 + "kopklep",
738 + "kopnagel",
739 + "koppejan",
740 + "koptekst",
741 + "kopwand",
742 + "koraal",
743 + "kosmisch",
744 + "kostbaar",
745 + "kram",
746 + "kraneveld",
747 + "kras",
748 + "kreling",
749 + "krengen",
750 + "kribbe",
751 + "krik",
752 + "kruid",
753 + "krulbol",
754 + "kuijper",
755 + "kuipbank",
756 + "kuit",
757 + "kuiven",
758 + "kutsmoes",
759 + "kuub",
760 + "kwak",
761 + "kwatong",
762 + "kwetsbaar",
763 + "kwezelaar",
764 + "kwijnen",
765 + "kwik",
766 + "kwinkslag",
767 + "kwitantie",
768 + "lading",
769 + "lakbeits",
770 + "lakken",
771 + "laklaag",
772 + "lakmoes",
773 + "lakwijk",
774 + "lamheid",
775 + "lamp",
776 + "lamsbout",
777 + "lapmiddel",
778 + "larve",
779 + "laser",
780 + "latijn",
781 + "latuw",
782 + "lawaai",
783 + "laxeerpil",
784 + "lebberen",
785 + "ledeboer",
786 + "leefbaar",
787 + "leeman",
788 + "lefdoekje",
789 + "lefhebber",
790 + "legboor",
791 + "legsel",
792 + "leguaan",
793 + "leiplaat",
794 + "lekdicht",
795 + "lekrijden",
796 + "leksteen",
797 + "lenen",
798 + "leraar",
799 + "lesbienne",
800 + "leugenaar",
801 + "leut",
802 + "lexicaal",
803 + "lezing",
804 + "lieten",
805 + "liggeld",
806 + "lijdzaam",
807 + "lijk",
808 + "lijmstang",
809 + "lijnschip",
810 + "likdoorn",
811 + "likken",
812 + "liksteen",
813 + "limburg",
814 + "link",
815 + "linoleum",
816 + "lipbloem",
817 + "lipman",
818 + "lispelen",
819 + "lissabon",
820 + "litanie",
821 + "liturgie",
822 + "lochem",
823 + "loempia",
824 + "loesje",
825 + "logheid",
826 + "lonen",
827 + "lonneke",
828 + "loom",
829 + "loos",
830 + "losbaar",
831 + "loslaten",
832 + "losplaats",
833 + "loting",
834 + "lotnummer",
835 + "lots",
836 + "louie",
837 + "lourdes",
838 + "louter",
839 + "lowbudget",
840 + "luijten",
841 + "luikenaar",
842 + "luilak",
843 + "luipaard",
844 + "luizenbos",
845 + "lulkoek",
846 + "lumen",
847 + "lunzen",
848 + "lurven",
849 + "lutjeboer",
850 + "luttel",
851 + "lutz",
852 + "luuk",
853 + "luwte",
854 + "luyendijk",
855 + "lyceum",
856 + "lynx",
857 + "maakbaar",
858 + "magdalena",
859 + "malheid",
860 + "manchet",
861 + "manfred",
862 + "manhaftig",
863 + "mank",
864 + "mantel",
865 + "marion",
866 + "marxist",
867 + "masmeijer",
868 + "massaal",
869 + "matsen",
870 + "matverf",
871 + "matze",
872 + "maude",
873 + "mayonaise",
874 + "mechanica",
875 + "meifeest",
876 + "melodie",
877 + "meppelink",
878 + "midvoor",
879 + "midweeks",
880 + "midzomer",
881 + "miezel",
882 + "mijnraad",
883 + "minus",
884 + "mirck",
885 + "mirte",
886 + "mispakken",
887 + "misraden",
888 + "miswassen",
889 + "mitella",
890 + "moker",
891 + "molecule",
892 + "mombakkes",
893 + "moonen",
894 + "mopperaar",
895 + "moraal",
896 + "morgana",
897 + "mormel",
898 + "mosselaar",
899 + "motregen",
900 + "mouw",
901 + "mufheid",
902 + "mutueel",
903 + "muzelman",
904 + "naaidoos",
905 + "naald",
906 + "nadeel",
907 + "nadruk",
908 + "nagy",
909 + "nahon",
910 + "naima",
911 + "nairobi",
912 + "napalm",
913 + "napels",
914 + "napijn",
915 + "napoleon",
916 + "narigheid",
917 + "narratief",
918 + "naseizoen",
919 + "nasibal",
920 + "navigatie",
921 + "nawijn",
922 + "negatief",
923 + "nekletsel",
924 + "nekwervel",
925 + "neolatijn",
926 + "neonataal",
927 + "neptunus",
928 + "nerd",
929 + "nest",
930 + "neuzelaar",
931 + "nihiliste",
932 + "nijenhuis",
933 + "nijging",
934 + "nijhoff",
935 + "nijl",
936 + "nijptang",
937 + "nippel",
938 + "nokkenas",
939 + "noordam",
940 + "noren",
941 + "normaal",
942 + "nottelman",
943 + "notulant",
944 + "nout",
945 + "nuance",
946 + "nuchter",
947 + "nudorp",
948 + "nulde",
949 + "nullijn",
950 + "nulmeting",
951 + "nunspeet",
952 + "nylon",
953 + "obelisk",
954 + "object",
955 + "oblie",
956 + "obsceen",
957 + "occlusie",
958 + "oceaan",
959 + "ochtend",
960 + "ockhuizen",
961 + "oerdom",
962 + "oergezond",
963 + "oerlaag",
964 + "oester",
965 + "okhuijsen",
966 + "olifant",
967 + "olijfboer",
968 + "omaans",
969 + "ombudsman",
970 + "omdat",
971 + "omdijken",
972 + "omdoen",
973 + "omgebouwd",
974 + "omkeer",
975 + "omkomen",
976 + "ommegaand",
977 + "ommuren",
978 + "omroep",
979 + "omruil",
980 + "omslaan",
981 + "omsmeden",
982 + "omvaar",
983 + "onaardig",
984 + "onedel",
985 + "onenig",
986 + "onheilig",
987 + "onrecht",
988 + "onroerend",
989 + "ontcijfer",
990 + "onthaal",
991 + "ontvallen",
992 + "ontzadeld",
993 + "onzacht",
994 + "onzin",
995 + "onzuiver",
996 + "oogappel",
997 + "ooibos",
998 + "ooievaar",
999 + "ooit",
1000 + "oorarts",
1001 + "oorhanger",
1002 + "oorijzer",
1003 + "oorklep",
1004 + "oorschelp",
1005 + "oorworm",
1006 + "oorzaak",
1007 + "opdagen",
1008 + "opdien",
1009 + "opdweilen",
1010 + "opel",
1011 + "opgebaard",
1012 + "opinie",
1013 + "opjutten",
1014 + "opkijken",
1015 + "opklaar",
1016 + "opkuisen",
1017 + "opkwam",
1018 + "opnaaien",
1019 + "opossum",
1020 + "opsieren",
1021 + "opsmeer",
1022 + "optreden",
1023 + "opvijzel",
1024 + "opvlammen",
1025 + "opwind",
1026 + "oraal",
1027 + "orchidee",
1028 + "orkest",
1029 + "ossuarium",
1030 + "ostendorf",
1031 + "oublie",
1032 + "oudachtig",
1033 + "oudbakken",
1034 + "oudnoors",
1035 + "oudshoorn",
1036 + "oudtante",
1037 + "oven",
1038 + "over",
1039 + "oxidant",
1040 + "pablo",
1041 + "pacht",
1042 + "paktafel",
1043 + "pakzadel",
1044 + "paljas",
1045 + "panharing",
1046 + "papfles",
1047 + "paprika",
1048 + "parochie",
1049 + "paus",
1050 + "pauze",
1051 + "paviljoen",
1052 + "peek",
1053 + "pegel",
1054 + "peigeren",
1055 + "pekela",
1056 + "pendant",
1057 + "penibel",
1058 + "pepmiddel",
1059 + "peptalk",
1060 + "periferie",
1061 + "perron",
1062 + "pessarium",
1063 + "peter",
1064 + "petfles",
1065 + "petgat",
1066 + "peuk",
1067 + "pfeifer",
1068 + "picknick",
1069 + "pief",
1070 + "pieneman",
1071 + "pijlkruid",
1072 + "pijnacker",
1073 + "pijpelink",
1074 + "pikdonker",
1075 + "pikeer",
1076 + "pilaar",
1077 + "pionier",
1078 + "pipet",
1079 + "piscine",
1080 + "pissebed",
1081 + "pitchen",
1082 + "pixel",
1083 + "plamuren",
1084 + "plan",
1085 + "plausibel",
1086 + "plegen",
1087 + "plempen",
1088 + "pleonasme",
1089 + "plezant",
1090 + "podoloog",
1091 + "pofmouw",
1092 + "pokdalig",
1093 + "ponywagen",
1094 + "popachtig",
1095 + "popidool",
1096 + "porren",
1097 + "positie",
1098 + "potten",
1099 + "pralen",
1100 + "prezen",
1101 + "prijzen",
1102 + "privaat",
1103 + "proef",
1104 + "prooi",
1105 + "prozawerk",
1106 + "pruik",
1107 + "prul",
1108 + "publiceer",
1109 + "puck",
1110 + "puilen",
1111 + "pukkelig",
1112 + "pulveren",
1113 + "pupil",
1114 + "puppy",
1115 + "purmerend",
1116 + "pustjens",
1117 + "putemmer",
1118 + "puzzelaar",
1119 + "queenie",
1120 + "quiche",
1121 + "raam",
1122 + "raar",
1123 + "raat",
1124 + "raes",
1125 + "ralf",
1126 + "rally",
1127 + "ramona",
1128 + "ramselaar",
1129 + "ranonkel",
1130 + "rapen",
1131 + "rapunzel",
1132 + "rarekiek",
1133 + "rarigheid",
1134 + "rattenhol",
1135 + "ravage",
1136 + "reactie",
1137 + "recreant",
1138 + "redacteur",
1139 + "redster",
1140 + "reewild",
1141 + "regie",
1142 + "reijnders",
1143 + "rein",
1144 + "replica",
1145 + "revanche",
1146 + "rigide",
1147 + "rijbaan",
1148 + "rijdansen",
1149 + "rijgen",
1150 + "rijkdom",
1151 + "rijles",
1152 + "rijnwijn",
1153 + "rijpma",
1154 + "rijstafel",
1155 + "rijtaak",
1156 + "rijzwepen",
1157 + "rioleer",
1158 + "ripdeal",
1159 + "riphagen",
1160 + "riskant",
1161 + "rits",
1162 + "rivaal",
1163 + "robbedoes",
1164 + "robot",
1165 + "rockact",
1166 + "rodijk",
1167 + "rogier",
1168 + "rohypnol",
1169 + "rollaag",
1170 + "rolpaal",
1171 + "roltafel",
1172 + "roof",
1173 + "roon",
1174 + "roppen",
1175 + "rosbief",
1176 + "rosharig",
1177 + "rosielle",
1178 + "rotan",
1179 + "rotleven",
1180 + "rotten",
1181 + "rotvaart",
1182 + "royaal",
1183 + "royeer",
1184 + "rubato",
1185 + "ruby",
1186 + "ruche",
1187 + "rudge",
1188 + "ruggetje",
1189 + "rugnummer",
1190 + "rugpijn",
1191 + "rugtitel",
1192 + "rugzak",
1193 + "ruilbaar",
1194 + "ruis",
1195 + "ruit",
1196 + "rukwind",
1197 + "rulijs",
1198 + "rumoeren",
1199 + "rumsdorp",
1200 + "rumtaart",
1201 + "runnen",
1202 + "russchen",
1203 + "ruwkruid",
1204 + "saboteer",
1205 + "saksisch",
1206 + "salade",
1207 + "salpeter",
1208 + "sambabal",
1209 + "samsam",
1210 + "satelliet",
1211 + "satineer",
1212 + "saus",
1213 + "scampi",
1214 + "scarabee",
1215 + "scenario",
1216 + "schobben",
1217 + "schubben",
1218 + "scout",
1219 + "secessie",
1220 + "secondair",
1221 + "seculair",
1222 + "sediment",
1223 + "seeland",
1224 + "settelen",
1225 + "setwinst",
1226 + "sheriff",
1227 + "shiatsu",
1228 + "siciliaan",
1229 + "sidderaal",
1230 + "sigma",
1231 + "sijben",
1232 + "silvana",
1233 + "simkaart",
1234 + "sinds",
1235 + "situatie",
1236 + "sjaak",
1237 + "sjardijn",
1238 + "sjezen",
1239 + "sjor",
1240 + "skinhead",
1241 + "skylab",
1242 + "slamixen",
1243 + "sleijpen",
1244 + "slijkerig",
1245 + "slordig",
1246 + "slowaak",
1247 + "sluieren",
1248 + "smadelijk",
1249 + "smiecht",
1250 + "smoel",
1251 + "smos",
1252 + "smukken",
1253 + "snackcar",
1254 + "snavel",
1255 + "sneaker",
1256 + "sneu",
1257 + "snijdbaar",
1258 + "snit",
1259 + "snorder",
1260 + "soapbox",
1261 + "soetekouw",
1262 + "soigneren",
1263 + "sojaboon",
1264 + "solo",
1265 + "solvabel",
1266 + "somber",
1267 + "sommatie",
1268 + "soort",
1269 + "soppen",
1270 + "sopraan",
1271 + "soundbar",
1272 + "spanen",
1273 + "spawater",
1274 + "spijgat",
1275 + "spinaal",
1276 + "spionage",
1277 + "spiraal",
1278 + "spleet",
1279 + "splijt",
1280 + "spoed",
1281 + "sporen",
1282 + "spul",
1283 + "spuug",
1284 + "spuw",
1285 + "stalen",
1286 + "standaard",
1287 + "star",
1288 + "stefan",
1289 + "stencil",
1290 + "stijf",
1291 + "stil",
1292 + "stip",
1293 + "stopdas",
1294 + "stoten",
1295 + "stoven",
1296 + "straat",
1297 + "strobbe",
1298 + "strubbel",
1299 + "stucadoor",
1300 + "stuif",
1301 + "stukadoor",
1302 + "subhoofd",
1303 + "subregent",
1304 + "sudoku",
1305 + "sukade",
1306 + "sulfaat",
1307 + "surinaams",
1308 + "suus",
1309 + "syfilis",
1310 + "symboliek",
1311 + "sympathie",
1312 + "synagoge",
1313 + "synchroon",
1314 + "synergie",
1315 + "systeem",
1316 + "taanderij",
1317 + "tabak",
1318 + "tachtig",
1319 + "tackelen",
1320 + "taiwanees",
1321 + "talman",
1322 + "tamheid",
1323 + "tangaslip",
1324 + "taps",
1325 + "tarkan",
1326 + "tarwe",
1327 + "tasman",
1328 + "tatjana",
1329 + "taxameter",
1330 + "teil",
1331 + "teisman",
1332 + "telbaar",
1333 + "telco",
1334 + "telganger",
1335 + "telstar",
1336 + "tenant",
1337 + "tepel",
1338 + "terzet",
1339 + "testament",
1340 + "ticket",
1341 + "tiesinga",
1342 + "tijdelijk",
1343 + "tika",
1344 + "tiksel",
1345 + "tilleman",
1346 + "timbaal",
1347 + "tinsteen",
1348 + "tiplijn",
1349 + "tippelaar",
1350 + "tjirpen",
1351 + "toezeggen",
1352 + "tolbaas",
1353 + "tolgeld",
1354 + "tolhek",
1355 + "tolo",
1356 + "tolpoort",
1357 + "toltarief",
1358 + "tolvrij",
1359 + "tomaat",
1360 + "tondeuse",
1361 + "toog",
1362 + "tooi",
1363 + "toonbaar",
1364 + "toos",
1365 + "topclub",
1366 + "toppen",
1367 + "toptalent",
1368 + "topvrouw",
1369 + "toque",
1370 + "torment",
1371 + "tornado",
1372 + "tosti",
1373 + "totdat",
1374 + "toucheer",
1375 + "toulouse",
1376 + "tournedos",
1377 + "tout",
1378 + "trabant",
1379 + "tragedie",
1380 + "trailer",
1381 + "traject",
1382 + "traktaat",
1383 + "trauma",
1384 + "tray",
1385 + "trechter",
1386 + "tred",
1387 + "tref",
1388 + "treur",
1389 + "troebel",
1390 + "tros",
1391 + "trucage",
1392 + "truffel",
1393 + "tsaar",
1394 + "tucht",
1395 + "tuenter",
1396 + "tuitelig",
1397 + "tukje",
1398 + "tuktuk",
1399 + "tulp",
1400 + "tuma",
1401 + "tureluurs",
1402 + "twijfel",
1403 + "twitteren",
1404 + "tyfoon",
1405 + "typograaf",
1406 + "ugandees",
1407 + "uiachtig",
1408 + "uier",
1409 + "uisnipper",
1410 + "ultiem",
1411 + "unitair",
1412 + "uranium",
1413 + "urbaan",
1414 + "urendag",
1415 + "ursula",
1416 + "uurcirkel",
1417 + "uurglas",
1418 + "uzelf",
1419 + "vaat",
1420 + "vakantie",
1421 + "vakleraar",
1422 + "valbijl",
1423 + "valpartij",
1424 + "valreep",
1425 + "valuatie",
1426 + "vanmiddag",
1427 + "vanonder",
1428 + "varaan",
1429 + "varken",
1430 + "vaten",
1431 + "veenbes",
1432 + "veeteler",
1433 + "velgrem",
1434 + "vellekoop",
1435 + "velvet",
1436 + "veneberg",
1437 + "venlo",
1438 + "vent",
1439 + "venusberg",
1440 + "venw",
1441 + "veredeld",
1442 + "verf",
1443 + "verhaaf",
1444 + "vermaak",
1445 + "vernaaid",
1446 + "verraad",
1447 + "vers",
1448 + "veruit",
1449 + "verzaagd",
1450 + "vetachtig",
1451 + "vetlok",
1452 + "vetmesten",
1453 + "veto",
1454 + "vetrek",
1455 + "vetstaart",
1456 + "vetten",
1457 + "veurink",
1458 + "viaduct",
1459 + "vibrafoon",
1460 + "vicariaat",
1461 + "vieux",
1462 + "vieveen",
1463 + "vijfvoud",
1464 + "villa",
1465 + "vilt",
1466 + "vimmetje",
1467 + "vindbaar",
1468 + "vips",
1469 + "virtueel",
1470 + "visdieven",
1471 + "visee",
1472 + "visie",
1473 + "vlaag",
1474 + "vleugel",
1475 + "vmbo",
1476 + "vocht",
1477 + "voesenek",
1478 + "voicemail",
1479 + "voip",
1480 + "volg",
1481 + "vork",
1482 + "vorselaar",
1483 + "voyeur",
1484 + "vracht",
1485 + "vrekkig",
1486 + "vreten",
1487 + "vrije",
1488 + "vrozen",
1489 + "vrucht",
1490 + "vucht",
1491 + "vugt",
1492 + "vulkaan",
1493 + "vulmiddel",
1494 + "vulva",
1495 + "vuren",
1496 + "waas",
1497 + "wacht",
1498 + "wadvogel",
1499 + "wafel",
1500 + "waffel",
1501 + "walhalla",
1502 + "walnoot",
1503 + "walraven",
1504 + "wals",
1505 + "walvis",
1506 + "wandaad",
1507 + "wanen",
1508 + "wanmolen",
1509 + "want",
1510 + "warklomp",
1511 + "warm",
1512 + "wasachtig",
1513 + "wasteil",
1514 + "watt",
1515 + "webhandel",
1516 + "weblog",
1517 + "webpagina",
1518 + "webzine",
1519 + "wedereis",
1520 + "wedstrijd",
1521 + "weeda",
1522 + "weert",
1523 + "wegmaaien",
1524 + "wegscheer",
1525 + "wekelijks",
1526 + "wekken",
1527 + "wekroep",
1528 + "wektoon",
1529 + "weldaad",
1530 + "welwater",
1531 + "wendbaar",
1532 + "wenkbrauw",
1533 + "wens",
1534 + "wentelaar",
1535 + "wervel",
1536 + "wesseling",
1537 + "wetboek",
1538 + "wetmatig",
1539 + "whirlpool",
1540 + "wijbrands",
1541 + "wijdbeens",
1542 + "wijk",
1543 + "wijnbes",
1544 + "wijting",
1545 + "wild",
1546 + "wimpelen",
1547 + "wingebied",
1548 + "winplaats",
1549 + "winter",
1550 + "winzucht",
1551 + "wipstaart",
1552 + "wisgerhof",
1553 + "withaar",
1554 + "witmaker",
1555 + "wokkel",
1556 + "wolf",
1557 + "wonenden",
1558 + "woning",
1559 + "worden",
1560 + "worp",
1561 + "wortel",
1562 + "wrat",
1563 + "wrijf",
1564 + "wringen",
1565 + "yoghurt",
1566 + "ypsilon",
1567 + "zaaijer",
1568 + "zaak",
1569 + "zacharias",
1570 + "zakelijk",
1571 + "zakkam",
1572 + "zakwater",
1573 + "zalf",
1574 + "zalig",
1575 + "zaniken",
1576 + "zebracode",
1577 + "zeeblauw",
1578 + "zeef",
1579 + "zeegaand",
1580 + "zeeuw",
1581 + "zege",
1582 + "zegje",
1583 + "zeil",
1584 + "zesbaans",
1585 + "zesenhalf",
1586 + "zeskantig",
1587 + "zesmaal",
1588 + "zetbaas",
1589 + "zetpil",
1590 + "zeulen",
1591 + "ziezo",
1592 + "zigzag",
1593 + "zijaltaar",
1594 + "zijbeuk",
1595 + "zijlijn",
1596 + "zijmuur",
1597 + "zijn",
1598 + "zijwaarts",
1599 + "zijzelf",
1600 + "zilt",
1601 + "zimmerman",
1602 + "zinledig",
1603 + "zinnelijk",
1604 + "zionist",
1605 + "zitdag",
1606 + "zitruimte",
1607 + "zitzak",
1608 + "zoal",
1609 + "zodoende",
1610 + "zoekbots",
1611 + "zoem",
1612 + "zoiets",
1613 + "zojuist",
1614 + "zondaar",
1615 + "zotskap",
1616 + "zottebol",
1617 + "zucht",
1618 + "zuivel",
1619 + "zulk",
1620 + "zult",
1621 + "zuster",
1622 + "zuur",
1623 + "zweedijk",
1624 + "zwendel",
1625 + "zwepen",
1626 + "zwiep",
1627 + "zwijmel",
1628 + "zworen"
1629 + ];
1630 +}
\ No newline at end of file
cw_monero/lib/mnemonics/english.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class EnglishMnemonics {
2 + static const words = [
3 + "abbey",
4 + "abducts",
5 + "ability",
6 + "ablaze",
7 + "abnormal",
8 + "abort",
9 + "abrasive",
10 + "absorb",
11 + "abyss",
12 + "academy",
13 + "aces",
14 + "aching",
15 + "acidic",
16 + "acoustic",
17 + "acquire",
18 + "across",
19 + "actress",
20 + "acumen",
21 + "adapt",
22 + "addicted",
23 + "adept",
24 + "adhesive",
25 + "adjust",
26 + "adopt",
27 + "adrenalin",
28 + "adult",
29 + "adventure",
30 + "aerial",
31 + "afar",
32 + "affair",
33 + "afield",
34 + "afloat",
35 + "afoot",
36 + "afraid",
37 + "after",
38 + "against",
39 + "agenda",
40 + "aggravate",
41 + "agile",
42 + "aglow",
43 + "agnostic",
44 + "agony",
45 + "agreed",
46 + "ahead",
47 + "aided",
48 + "ailments",
49 + "aimless",
50 + "airport",
51 + "aisle",
52 + "ajar",
53 + "akin",
54 + "alarms",
55 + "album",
56 + "alchemy",
57 + "alerts",
58 + "algebra",
59 + "alkaline",
60 + "alley",
61 + "almost",
62 + "aloof",
63 + "alpine",
64 + "already",
65 + "also",
66 + "altitude",
67 + "alumni",
68 + "always",
69 + "amaze",
70 + "ambush",
71 + "amended",
72 + "amidst",
73 + "ammo",
74 + "amnesty",
75 + "among",
76 + "amply",
77 + "amused",
78 + "anchor",
79 + "android",
80 + "anecdote",
81 + "angled",
82 + "ankle",
83 + "annoyed",
84 + "answers",
85 + "antics",
86 + "anvil",
87 + "anxiety",
88 + "anybody",
89 + "apart",
90 + "apex",
91 + "aphid",
92 + "aplomb",
93 + "apology",
94 + "apply",
95 + "apricot",
96 + "aptitude",
97 + "aquarium",
98 + "arbitrary",
99 + "archer",
100 + "ardent",
101 + "arena",
102 + "argue",
103 + "arises",
104 + "army",
105 + "around",
106 + "arrow",
107 + "arsenic",
108 + "artistic",
109 + "ascend",
110 + "ashtray",
111 + "aside",
112 + "asked",
113 + "asleep",
114 + "aspire",
115 + "assorted",
116 + "asylum",
117 + "athlete",
118 + "atlas",
119 + "atom",
120 + "atrium",
121 + "attire",
122 + "auburn",
123 + "auctions",
124 + "audio",
125 + "august",
126 + "aunt",
127 + "austere",
128 + "autumn",
129 + "avatar",
130 + "avidly",
131 + "avoid",
132 + "awakened",
133 + "awesome",
134 + "awful",
135 + "awkward",
136 + "awning",
137 + "awoken",
138 + "axes",
139 + "axis",
140 + "axle",
141 + "aztec",
142 + "azure",
143 + "baby",
144 + "bacon",
145 + "badge",
146 + "baffles",
147 + "bagpipe",
148 + "bailed",
149 + "bakery",
150 + "balding",
151 + "bamboo",
152 + "banjo",
153 + "baptism",
154 + "basin",
155 + "batch",
156 + "bawled",
157 + "bays",
158 + "because",
159 + "beer",
160 + "befit",
161 + "begun",
162 + "behind",
163 + "being",
164 + "below",
165 + "bemused",
166 + "benches",
167 + "berries",
168 + "bested",
169 + "betting",
170 + "bevel",
171 + "beware",
172 + "beyond",
173 + "bias",
174 + "bicycle",
175 + "bids",
176 + "bifocals",
177 + "biggest",
178 + "bikini",
179 + "bimonthly",
180 + "binocular",
181 + "biology",
182 + "biplane",
183 + "birth",
184 + "biscuit",
185 + "bite",
186 + "biweekly",
187 + "blender",
188 + "blip",
189 + "bluntly",
190 + "boat",
191 + "bobsled",
192 + "bodies",
193 + "bogeys",
194 + "boil",
195 + "boldly",
196 + "bomb",
197 + "border",
198 + "boss",
199 + "both",
200 + "bounced",
201 + "bovine",
202 + "bowling",
203 + "boxes",
204 + "boyfriend",
205 + "broken",
206 + "brunt",
207 + "bubble",
208 + "buckets",
209 + "budget",
210 + "buffet",
211 + "bugs",
212 + "building",
213 + "bulb",
214 + "bumper",
215 + "bunch",
216 + "business",
217 + "butter",
218 + "buying",
219 + "buzzer",
220 + "bygones",
221 + "byline",
222 + "bypass",
223 + "cabin",
224 + "cactus",
225 + "cadets",
226 + "cafe",
227 + "cage",
228 + "cajun",
229 + "cake",
230 + "calamity",
231 + "camp",
232 + "candy",
233 + "casket",
234 + "catch",
235 + "cause",
236 + "cavernous",
237 + "cease",
238 + "cedar",
239 + "ceiling",
240 + "cell",
241 + "cement",
242 + "cent",
243 + "certain",
244 + "chlorine",
245 + "chrome",
246 + "cider",
247 + "cigar",
248 + "cinema",
249 + "circle",
250 + "cistern",
251 + "citadel",
252 + "civilian",
253 + "claim",
254 + "click",
255 + "clue",
256 + "coal",
257 + "cobra",
258 + "cocoa",
259 + "code",
260 + "coexist",
261 + "coffee",
262 + "cogs",
263 + "cohesive",
264 + "coils",
265 + "colony",
266 + "comb",
267 + "cool",
268 + "copy",
269 + "corrode",
270 + "costume",
271 + "cottage",
272 + "cousin",
273 + "cowl",
274 + "criminal",
275 + "cube",
276 + "cucumber",
277 + "cuddled",
278 + "cuffs",
279 + "cuisine",
280 + "cunning",
281 + "cupcake",
282 + "custom",
283 + "cycling",
284 + "cylinder",
285 + "cynical",
286 + "dabbing",
287 + "dads",
288 + "daft",
289 + "dagger",
290 + "daily",
291 + "damp",
292 + "dangerous",
293 + "dapper",
294 + "darted",
295 + "dash",
296 + "dating",
297 + "dauntless",
298 + "dawn",
299 + "daytime",
300 + "dazed",
301 + "debut",
302 + "decay",
303 + "dedicated",
304 + "deepest",
305 + "deftly",
306 + "degrees",
307 + "dehydrate",
308 + "deity",
309 + "dejected",
310 + "delayed",
311 + "demonstrate",
312 + "dented",
313 + "deodorant",
314 + "depth",
315 + "desk",
316 + "devoid",
317 + "dewdrop",
318 + "dexterity",
319 + "dialect",
320 + "dice",
321 + "diet",
322 + "different",
323 + "digit",
324 + "dilute",
325 + "dime",
326 + "dinner",
327 + "diode",
328 + "diplomat",
329 + "directed",
330 + "distance",
331 + "ditch",
332 + "divers",
333 + "dizzy",
334 + "doctor",
335 + "dodge",
336 + "does",
337 + "dogs",
338 + "doing",
339 + "dolphin",
340 + "domestic",
341 + "donuts",
342 + "doorway",
343 + "dormant",
344 + "dosage",
345 + "dotted",
346 + "double",
347 + "dove",
348 + "down",
349 + "dozen",
350 + "dreams",
351 + "drinks",
352 + "drowning",
353 + "drunk",
354 + "drying",
355 + "dual",
356 + "dubbed",
357 + "duckling",
358 + "dude",
359 + "duets",
360 + "duke",
361 + "dullness",
362 + "dummy",
363 + "dunes",
364 + "duplex",
365 + "duration",
366 + "dusted",
367 + "duties",
368 + "dwarf",
369 + "dwelt",
370 + "dwindling",
371 + "dying",
372 + "dynamite",
373 + "dyslexic",
374 + "each",
375 + "eagle",
376 + "earth",
377 + "easy",
378 + "eating",
379 + "eavesdrop",
380 + "eccentric",
381 + "echo",
382 + "eclipse",
383 + "economics",
384 + "ecstatic",
385 + "eden",
386 + "edgy",
387 + "edited",
388 + "educated",
389 + "eels",
390 + "efficient",
391 + "eggs",
392 + "egotistic",
393 + "eight",
394 + "either",
395 + "eject",
396 + "elapse",
397 + "elbow",
398 + "eldest",
399 + "eleven",
400 + "elite",
401 + "elope",
402 + "else",
403 + "eluded",
404 + "emails",
405 + "ember",
406 + "emerge",
407 + "emit",
408 + "emotion",
409 + "empty",
410 + "emulate",
411 + "energy",
412 + "enforce",
413 + "enhanced",
414 + "enigma",
415 + "enjoy",
416 + "enlist",
417 + "enmity",
418 + "enough",
419 + "enraged",
420 + "ensign",
421 + "entrance",
422 + "envy",
423 + "epoxy",
424 + "equip",
425 + "erase",
426 + "erected",
427 + "erosion",
428 + "error",
429 + "eskimos",
430 + "espionage",
431 + "essential",
432 + "estate",
433 + "etched",
434 + "eternal",
435 + "ethics",
436 + "etiquette",
437 + "evaluate",
438 + "evenings",
439 + "evicted",
440 + "evolved",
441 + "examine",
442 + "excess",
443 + "exhale",
444 + "exit",
445 + "exotic",
446 + "exquisite",
447 + "extra",
448 + "exult",
449 + "fabrics",
450 + "factual",
451 + "fading",
452 + "fainted",
453 + "faked",
454 + "fall",
455 + "family",
456 + "fancy",
457 + "farming",
458 + "fatal",
459 + "faulty",
460 + "fawns",
461 + "faxed",
462 + "fazed",
463 + "feast",
464 + "february",
465 + "federal",
466 + "feel",
467 + "feline",
468 + "females",
469 + "fences",
470 + "ferry",
471 + "festival",
472 + "fetches",
473 + "fever",
474 + "fewest",
475 + "fiat",
476 + "fibula",
477 + "fictional",
478 + "fidget",
479 + "fierce",
480 + "fifteen",
481 + "fight",
482 + "films",
483 + "firm",
484 + "fishing",
485 + "fitting",
486 + "five",
487 + "fixate",
488 + "fizzle",
489 + "fleet",
490 + "flippant",
491 + "flying",
492 + "foamy",
493 + "focus",
494 + "foes",
495 + "foggy",
496 + "foiled",
497 + "folding",
498 + "fonts",
499 + "foolish",
500 + "fossil",
501 + "fountain",
502 + "fowls",
503 + "foxes",
504 + "foyer",
505 + "framed",
506 + "friendly",
507 + "frown",
508 + "fruit",
509 + "frying",
510 + "fudge",
511 + "fuel",
512 + "fugitive",
513 + "fully",
514 + "fuming",
515 + "fungal",
516 + "furnished",
517 + "fuselage",
518 + "future",
519 + "fuzzy",
520 + "gables",
521 + "gadget",
522 + "gags",
523 + "gained",
524 + "galaxy",
525 + "gambit",
526 + "gang",
527 + "gasp",
528 + "gather",
529 + "gauze",
530 + "gave",
531 + "gawk",
532 + "gaze",
533 + "gearbox",
534 + "gecko",
535 + "geek",
536 + "gels",
537 + "gemstone",
538 + "general",
539 + "geometry",
540 + "germs",
541 + "gesture",
542 + "getting",
543 + "geyser",
544 + "ghetto",
545 + "ghost",
546 + "giant",
547 + "giddy",
548 + "gifts",
549 + "gigantic",
550 + "gills",
551 + "gimmick",
552 + "ginger",
553 + "girth",
554 + "giving",
555 + "glass",
556 + "gleeful",
557 + "glide",
558 + "gnaw",
559 + "gnome",
560 + "goat",
561 + "goblet",
562 + "godfather",
563 + "goes",
564 + "goggles",
565 + "going",
566 + "goldfish",
567 + "gone",
568 + "goodbye",
569 + "gopher",
570 + "gorilla",
571 + "gossip",
572 + "gotten",
573 + "gourmet",
574 + "governing",
575 + "gown",
576 + "greater",
577 + "grunt",
578 + "guarded",
579 + "guest",
580 + "guide",
581 + "gulp",
582 + "gumball",
583 + "guru",
584 + "gusts",
585 + "gutter",
586 + "guys",
587 + "gymnast",
588 + "gypsy",
589 + "gyrate",
590 + "habitat",
591 + "hacksaw",
592 + "haggled",
593 + "hairy",
594 + "hamburger",
595 + "happens",
596 + "hashing",
597 + "hatchet",
598 + "haunted",
599 + "having",
600 + "hawk",
601 + "haystack",
602 + "hazard",
603 + "hectare",
604 + "hedgehog",
605 + "heels",
606 + "hefty",
607 + "height",
608 + "hemlock",
609 + "hence",
610 + "heron",
611 + "hesitate",
612 + "hexagon",
613 + "hickory",
614 + "hiding",
615 + "highway",
616 + "hijack",
617 + "hiker",
618 + "hills",
619 + "himself",
620 + "hinder",
621 + "hippo",
622 + "hire",
623 + "history",
624 + "hitched",
625 + "hive",
626 + "hoax",
627 + "hobby",
628 + "hockey",
629 + "hoisting",
630 + "hold",
631 + "honked",
632 + "hookup",
633 + "hope",
634 + "hornet",
635 + "hospital",
636 + "hotel",
637 + "hounded",
638 + "hover",
639 + "howls",
640 + "hubcaps",
641 + "huddle",
642 + "huge",
643 + "hull",
644 + "humid",
645 + "hunter",
646 + "hurried",
647 + "husband",
648 + "huts",
649 + "hybrid",
650 + "hydrogen",
651 + "hyper",
652 + "iceberg",
653 + "icing",
654 + "icon",
655 + "identity",
656 + "idiom",
657 + "idled",
658 + "idols",
659 + "igloo",
660 + "ignore",
661 + "iguana",
662 + "illness",
663 + "imagine",
664 + "imbalance",
665 + "imitate",
666 + "impel",
667 + "inactive",
668 + "inbound",
669 + "incur",
670 + "industrial",
671 + "inexact",
672 + "inflamed",
673 + "ingested",
674 + "initiate",
675 + "injury",
676 + "inkling",
677 + "inline",
678 + "inmate",
679 + "innocent",
680 + "inorganic",
681 + "input",
682 + "inquest",
683 + "inroads",
684 + "insult",
685 + "intended",
686 + "inundate",
687 + "invoke",
688 + "inwardly",
689 + "ionic",
690 + "irate",
691 + "iris",
692 + "irony",
693 + "irritate",
694 + "island",
695 + "isolated",
696 + "issued",
697 + "italics",
698 + "itches",
699 + "items",
700 + "itinerary",
701 + "itself",
702 + "ivory",
703 + "jabbed",
704 + "jackets",
705 + "jaded",
706 + "jagged",
707 + "jailed",
708 + "jamming",
709 + "january",
710 + "jargon",
711 + "jaunt",
712 + "javelin",
713 + "jaws",
714 + "jazz",
715 + "jeans",
716 + "jeers",
717 + "jellyfish",
718 + "jeopardy",
719 + "jerseys",
720 + "jester",
721 + "jetting",
722 + "jewels",
723 + "jigsaw",
724 + "jingle",
725 + "jittery",
726 + "jive",
727 + "jobs",
728 + "jockey",
729 + "jogger",
730 + "joining",
731 + "joking",
732 + "jolted",
733 + "jostle",
734 + "journal",
735 + "joyous",
736 + "jubilee",
737 + "judge",
738 + "juggled",
739 + "juicy",
740 + "jukebox",
741 + "july",
742 + "jump",
743 + "junk",
744 + "jury",
745 + "justice",
746 + "juvenile",
747 + "kangaroo",
748 + "karate",
749 + "keep",
750 + "kennel",
751 + "kept",
752 + "kernels",
753 + "kettle",
754 + "keyboard",
755 + "kickoff",
756 + "kidneys",
757 + "king",
758 + "kiosk",
759 + "kisses",
760 + "kitchens",
761 + "kiwi",
762 + "knapsack",
763 + "knee",
764 + "knife",
765 + "knowledge",
766 + "knuckle",
767 + "koala",
768 + "laboratory",
769 + "ladder",
770 + "lagoon",
771 + "lair",
772 + "lakes",
773 + "lamb",
774 + "language",
775 + "laptop",
776 + "large",
777 + "last",
778 + "later",
779 + "launching",
780 + "lava",
781 + "lawsuit",
782 + "layout",
783 + "lazy",
784 + "lectures",
785 + "ledge",
786 + "leech",
787 + "left",
788 + "legion",
789 + "leisure",
790 + "lemon",
791 + "lending",
792 + "leopard",
793 + "lesson",
794 + "lettuce",
795 + "lexicon",
796 + "liar",
797 + "library",
798 + "licks",
799 + "lids",
800 + "lied",
801 + "lifestyle",
802 + "light",
803 + "likewise",
804 + "lilac",
805 + "limits",
806 + "linen",
807 + "lion",
808 + "lipstick",
809 + "liquid",
810 + "listen",
811 + "lively",
812 + "loaded",
813 + "lobster",
814 + "locker",
815 + "lodge",
816 + "lofty",
817 + "logic",
818 + "loincloth",
819 + "long",
820 + "looking",
821 + "lopped",
822 + "lordship",
823 + "losing",
824 + "lottery",
825 + "loudly",
826 + "love",
827 + "lower",
828 + "loyal",
829 + "lucky",
830 + "luggage",
831 + "lukewarm",
832 + "lullaby",
833 + "lumber",
834 + "lunar",
835 + "lurk",
836 + "lush",
837 + "luxury",
838 + "lymph",
839 + "lynx",
840 + "lyrics",
841 + "macro",
842 + "madness",
843 + "magically",
844 + "mailed",
845 + "major",
846 + "makeup",
847 + "malady",
848 + "mammal",
849 + "maps",
850 + "masterful",
851 + "match",
852 + "maul",
853 + "maverick",
854 + "maximum",
855 + "mayor",
856 + "maze",
857 + "meant",
858 + "mechanic",
859 + "medicate",
860 + "meeting",
861 + "megabyte",
862 + "melting",
863 + "memoir",
864 + "menu",
865 + "merger",
866 + "mesh",
867 + "metro",
868 + "mews",
869 + "mice",
870 + "midst",
871 + "mighty",
872 + "mime",
873 + "mirror",
874 + "misery",
875 + "mittens",
876 + "mixture",
877 + "moat",
878 + "mobile",
879 + "mocked",
880 + "mohawk",
881 + "moisture",
882 + "molten",
883 + "moment",
884 + "money",
885 + "moon",
886 + "mops",
887 + "morsel",
888 + "mostly",
889 + "motherly",
890 + "mouth",
891 + "movement",
892 + "mowing",
893 + "much",
894 + "muddy",
895 + "muffin",
896 + "mugged",
897 + "mullet",
898 + "mumble",
899 + "mundane",
900 + "muppet",
901 + "mural",
902 + "musical",
903 + "muzzle",
904 + "myriad",
905 + "mystery",
906 + "myth",
907 + "nabbing",
908 + "nagged",
909 + "nail",
910 + "names",
911 + "nanny",
912 + "napkin",
913 + "narrate",
914 + "nasty",
915 + "natural",
916 + "nautical",
917 + "navy",
918 + "nearby",
919 + "necklace",
920 + "needed",
921 + "negative",
922 + "neither",
923 + "neon",
924 + "nephew",
925 + "nerves",
926 + "nestle",
927 + "network",
928 + "neutral",
929 + "never",
930 + "newt",
931 + "nexus",
932 + "nibs",
933 + "niche",
934 + "niece",
935 + "nifty",
936 + "nightly",
937 + "nimbly",
938 + "nineteen",
939 + "nirvana",
940 + "nitrogen",
941 + "nobody",
942 + "nocturnal",
943 + "nodes",
944 + "noises",
945 + "nomad",
946 + "noodles",
947 + "northern",
948 + "nostril",
949 + "noted",
950 + "nouns",
951 + "novelty",
952 + "nowhere",
953 + "nozzle",
954 + "nuance",
955 + "nucleus",
956 + "nudged",
957 + "nugget",
958 + "nuisance",
959 + "null",
960 + "number",
961 + "nuns",
962 + "nurse",
963 + "nutshell",
964 + "nylon",
965 + "oaks",
966 + "oars",
967 + "oasis",
968 + "oatmeal",
969 + "obedient",
970 + "object",
971 + "obliged",
972 + "obnoxious",
973 + "observant",
974 + "obtains",
975 + "obvious",
976 + "occur",
977 + "ocean",
978 + "october",
979 + "odds",
980 + "odometer",
981 + "offend",
982 + "often",
983 + "oilfield",
984 + "ointment",
985 + "okay",
986 + "older",
987 + "olive",
988 + "olympics",
989 + "omega",
990 + "omission",
991 + "omnibus",
992 + "onboard",
993 + "oncoming",
994 + "oneself",
995 + "ongoing",
996 + "onion",
997 + "online",
998 + "onslaught",
999 + "onto",
1000 + "onward",
1001 + "oozed",
1002 + "opacity",
1003 + "opened",
1004 + "opposite",
1005 + "optical",
1006 + "opus",
1007 + "orange",
1008 + "orbit",
1009 + "orchid",
1010 + "orders",
1011 + "organs",
1012 + "origin",
1013 + "ornament",
1014 + "orphans",
1015 + "oscar",
1016 + "ostrich",
1017 + "otherwise",
1018 + "otter",
1019 + "ouch",
1020 + "ought",
1021 + "ounce",
1022 + "ourselves",
1023 + "oust",
1024 + "outbreak",
1025 + "oval",
1026 + "oven",
1027 + "owed",
1028 + "owls",
1029 + "owner",
1030 + "oxidant",
1031 + "oxygen",
1032 + "oyster",
1033 + "ozone",
1034 + "pact",
1035 + "paddles",
1036 + "pager",
1037 + "pairing",
1038 + "palace",
1039 + "pamphlet",
1040 + "pancakes",
1041 + "paper",
1042 + "paradise",
1043 + "pastry",
1044 + "patio",
1045 + "pause",
1046 + "pavements",
1047 + "pawnshop",
1048 + "payment",
1049 + "peaches",
1050 + "pebbles",
1051 + "peculiar",
1052 + "pedantic",
1053 + "peeled",
1054 + "pegs",
1055 + "pelican",
1056 + "pencil",
1057 + "people",
1058 + "pepper",
1059 + "perfect",
1060 + "pests",
1061 + "petals",
1062 + "phase",
1063 + "pheasants",
1064 + "phone",
1065 + "phrases",
1066 + "physics",
1067 + "piano",
1068 + "picked",
1069 + "pierce",
1070 + "pigment",
1071 + "piloted",
1072 + "pimple",
1073 + "pinched",
1074 + "pioneer",
1075 + "pipeline",
1076 + "pirate",
1077 + "pistons",
1078 + "pitched",
1079 + "pivot",
1080 + "pixels",
1081 + "pizza",
1082 + "playful",
1083 + "pledge",
1084 + "pliers",
1085 + "plotting",
1086 + "plus",
1087 + "plywood",
1088 + "poaching",
1089 + "pockets",
1090 + "podcast",
1091 + "poetry",
1092 + "point",
1093 + "poker",
1094 + "polar",
1095 + "ponies",
1096 + "pool",
1097 + "popular",
1098 + "portents",
1099 + "possible",
1100 + "potato",
1101 + "pouch",
1102 + "poverty",
1103 + "powder",
1104 + "pram",
1105 + "present",
1106 + "pride",
1107 + "problems",
1108 + "pruned",
1109 + "prying",
1110 + "psychic",
1111 + "public",
1112 + "puck",
1113 + "puddle",
1114 + "puffin",
1115 + "pulp",
1116 + "pumpkins",
1117 + "punch",
1118 + "puppy",
1119 + "purged",
1120 + "push",
1121 + "putty",
1122 + "puzzled",
1123 + "pylons",
1124 + "pyramid",
1125 + "python",
1126 + "queen",
1127 + "quick",
1128 + "quote",
1129 + "rabbits",
1130 + "racetrack",
1131 + "radar",
1132 + "rafts",
1133 + "rage",
1134 + "railway",
1135 + "raking",
1136 + "rally",
1137 + "ramped",
1138 + "randomly",
1139 + "rapid",
1140 + "rarest",
1141 + "rash",
1142 + "rated",
1143 + "ravine",
1144 + "rays",
1145 + "razor",
1146 + "react",
1147 + "rebel",
1148 + "recipe",
1149 + "reduce",
1150 + "reef",
1151 + "refer",
1152 + "regular",
1153 + "reheat",
1154 + "reinvest",
1155 + "rejoices",
1156 + "rekindle",
1157 + "relic",
1158 + "remedy",
1159 + "renting",
1160 + "reorder",
1161 + "repent",
1162 + "request",
1163 + "reruns",
1164 + "rest",
1165 + "return",
1166 + "reunion",
1167 + "revamp",
1168 + "rewind",
1169 + "rhino",
1170 + "rhythm",
1171 + "ribbon",
1172 + "richly",
1173 + "ridges",
1174 + "rift",
1175 + "rigid",
1176 + "rims",
1177 + "ringing",
1178 + "riots",
1179 + "ripped",
1180 + "rising",
1181 + "ritual",
1182 + "river",
1183 + "roared",
1184 + "robot",
1185 + "rockets",
1186 + "rodent",
1187 + "rogue",
1188 + "roles",
1189 + "romance",
1190 + "roomy",
1191 + "roped",
1192 + "roster",
1193 + "rotate",
1194 + "rounded",
1195 + "rover",
1196 + "rowboat",
1197 + "royal",
1198 + "ruby",
1199 + "rudely",
1200 + "ruffled",
1201 + "rugged",
1202 + "ruined",
1203 + "ruling",
1204 + "rumble",
1205 + "runway",
1206 + "rural",
1207 + "rustled",
1208 + "ruthless",
1209 + "sabotage",
1210 + "sack",
1211 + "sadness",
1212 + "safety",
1213 + "saga",
1214 + "sailor",
1215 + "sake",
1216 + "salads",
1217 + "sample",
1218 + "sanity",
1219 + "sapling",
1220 + "sarcasm",
1221 + "sash",
1222 + "satin",
1223 + "saucepan",
1224 + "saved",
1225 + "sawmill",
1226 + "saxophone",
1227 + "sayings",
1228 + "scamper",
1229 + "scenic",
1230 + "school",
1231 + "science",
1232 + "scoop",
1233 + "scrub",
1234 + "scuba",
1235 + "seasons",
1236 + "second",
1237 + "sedan",
1238 + "seeded",
1239 + "segments",
1240 + "seismic",
1241 + "selfish",
1242 + "semifinal",
1243 + "sensible",
1244 + "september",
1245 + "sequence",
1246 + "serving",
1247 + "session",
1248 + "setup",
1249 + "seventh",
1250 + "sewage",
1251 + "shackles",
1252 + "shelter",
1253 + "shipped",
1254 + "shocking",
1255 + "shrugged",
1256 + "shuffled",
1257 + "shyness",
1258 + "siblings",
1259 + "sickness",
1260 + "sidekick",
1261 + "sieve",
1262 + "sifting",
1263 + "sighting",
1264 + "silk",
1265 + "simplest",
1266 + "sincerely",
1267 + "sipped",
1268 + "siren",
1269 + "situated",
1270 + "sixteen",
1271 + "sizes",
1272 + "skater",
1273 + "skew",
1274 + "skirting",
1275 + "skulls",
1276 + "skydive",
1277 + "slackens",
1278 + "sleepless",
1279 + "slid",
1280 + "slower",
1281 + "slug",
1282 + "smash",
1283 + "smelting",
1284 + "smidgen",
1285 + "smog",
1286 + "smuggled",
1287 + "snake",
1288 + "sneeze",
1289 + "sniff",
1290 + "snout",
1291 + "snug",
1292 + "soapy",
1293 + "sober",
1294 + "soccer",
1295 + "soda",
1296 + "software",
1297 + "soggy",
1298 + "soil",
1299 + "solved",
1300 + "somewhere",
1301 + "sonic",
1302 + "soothe",
1303 + "soprano",
1304 + "sorry",
1305 + "southern",
1306 + "sovereign",
1307 + "sowed",
1308 + "soya",
1309 + "space",
1310 + "speedy",
1311 + "sphere",
1312 + "spiders",
1313 + "splendid",
1314 + "spout",
1315 + "sprig",
1316 + "spud",
1317 + "spying",
1318 + "square",
1319 + "stacking",
1320 + "stellar",
1321 + "stick",
1322 + "stockpile",
1323 + "strained",
1324 + "stunning",
1325 + "stylishly",
1326 + "subtly",
1327 + "succeed",
1328 + "suddenly",
1329 + "suede",
1330 + "suffice",
1331 + "sugar",
1332 + "suitcase",
1333 + "sulking",
1334 + "summon",
1335 + "sunken",
1336 + "superior",
1337 + "surfer",
1338 + "sushi",
1339 + "suture",
1340 + "swagger",
1341 + "swept",
1342 + "swiftly",
1343 + "sword",
1344 + "swung",
1345 + "syllabus",
1346 + "symptoms",
1347 + "syndrome",
1348 + "syringe",
1349 + "system",
1350 + "taboo",
1351 + "tacit",
1352 + "tadpoles",
1353 + "tagged",
1354 + "tail",
1355 + "taken",
1356 + "talent",
1357 + "tamper",
1358 + "tanks",
1359 + "tapestry",
1360 + "tarnished",
1361 + "tasked",
1362 + "tattoo",
1363 + "taunts",
1364 + "tavern",
1365 + "tawny",
1366 + "taxi",
1367 + "teardrop",
1368 + "technical",
1369 + "tedious",
1370 + "teeming",
1371 + "tell",
1372 + "template",
1373 + "tender",
1374 + "tepid",
1375 + "tequila",
1376 + "terminal",
1377 + "testing",
1378 + "tether",
1379 + "textbook",
1380 + "thaw",
1381 + "theatrics",
1382 + "thirsty",
1383 + "thorn",
1384 + "threaten",
1385 + "thumbs",
1386 + "thwart",
1387 + "ticket",
1388 + "tidy",
1389 + "tiers",
1390 + "tiger",
1391 + "tilt",
1392 + "timber",
1393 + "tinted",
1394 + "tipsy",
1395 + "tirade",
1396 + "tissue",
1397 + "titans",
1398 + "toaster",
1399 + "tobacco",
1400 + "today",
1401 + "toenail",
1402 + "toffee",
1403 + "together",
1404 + "toilet",
1405 + "token",
1406 + "tolerant",
1407 + "tomorrow",
1408 + "tonic",
1409 + "toolbox",
1410 + "topic",
1411 + "torch",
1412 + "tossed",
1413 + "total",
1414 + "touchy",
1415 + "towel",
1416 + "toxic",
1417 + "toyed",
1418 + "trash",
1419 + "trendy",
1420 + "tribal",
1421 + "trolling",
1422 + "truth",
1423 + "trying",
1424 + "tsunami",
1425 + "tubes",
1426 + "tucks",
1427 + "tudor",
1428 + "tuesday",
1429 + "tufts",
1430 + "tugs",
1431 + "tuition",
1432 + "tulips",
1433 + "tumbling",
1434 + "tunnel",
1435 + "turnip",
1436 + "tusks",
1437 + "tutor",
1438 + "tuxedo",
1439 + "twang",
1440 + "tweezers",
1441 + "twice",
1442 + "twofold",
1443 + "tycoon",
1444 + "typist",
1445 + "tyrant",
1446 + "ugly",
1447 + "ulcers",
1448 + "ultimate",
1449 + "umbrella",
1450 + "umpire",
1451 + "unafraid",
1452 + "unbending",
1453 + "uncle",
1454 + "under",
1455 + "uneven",
1456 + "unfit",
1457 + "ungainly",
1458 + "unhappy",
1459 + "union",
1460 + "unjustly",
1461 + "unknown",
1462 + "unlikely",
1463 + "unmask",
1464 + "unnoticed",
1465 + "unopened",
1466 + "unplugs",
1467 + "unquoted",
1468 + "unrest",
1469 + "unsafe",
1470 + "until",
1471 + "unusual",
1472 + "unveil",
1473 + "unwind",
1474 + "unzip",
1475 + "upbeat",
1476 + "upcoming",
1477 + "update",
1478 + "upgrade",
1479 + "uphill",
1480 + "upkeep",
1481 + "upload",
1482 + "upon",
1483 + "upper",
1484 + "upright",
1485 + "upstairs",
1486 + "uptight",
1487 + "upwards",
1488 + "urban",
1489 + "urchins",
1490 + "urgent",
1491 + "usage",
1492 + "useful",
1493 + "usher",
1494 + "using",
1495 + "usual",
1496 + "utensils",
1497 + "utility",
1498 + "utmost",
1499 + "utopia",
1500 + "uttered",
1501 + "vacation",
1502 + "vague",
1503 + "vain",
1504 + "value",
1505 + "vampire",
1506 + "vane",
1507 + "vapidly",
1508 + "vary",
1509 + "vastness",
1510 + "vats",
1511 + "vaults",
1512 + "vector",
1513 + "veered",
1514 + "vegan",
1515 + "vehicle",
1516 + "vein",
1517 + "velvet",
1518 + "venomous",
1519 + "verification",
1520 + "vessel",
1521 + "veteran",
1522 + "vexed",
1523 + "vials",
1524 + "vibrate",
1525 + "victim",
1526 + "video",
1527 + "viewpoint",
1528 + "vigilant",
1529 + "viking",
1530 + "village",
1531 + "vinegar",
1532 + "violin",
1533 + "vipers",
1534 + "virtual",
1535 + "visited",
1536 + "vitals",
1537 + "vivid",
1538 + "vixen",
1539 + "vocal",
1540 + "vogue",
1541 + "voice",
1542 + "volcano",
1543 + "vortex",
1544 + "voted",
1545 + "voucher",
1546 + "vowels",
1547 + "voyage",
1548 + "vulture",
1549 + "wade",
1550 + "waffle",
1551 + "wagtail",
1552 + "waist",
1553 + "waking",
1554 + "wallets",
1555 + "wanted",
1556 + "warped",
1557 + "washing",
1558 + "water",
1559 + "waveform",
1560 + "waxing",
1561 + "wayside",
1562 + "weavers",
1563 + "website",
1564 + "wedge",
1565 + "weekday",
1566 + "weird",
1567 + "welders",
1568 + "went",
1569 + "wept",
1570 + "were",
1571 + "western",
1572 + "wetsuit",
1573 + "whale",
1574 + "when",
1575 + "whipped",
1576 + "whole",
1577 + "wickets",
1578 + "width",
1579 + "wield",
1580 + "wife",
1581 + "wiggle",
1582 + "wildly",
1583 + "winter",
1584 + "wipeout",
1585 + "wiring",
1586 + "wise",
1587 + "withdrawn",
1588 + "wives",
1589 + "wizard",
1590 + "wobbly",
1591 + "woes",
1592 + "woken",
1593 + "wolf",
1594 + "womanly",
1595 + "wonders",
1596 + "woozy",
1597 + "worry",
1598 + "wounded",
1599 + "woven",
1600 + "wrap",
1601 + "wrist",
1602 + "wrong",
1603 + "yacht",
1604 + "yahoo",
1605 + "yanks",
1606 + "yard",
1607 + "yawning",
1608 + "yearbook",
1609 + "yellow",
1610 + "yesterday",
1611 + "yeti",
1612 + "yields",
1613 + "yodel",
1614 + "yoga",
1615 + "younger",
1616 + "yoyo",
1617 + "zapped",
1618 + "zeal",
1619 + "zebra",
1620 + "zero",
1621 + "zesty",
1622 + "zigzags",
1623 + "zinger",
1624 + "zippers",
1625 + "zodiac",
1626 + "zombie",
1627 + "zones",
1628 + "zoom"
1629 + ];
1630 +}
cw_monero/lib/mnemonics/german.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class GermanMnemonics {
2 + static const words = [
3 + "Abakus",
4 + "Abart",
5 + "abbilden",
6 + "Abbruch",
7 + "Abdrift",
8 + "Abendrot",
9 + "Abfahrt",
10 + "abfeuern",
11 + "Abflug",
12 + "abfragen",
13 + "Abglanz",
14 + "abhärten",
15 + "abheben",
16 + "Abhilfe",
17 + "Abitur",
18 + "Abkehr",
19 + "Ablauf",
20 + "ablecken",
21 + "Ablösung",
22 + "Abnehmer",
23 + "abnutzen",
24 + "Abonnent",
25 + "Abrasion",
26 + "Abrede",
27 + "abrüsten",
28 + "Absicht",
29 + "Absprung",
30 + "Abstand",
31 + "absuchen",
32 + "Abteil",
33 + "Abundanz",
34 + "abwarten",
35 + "Abwurf",
36 + "Abzug",
37 + "Achse",
38 + "Achtung",
39 + "Acker",
40 + "Aderlass",
41 + "Adler",
42 + "Admiral",
43 + "Adresse",
44 + "Affe",
45 + "Affront",
46 + "Afrika",
47 + "Aggregat",
48 + "Agilität",
49 + "ähneln",
50 + "Ahnung",
51 + "Ahorn",
52 + "Akazie",
53 + "Akkord",
54 + "Akrobat",
55 + "Aktfoto",
56 + "Aktivist",
57 + "Albatros",
58 + "Alchimie",
59 + "Alemanne",
60 + "Alibi",
61 + "Alkohol",
62 + "Allee",
63 + "Allüre",
64 + "Almosen",
65 + "Almweide",
66 + "Aloe",
67 + "Alpaka",
68 + "Alpental",
69 + "Alphabet",
70 + "Alpinist",
71 + "Alraune",
72 + "Altbier",
73 + "Alter",
74 + "Altflöte",
75 + "Altruist",
76 + "Alublech",
77 + "Aludose",
78 + "Amateur",
79 + "Amazonas",
80 + "Ameise",
81 + "Amnesie",
82 + "Amok",
83 + "Ampel",
84 + "Amphibie",
85 + "Ampulle",
86 + "Amsel",
87 + "Amulett",
88 + "Anakonda",
89 + "Analogie",
90 + "Ananas",
91 + "Anarchie",
92 + "Anatomie",
93 + "Anbau",
94 + "Anbeginn",
95 + "anbieten",
96 + "Anblick",
97 + "ändern",
98 + "andocken",
99 + "Andrang",
100 + "anecken",
101 + "Anflug",
102 + "Anfrage",
103 + "Anführer",
104 + "Angebot",
105 + "Angler",
106 + "Anhalter",
107 + "Anhöhe",
108 + "Animator",
109 + "Anis",
110 + "Anker",
111 + "ankleben",
112 + "Ankunft",
113 + "Anlage",
114 + "anlocken",
115 + "Anmut",
116 + "Annahme",
117 + "Anomalie",
118 + "Anonymus",
119 + "Anorak",
120 + "anpeilen",
121 + "Anrecht",
122 + "Anruf",
123 + "Ansage",
124 + "Anschein",
125 + "Ansicht",
126 + "Ansporn",
127 + "Anteil",
128 + "Antlitz",
129 + "Antrag",
130 + "Antwort",
131 + "Anwohner",
132 + "Aorta",
133 + "Apfel",
134 + "Appetit",
135 + "Applaus",
136 + "Aquarium",
137 + "Arbeit",
138 + "Arche",
139 + "Argument",
140 + "Arktis",
141 + "Armband",
142 + "Aroma",
143 + "Asche",
144 + "Askese",
145 + "Asphalt",
146 + "Asteroid",
147 + "Ästhetik",
148 + "Astronom",
149 + "Atelier",
150 + "Athlet",
151 + "Atlantik",
152 + "Atmung",
153 + "Audienz",
154 + "aufatmen",
155 + "Auffahrt",
156 + "aufholen",
157 + "aufregen",
158 + "Aufsatz",
159 + "Auftritt",
160 + "Aufwand",
161 + "Augapfel",
162 + "Auktion",
163 + "Ausbruch",
164 + "Ausflug",
165 + "Ausgabe",
166 + "Aushilfe",
167 + "Ausland",
168 + "Ausnahme",
169 + "Aussage",
170 + "Autobahn",
171 + "Avocado",
172 + "Axthieb",
173 + "Bach",
174 + "backen",
175 + "Badesee",
176 + "Bahnhof",
177 + "Balance",
178 + "Balkon",
179 + "Ballett",
180 + "Balsam",
181 + "Banane",
182 + "Bandage",
183 + "Bankett",
184 + "Barbar",
185 + "Barde",
186 + "Barett",
187 + "Bargeld",
188 + "Barkasse",
189 + "Barriere",
190 + "Bart",
191 + "Bass",
192 + "Bastler",
193 + "Batterie",
194 + "Bauch",
195 + "Bauer",
196 + "Bauholz",
197 + "Baujahr",
198 + "Baum",
199 + "Baustahl",
200 + "Bauteil",
201 + "Bauweise",
202 + "Bazar",
203 + "beachten",
204 + "Beatmung",
205 + "beben",
206 + "Becher",
207 + "Becken",
208 + "bedanken",
209 + "beeilen",
210 + "beenden",
211 + "Beere",
212 + "befinden",
213 + "Befreier",
214 + "Begabung",
215 + "Begierde",
216 + "begrüßen",
217 + "Beiboot",
218 + "Beichte",
219 + "Beifall",
220 + "Beigabe",
221 + "Beil",
222 + "Beispiel",
223 + "Beitrag",
224 + "beizen",
225 + "bekommen",
226 + "beladen",
227 + "Beleg",
228 + "bellen",
229 + "belohnen",
230 + "Bemalung",
231 + "Bengel",
232 + "Benutzer",
233 + "Benzin",
234 + "beraten",
235 + "Bereich",
236 + "Bergluft",
237 + "Bericht",
238 + "Bescheid",
239 + "Besitz",
240 + "besorgen",
241 + "Bestand",
242 + "Besuch",
243 + "betanken",
244 + "beten",
245 + "betören",
246 + "Bett",
247 + "Beule",
248 + "Beute",
249 + "Bewegung",
250 + "bewirken",
251 + "Bewohner",
252 + "bezahlen",
253 + "Bezug",
254 + "biegen",
255 + "Biene",
256 + "Bierzelt",
257 + "bieten",
258 + "Bikini",
259 + "Bildung",
260 + "Billard",
261 + "binden",
262 + "Biobauer",
263 + "Biologe",
264 + "Bionik",
265 + "Biotop",
266 + "Birke",
267 + "Bison",
268 + "Bitte",
269 + "Biwak",
270 + "Bizeps",
271 + "blasen",
272 + "Blatt",
273 + "Blauwal",
274 + "Blende",
275 + "Blick",
276 + "Blitz",
277 + "Blockade",
278 + "Blödelei",
279 + "Blondine",
280 + "Blues",
281 + "Blume",
282 + "Blut",
283 + "Bodensee",
284 + "Bogen",
285 + "Boje",
286 + "Bollwerk",
287 + "Bonbon",
288 + "Bonus",
289 + "Boot",
290 + "Bordarzt",
291 + "Börse",
292 + "Böschung",
293 + "Boudoir",
294 + "Boxkampf",
295 + "Boykott",
296 + "Brahms",
297 + "Brandung",
298 + "Brauerei",
299 + "Brecher",
300 + "Breitaxt",
301 + "Bremse",
302 + "brennen",
303 + "Brett",
304 + "Brief",
305 + "Brigade",
306 + "Brillanz",
307 + "bringen",
308 + "brodeln",
309 + "Brosche",
310 + "Brötchen",
311 + "Brücke",
312 + "Brunnen",
313 + "Brüste",
314 + "Brutofen",
315 + "Buch",
316 + "Büffel",
317 + "Bugwelle",
318 + "Bühne",
319 + "Buletten",
320 + "Bullauge",
321 + "Bumerang",
322 + "bummeln",
323 + "Buntglas",
324 + "Bürde",
325 + "Burgherr",
326 + "Bursche",
327 + "Busen",
328 + "Buslinie",
329 + "Bussard",
330 + "Butangas",
331 + "Butter",
332 + "Cabrio",
333 + "campen",
334 + "Captain",
335 + "Cartoon",
336 + "Cello",
337 + "Chalet",
338 + "Charisma",
339 + "Chefarzt",
340 + "Chiffon",
341 + "Chipsatz",
342 + "Chirurg",
343 + "Chor",
344 + "Chronik",
345 + "Chuzpe",
346 + "Clubhaus",
347 + "Cockpit",
348 + "Codewort",
349 + "Cognac",
350 + "Coladose",
351 + "Computer",
352 + "Coupon",
353 + "Cousin",
354 + "Cracking",
355 + "Crash",
356 + "Curry",
357 + "Dach",
358 + "Dackel",
359 + "daddeln",
360 + "daliegen",
361 + "Dame",
362 + "Dammbau",
363 + "Dämon",
364 + "Dampflok",
365 + "Dank",
366 + "Darm",
367 + "Datei",
368 + "Datsche",
369 + "Datteln",
370 + "Datum",
371 + "Dauer",
372 + "Daunen",
373 + "Deckel",
374 + "Decoder",
375 + "Defekt",
376 + "Degen",
377 + "Dehnung",
378 + "Deiche",
379 + "Dekade",
380 + "Dekor",
381 + "Delfin",
382 + "Demut",
383 + "denken",
384 + "Deponie",
385 + "Design",
386 + "Desktop",
387 + "Dessert",
388 + "Detail",
389 + "Detektiv",
390 + "Dezibel",
391 + "Diadem",
392 + "Diagnose",
393 + "Dialekt",
394 + "Diamant",
395 + "Dichter",
396 + "Dickicht",
397 + "Diesel",
398 + "Diktat",
399 + "Diplom",
400 + "Direktor",
401 + "Dirne",
402 + "Diskurs",
403 + "Distanz",
404 + "Docht",
405 + "Dohle",
406 + "Dolch",
407 + "Domäne",
408 + "Donner",
409 + "Dorade",
410 + "Dorf",
411 + "Dörrobst",
412 + "Dorsch",
413 + "Dossier",
414 + "Dozent",
415 + "Drachen",
416 + "Draht",
417 + "Drama",
418 + "Drang",
419 + "Drehbuch",
420 + "Dreieck",
421 + "Dressur",
422 + "Drittel",
423 + "Drossel",
424 + "Druck",
425 + "Duell",
426 + "Duft",
427 + "Düne",
428 + "Dünung",
429 + "dürfen",
430 + "Duschbad",
431 + "Düsenjet",
432 + "Dynamik",
433 + "Ebbe",
434 + "Echolot",
435 + "Echse",
436 + "Eckball",
437 + "Edding",
438 + "Edelweiß",
439 + "Eden",
440 + "Edition",
441 + "Efeu",
442 + "Effekte",
443 + "Egoismus",
444 + "Ehre",
445 + "Eiablage",
446 + "Eiche",
447 + "Eidechse",
448 + "Eidotter",
449 + "Eierkopf",
450 + "Eigelb",
451 + "Eiland",
452 + "Eilbote",
453 + "Eimer",
454 + "einatmen",
455 + "Einband",
456 + "Eindruck",
457 + "Einfall",
458 + "Eingang",
459 + "Einkauf",
460 + "einladen",
461 + "Einöde",
462 + "Einrad",
463 + "Eintopf",
464 + "Einwurf",
465 + "Einzug",
466 + "Eisbär",
467 + "Eisen",
468 + "Eishöhle",
469 + "Eismeer",
470 + "Eiweiß",
471 + "Ekstase",
472 + "Elan",
473 + "Elch",
474 + "Elefant",
475 + "Eleganz",
476 + "Element",
477 + "Elfe",
478 + "Elite",
479 + "Elixier",
480 + "Ellbogen",
481 + "Eloquenz",
482 + "Emigrant",
483 + "Emission",
484 + "Emotion",
485 + "Empathie",
486 + "Empfang",
487 + "Endzeit",
488 + "Energie",
489 + "Engpass",
490 + "Enkel",
491 + "Enklave",
492 + "Ente",
493 + "entheben",
494 + "Entität",
495 + "entladen",
496 + "Entwurf",
497 + "Episode",
498 + "Epoche",
499 + "erachten",
500 + "Erbauer",
501 + "erblühen",
502 + "Erdbeere",
503 + "Erde",
504 + "Erdgas",
505 + "Erdkunde",
506 + "Erdnuss",
507 + "Erdöl",
508 + "Erdteil",
509 + "Ereignis",
510 + "Eremit",
511 + "erfahren",
512 + "Erfolg",
513 + "erfreuen",
514 + "erfüllen",
515 + "Ergebnis",
516 + "erhitzen",
517 + "erkalten",
518 + "erkennen",
519 + "erleben",
520 + "Erlösung",
521 + "ernähren",
522 + "erneuern",
523 + "Ernte",
524 + "Eroberer",
525 + "eröffnen",
526 + "Erosion",
527 + "Erotik",
528 + "Erpel",
529 + "erraten",
530 + "Erreger",
531 + "erröten",
532 + "Ersatz",
533 + "Erstflug",
534 + "Ertrag",
535 + "Eruption",
536 + "erwarten",
537 + "erwidern",
538 + "Erzbau",
539 + "Erzeuger",
540 + "erziehen",
541 + "Esel",
542 + "Eskimo",
543 + "Eskorte",
544 + "Espe",
545 + "Espresso",
546 + "essen",
547 + "Etage",
548 + "Etappe",
549 + "Etat",
550 + "Ethik",
551 + "Etikett",
552 + "Etüde",
553 + "Eule",
554 + "Euphorie",
555 + "Europa",
556 + "Everest",
557 + "Examen",
558 + "Exil",
559 + "Exodus",
560 + "Extrakt",
561 + "Fabel",
562 + "Fabrik",
563 + "Fachmann",
564 + "Fackel",
565 + "Faden",
566 + "Fagott",
567 + "Fahne",
568 + "Faible",
569 + "Fairness",
570 + "Fakt",
571 + "Fakultät",
572 + "Falke",
573 + "Fallobst",
574 + "Fälscher",
575 + "Faltboot",
576 + "Familie",
577 + "Fanclub",
578 + "Fanfare",
579 + "Fangarm",
580 + "Fantasie",
581 + "Farbe",
582 + "Farmhaus",
583 + "Farn",
584 + "Fasan",
585 + "Faser",
586 + "Fassung",
587 + "fasten",
588 + "Faulheit",
589 + "Fauna",
590 + "Faust",
591 + "Favorit",
592 + "Faxgerät",
593 + "Fazit",
594 + "fechten",
595 + "Federboa",
596 + "Fehler",
597 + "Feier",
598 + "Feige",
599 + "feilen",
600 + "Feinripp",
601 + "Feldbett",
602 + "Felge",
603 + "Fellpony",
604 + "Felswand",
605 + "Ferien",
606 + "Ferkel",
607 + "Fernweh",
608 + "Ferse",
609 + "Fest",
610 + "Fettnapf",
611 + "Feuer",
612 + "Fiasko",
613 + "Fichte",
614 + "Fiktion",
615 + "Film",
616 + "Filter",
617 + "Filz",
618 + "Finanzen",
619 + "Findling",
620 + "Finger",
621 + "Fink",
622 + "Finnwal",
623 + "Fisch",
624 + "Fitness",
625 + "Fixpunkt",
626 + "Fixstern",
627 + "Fjord",
628 + "Flachbau",
629 + "Flagge",
630 + "Flamenco",
631 + "Flanke",
632 + "Flasche",
633 + "Flaute",
634 + "Fleck",
635 + "Flegel",
636 + "flehen",
637 + "Fleisch",
638 + "fliegen",
639 + "Flinte",
640 + "Flirt",
641 + "Flocke",
642 + "Floh",
643 + "Floskel",
644 + "Floß",
645 + "Flöte",
646 + "Flugzeug",
647 + "Flunder",
648 + "Flusstal",
649 + "Flutung",
650 + "Fockmast",
651 + "Fohlen",
652 + "Föhnlage",
653 + "Fokus",
654 + "folgen",
655 + "Foliant",
656 + "Folklore",
657 + "Fontäne",
658 + "Förde",
659 + "Forelle",
660 + "Format",
661 + "Forscher",
662 + "Fortgang",
663 + "Forum",
664 + "Fotograf",
665 + "Frachter",
666 + "Fragment",
667 + "Fraktion",
668 + "fräsen",
669 + "Frauenpo",
670 + "Freak",
671 + "Fregatte",
672 + "Freiheit",
673 + "Freude",
674 + "Frieden",
675 + "Frohsinn",
676 + "Frosch",
677 + "Frucht",
678 + "Frühjahr",
679 + "Fuchs",
680 + "Fügung",
681 + "fühlen",
682 + "Füller",
683 + "Fundbüro",
684 + "Funkboje",
685 + "Funzel",
686 + "Furnier",
687 + "Fürsorge",
688 + "Fusel",
689 + "Fußbad",
690 + "Futteral",
691 + "Gabelung",
692 + "gackern",
693 + "Gage",
694 + "gähnen",
695 + "Galaxie",
696 + "Galeere",
697 + "Galopp",
698 + "Gameboy",
699 + "Gamsbart",
700 + "Gandhi",
701 + "Gang",
702 + "Garage",
703 + "Gardine",
704 + "Garküche",
705 + "Garten",
706 + "Gasthaus",
707 + "Gattung",
708 + "gaukeln",
709 + "Gazelle",
710 + "Gebäck",
711 + "Gebirge",
712 + "Gebräu",
713 + "Geburt",
714 + "Gedanke",
715 + "Gedeck",
716 + "Gedicht",
717 + "Gefahr",
718 + "Gefieder",
719 + "Geflügel",
720 + "Gefühl",
721 + "Gegend",
722 + "Gehirn",
723 + "Gehöft",
724 + "Gehweg",
725 + "Geige",
726 + "Geist",
727 + "Gelage",
728 + "Geld",
729 + "Gelenk",
730 + "Gelübde",
731 + "Gemälde",
732 + "Gemeinde",
733 + "Gemüse",
734 + "genesen",
735 + "Genuss",
736 + "Gepäck",
737 + "Geranie",
738 + "Gericht",
739 + "Germane",
740 + "Geruch",
741 + "Gesang",
742 + "Geschenk",
743 + "Gesetz",
744 + "Gesindel",
745 + "Gesöff",
746 + "Gespan",
747 + "Gestade",
748 + "Gesuch",
749 + "Getier",
750 + "Getränk",
751 + "Getümmel",
752 + "Gewand",
753 + "Geweih",
754 + "Gewitter",
755 + "Gewölbe",
756 + "Geysir",
757 + "Giftzahn",
758 + "Gipfel",
759 + "Giraffe",
760 + "Gitarre",
761 + "glänzen",
762 + "Glasauge",
763 + "Glatze",
764 + "Gleis",
765 + "Globus",
766 + "Glück",
767 + "glühen",
768 + "Glutofen",
769 + "Goldzahn",
770 + "Gondel",
771 + "gönnen",
772 + "Gottheit",
773 + "graben",
774 + "Grafik",
775 + "Grashalm",
776 + "Graugans",
777 + "greifen",
778 + "Grenze",
779 + "grillen",
780 + "Groschen",
781 + "Grotte",
782 + "Grube",
783 + "Grünalge",
784 + "Gruppe",
785 + "gruseln",
786 + "Gulasch",
787 + "Gummibär",
788 + "Gurgel",
789 + "Gürtel",
790 + "Güterzug",
791 + "Haarband",
792 + "Habicht",
793 + "hacken",
794 + "hadern",
795 + "Hafen",
796 + "Hagel",
797 + "Hähnchen",
798 + "Haifisch",
799 + "Haken",
800 + "Halbaffe",
801 + "Halsader",
802 + "halten",
803 + "Halunke",
804 + "Handbuch",
805 + "Hanf",
806 + "Harfe",
807 + "Harnisch",
808 + "härten",
809 + "Harz",
810 + "Hasenohr",
811 + "Haube",
812 + "hauchen",
813 + "Haupt",
814 + "Haut",
815 + "Havarie",
816 + "Hebamme",
817 + "hecheln",
818 + "Heck",
819 + "Hedonist",
820 + "Heiler",
821 + "Heimat",
822 + "Heizung",
823 + "Hektik",
824 + "Held",
825 + "helfen",
826 + "Helium",
827 + "Hemd",
828 + "hemmen",
829 + "Hengst",
830 + "Herd",
831 + "Hering",
832 + "Herkunft",
833 + "Hermelin",
834 + "Herrchen",
835 + "Herzdame",
836 + "Heulboje",
837 + "Hexe",
838 + "Hilfe",
839 + "Himbeere",
840 + "Himmel",
841 + "Hingabe",
842 + "hinhören",
843 + "Hinweis",
844 + "Hirsch",
845 + "Hirte",
846 + "Hitzkopf",
847 + "Hobel",
848 + "Hochform",
849 + "Hocker",
850 + "hoffen",
851 + "Hofhund",
852 + "Hofnarr",
853 + "Höhenzug",
854 + "Hohlraum",
855 + "Hölle",
856 + "Holzboot",
857 + "Honig",
858 + "Honorar",
859 + "horchen",
860 + "Hörprobe",
861 + "Höschen",
862 + "Hotel",
863 + "Hubraum",
864 + "Hufeisen",
865 + "Hügel",
866 + "huldigen",
867 + "Hülle",
868 + "Humbug",
869 + "Hummer",
870 + "Humor",
871 + "Hund",
872 + "Hunger",
873 + "Hupe",
874 + "Hürde",
875 + "Hurrikan",
876 + "Hydrant",
877 + "Hypnose",
878 + "Ibis",
879 + "Idee",
880 + "Idiot",
881 + "Igel",
882 + "Illusion",
883 + "Imitat",
884 + "impfen",
885 + "Import",
886 + "Inferno",
887 + "Ingwer",
888 + "Inhalte",
889 + "Inland",
890 + "Insekt",
891 + "Ironie",
892 + "Irrfahrt",
893 + "Irrtum",
894 + "Isolator",
895 + "Istwert",
896 + "Jacke",
897 + "Jade",
898 + "Jagdhund",
899 + "Jäger",
900 + "Jaguar",
901 + "Jahr",
902 + "Jähzorn",
903 + "Jazzfest",
904 + "Jetpilot",
905 + "jobben",
906 + "Jochbein",
907 + "jodeln",
908 + "Jodsalz",
909 + "Jolle",
910 + "Journal",
911 + "Jubel",
912 + "Junge",
913 + "Junimond",
914 + "Jupiter",
915 + "Jutesack",
916 + "Juwel",
917 + "Kabarett",
918 + "Kabine",
919 + "Kabuff",
920 + "Käfer",
921 + "Kaffee",
922 + "Kahlkopf",
923 + "Kaimauer",
924 + "Kajüte",
925 + "Kaktus",
926 + "Kaliber",
927 + "Kaltluft",
928 + "Kamel",
929 + "kämmen",
930 + "Kampagne",
931 + "Kanal",
932 + "Känguru",
933 + "Kanister",
934 + "Kanone",
935 + "Kante",
936 + "Kanu",
937 + "kapern",
938 + "Kapitän",
939 + "Kapuze",
940 + "Karneval",
941 + "Karotte",
942 + "Käsebrot",
943 + "Kasper",
944 + "Kastanie",
945 + "Katalog",
946 + "Kathode",
947 + "Katze",
948 + "kaufen",
949 + "Kaugummi",
950 + "Kauz",
951 + "Kehle",
952 + "Keilerei",
953 + "Keksdose",
954 + "Kellner",
955 + "Keramik",
956 + "Kerze",
957 + "Kessel",
958 + "Kette",
959 + "keuchen",
960 + "kichern",
961 + "Kielboot",
962 + "Kindheit",
963 + "Kinnbart",
964 + "Kinosaal",
965 + "Kiosk",
966 + "Kissen",
967 + "Klammer",
968 + "Klang",
969 + "Klapprad",
970 + "Klartext",
971 + "kleben",
972 + "Klee",
973 + "Kleinod",
974 + "Klima",
975 + "Klingel",
976 + "Klippe",
977 + "Klischee",
978 + "Kloster",
979 + "Klugheit",
980 + "Klüngel",
981 + "kneten",
982 + "Knie",
983 + "Knöchel",
984 + "knüpfen",
985 + "Kobold",
986 + "Kochbuch",
987 + "Kohlrabi",
988 + "Koje",
989 + "Kokosöl",
990 + "Kolibri",
991 + "Kolumne",
992 + "Kombüse",
993 + "Komiker",
994 + "kommen",
995 + "Konto",
996 + "Konzept",
997 + "Kopfkino",
998 + "Kordhose",
999 + "Korken",
1000 + "Korsett",
1001 + "Kosename",
1002 + "Krabbe",
1003 + "Krach",
1004 + "Kraft",
1005 + "Krähe",
1006 + "Kralle",
1007 + "Krapfen",
1008 + "Krater",
1009 + "kraulen",
1010 + "Kreuz",
1011 + "Krokodil",
1012 + "Kröte",
1013 + "Kugel",
1014 + "Kuhhirt",
1015 + "Kühnheit",
1016 + "Künstler",
1017 + "Kurort",
1018 + "Kurve",
1019 + "Kurzfilm",
1020 + "kuscheln",
1021 + "küssen",
1022 + "Kutter",
1023 + "Labor",
1024 + "lachen",
1025 + "Lackaffe",
1026 + "Ladeluke",
1027 + "Lagune",
1028 + "Laib",
1029 + "Lakritze",
1030 + "Lammfell",
1031 + "Land",
1032 + "Langmut",
1033 + "Lappalie",
1034 + "Last",
1035 + "Laterne",
1036 + "Latzhose",
1037 + "Laubsäge",
1038 + "laufen",
1039 + "Laune",
1040 + "Lausbub",
1041 + "Lavasee",
1042 + "Leben",
1043 + "Leder",
1044 + "Leerlauf",
1045 + "Lehm",
1046 + "Lehrer",
1047 + "leihen",
1048 + "Lektüre",
1049 + "Lenker",
1050 + "Lerche",
1051 + "Leseecke",
1052 + "Leuchter",
1053 + "Lexikon",
1054 + "Libelle",
1055 + "Libido",
1056 + "Licht",
1057 + "Liebe",
1058 + "liefern",
1059 + "Liftboy",
1060 + "Limonade",
1061 + "Lineal",
1062 + "Linoleum",
1063 + "List",
1064 + "Liveband",
1065 + "Lobrede",
1066 + "locken",
1067 + "Löffel",
1068 + "Logbuch",
1069 + "Logik",
1070 + "Lohn",
1071 + "Loipe",
1072 + "Lokal",
1073 + "Lorbeer",
1074 + "Lösung",
1075 + "löten",
1076 + "Lottofee",
1077 + "Löwe",
1078 + "Luchs",
1079 + "Luder",
1080 + "Luftpost",
1081 + "Luke",
1082 + "Lümmel",
1083 + "Lunge",
1084 + "lutschen",
1085 + "Luxus",
1086 + "Macht",
1087 + "Magazin",
1088 + "Magier",
1089 + "Magnet",
1090 + "mähen",
1091 + "Mahlzeit",
1092 + "Mahnmal",
1093 + "Maibaum",
1094 + "Maisbrei",
1095 + "Makel",
1096 + "malen",
1097 + "Mammut",
1098 + "Maniküre",
1099 + "Mantel",
1100 + "Marathon",
1101 + "Marder",
1102 + "Marine",
1103 + "Marke",
1104 + "Marmor",
1105 + "Märzluft",
1106 + "Maske",
1107 + "Maßanzug",
1108 + "Maßkrug",
1109 + "Mastkorb",
1110 + "Material",
1111 + "Matratze",
1112 + "Mauerbau",
1113 + "Maulkorb",
1114 + "Mäuschen",
1115 + "Mäzen",
1116 + "Medium",
1117 + "Meinung",
1118 + "melden",
1119 + "Melodie",
1120 + "Mensch",
1121 + "Merkmal",
1122 + "Messe",
1123 + "Metall",
1124 + "Meteor",
1125 + "Methode",
1126 + "Metzger",
1127 + "Mieze",
1128 + "Milchkuh",
1129 + "Mimose",
1130 + "Minirock",
1131 + "Minute",
1132 + "mischen",
1133 + "Missetat",
1134 + "mitgehen",
1135 + "Mittag",
1136 + "Mixtape",
1137 + "Möbel",
1138 + "Modul",
1139 + "mögen",
1140 + "Möhre",
1141 + "Molch",
1142 + "Moment",
1143 + "Monat",
1144 + "Mondflug",
1145 + "Monitor",
1146 + "Monokini",
1147 + "Monster",
1148 + "Monument",
1149 + "Moorhuhn",
1150 + "Moos",
1151 + "Möpse",
1152 + "Moral",
1153 + "Mörtel",
1154 + "Motiv",
1155 + "Motorrad",
1156 + "Möwe",
1157 + "Mühe",
1158 + "Mulatte",
1159 + "Müller",
1160 + "Mumie",
1161 + "Mund",
1162 + "Münze",
1163 + "Muschel",
1164 + "Muster",
1165 + "Mythos",
1166 + "Nabel",
1167 + "Nachtzug",
1168 + "Nackedei",
1169 + "Nagel",
1170 + "Nähe",
1171 + "Nähnadel",
1172 + "Namen",
1173 + "Narbe",
1174 + "Narwal",
1175 + "Nasenbär",
1176 + "Natur",
1177 + "Nebel",
1178 + "necken",
1179 + "Neffe",
1180 + "Neigung",
1181 + "Nektar",
1182 + "Nenner",
1183 + "Neptun",
1184 + "Nerz",
1185 + "Nessel",
1186 + "Nestbau",
1187 + "Netz",
1188 + "Neubau",
1189 + "Neuerung",
1190 + "Neugier",
1191 + "nicken",
1192 + "Niere",
1193 + "Nilpferd",
1194 + "nisten",
1195 + "Nocke",
1196 + "Nomade",
1197 + "Nordmeer",
1198 + "Notdurft",
1199 + "Notstand",
1200 + "Notwehr",
1201 + "Nudismus",
1202 + "Nuss",
1203 + "Nutzhanf",
1204 + "Oase",
1205 + "Obdach",
1206 + "Oberarzt",
1207 + "Objekt",
1208 + "Oboe",
1209 + "Obsthain",
1210 + "Ochse",
1211 + "Odyssee",
1212 + "Ofenholz",
1213 + "öffnen",
1214 + "Ohnmacht",
1215 + "Ohrfeige",
1216 + "Ohrwurm",
1217 + "Ökologie",
1218 + "Oktave",
1219 + "Ölberg",
1220 + "Olive",
1221 + "Ölkrise",
1222 + "Omelett",
1223 + "Onkel",
1224 + "Oper",
1225 + "Optiker",
1226 + "Orange",
1227 + "Orchidee",
1228 + "ordnen",
1229 + "Orgasmus",
1230 + "Orkan",
1231 + "Ortskern",
1232 + "Ortung",
1233 + "Ostasien",
1234 + "Ozean",
1235 + "Paarlauf",
1236 + "Packeis",
1237 + "paddeln",
1238 + "Paket",
1239 + "Palast",
1240 + "Pandabär",
1241 + "Panik",
1242 + "Panorama",
1243 + "Panther",
1244 + "Papagei",
1245 + "Papier",
1246 + "Paprika",
1247 + "Paradies",
1248 + "Parka",
1249 + "Parodie",
1250 + "Partner",
1251 + "Passant",
1252 + "Patent",
1253 + "Patzer",
1254 + "Pause",
1255 + "Pavian",
1256 + "Pedal",
1257 + "Pegel",
1258 + "peilen",
1259 + "Perle",
1260 + "Person",
1261 + "Pfad",
1262 + "Pfau",
1263 + "Pferd",
1264 + "Pfleger",
1265 + "Physik",
1266 + "Pier",
1267 + "Pilotwal",
1268 + "Pinzette",
1269 + "Piste",
1270 + "Plakat",
1271 + "Plankton",
1272 + "Platin",
1273 + "Plombe",
1274 + "plündern",
1275 + "Pobacke",
1276 + "Pokal",
1277 + "polieren",
1278 + "Popmusik",
1279 + "Porträt",
1280 + "Posaune",
1281 + "Postamt",
1282 + "Pottwal",
1283 + "Pracht",
1284 + "Pranke",
1285 + "Preis",
1286 + "Primat",
1287 + "Prinzip",
1288 + "Protest",
1289 + "Proviant",
1290 + "Prüfung",
1291 + "Pubertät",
1292 + "Pudding",
1293 + "Pullover",
1294 + "Pulsader",
1295 + "Punkt",
1296 + "Pute",
1297 + "Putsch",
1298 + "Puzzle",
1299 + "Python",
1300 + "quaken",
1301 + "Qualle",
1302 + "Quark",
1303 + "Quellsee",
1304 + "Querkopf",
1305 + "Quitte",
1306 + "Quote",
1307 + "Rabauke",
1308 + "Rache",
1309 + "Radclub",
1310 + "Radhose",
1311 + "Radio",
1312 + "Radtour",
1313 + "Rahmen",
1314 + "Rampe",
1315 + "Randlage",
1316 + "Ranzen",
1317 + "Rapsöl",
1318 + "Raserei",
1319 + "rasten",
1320 + "Rasur",
1321 + "Rätsel",
1322 + "Raubtier",
1323 + "Raumzeit",
1324 + "Rausch",
1325 + "Reaktor",
1326 + "Realität",
1327 + "Rebell",
1328 + "Rede",
1329 + "Reetdach",
1330 + "Regatta",
1331 + "Regen",
1332 + "Rehkitz",
1333 + "Reifen",
1334 + "Reim",
1335 + "Reise",
1336 + "Reizung",
1337 + "Rekord",
1338 + "Relevanz",
1339 + "Rennboot",
1340 + "Respekt",
1341 + "Restmüll",
1342 + "retten",
1343 + "Reue",
1344 + "Revolte",
1345 + "Rhetorik",
1346 + "Rhythmus",
1347 + "Richtung",
1348 + "Riegel",
1349 + "Rindvieh",
1350 + "Rippchen",
1351 + "Ritter",
1352 + "Robbe",
1353 + "Roboter",
1354 + "Rockband",
1355 + "Rohdaten",
1356 + "Roller",
1357 + "Roman",
1358 + "röntgen",
1359 + "Rose",
1360 + "Rosskur",
1361 + "Rost",
1362 + "Rotahorn",
1363 + "Rotglut",
1364 + "Rotznase",
1365 + "Rubrik",
1366 + "Rückweg",
1367 + "Rufmord",
1368 + "Ruhe",
1369 + "Ruine",
1370 + "Rumpf",
1371 + "Runde",
1372 + "Rüstung",
1373 + "rütteln",
1374 + "Saaltür",
1375 + "Saatguts",
1376 + "Säbel",
1377 + "Sachbuch",
1378 + "Sack",
1379 + "Saft",
1380 + "sagen",
1381 + "Sahneeis",
1382 + "Salat",
1383 + "Salbe",
1384 + "Salz",
1385 + "Sammlung",
1386 + "Samt",
1387 + "Sandbank",
1388 + "Sanftmut",
1389 + "Sardine",
1390 + "Satire",
1391 + "Sattel",
1392 + "Satzbau",
1393 + "Sauerei",
1394 + "Saum",
1395 + "Säure",
1396 + "Schall",
1397 + "Scheitel",
1398 + "Schiff",
1399 + "Schlager",
1400 + "Schmied",
1401 + "Schnee",
1402 + "Scholle",
1403 + "Schrank",
1404 + "Schulbus",
1405 + "Schwan",
1406 + "Seeadler",
1407 + "Seefahrt",
1408 + "Seehund",
1409 + "Seeufer",
1410 + "segeln",
1411 + "Sehnerv",
1412 + "Seide",
1413 + "Seilzug",
1414 + "Senf",
1415 + "Sessel",
1416 + "Seufzer",
1417 + "Sexgott",
1418 + "Sichtung",
1419 + "Signal",
1420 + "Silber",
1421 + "singen",
1422 + "Sinn",
1423 + "Sirup",
1424 + "Sitzbank",
1425 + "Skandal",
1426 + "Skikurs",
1427 + "Skipper",
1428 + "Skizze",
1429 + "Smaragd",
1430 + "Socke",
1431 + "Sohn",
1432 + "Sommer",
1433 + "Songtext",
1434 + "Sorte",
1435 + "Spagat",
1436 + "Spannung",
1437 + "Spargel",
1438 + "Specht",
1439 + "Speiseöl",
1440 + "Spiegel",
1441 + "Sport",
1442 + "spülen",
1443 + "Stadtbus",
1444 + "Stall",
1445 + "Stärke",
1446 + "Stativ",
1447 + "staunen",
1448 + "Stern",
1449 + "Stiftung",
1450 + "Stollen",
1451 + "Strömung",
1452 + "Sturm",
1453 + "Substanz",
1454 + "Südalpen",
1455 + "Sumpf",
1456 + "surfen",
1457 + "Tabak",
1458 + "Tafel",
1459 + "Tagebau",
1460 + "takeln",
1461 + "Taktung",
1462 + "Talsohle",
1463 + "Tand",
1464 + "Tanzbär",
1465 + "Tapir",
1466 + "Tarantel",
1467 + "Tarnname",
1468 + "Tasse",
1469 + "Tatnacht",
1470 + "Tatsache",
1471 + "Tatze",
1472 + "Taube",
1473 + "tauchen",
1474 + "Taufpate",
1475 + "Taumel",
1476 + "Teelicht",
1477 + "Teich",
1478 + "teilen",
1479 + "Tempo",
1480 + "Tenor",
1481 + "Terrasse",
1482 + "Testflug",
1483 + "Theater",
1484 + "Thermik",
1485 + "ticken",
1486 + "Tiefflug",
1487 + "Tierart",
1488 + "Tigerhai",
1489 + "Tinte",
1490 + "Tischler",
1491 + "toben",
1492 + "Toleranz",
1493 + "Tölpel",
1494 + "Tonband",
1495 + "Topf",
1496 + "Topmodel",
1497 + "Torbogen",
1498 + "Torlinie",
1499 + "Torte",
1500 + "Tourist",
1501 + "Tragesel",
1502 + "trampeln",
1503 + "Trapez",
1504 + "Traum",
1505 + "treffen",
1506 + "Trennung",
1507 + "Treue",
1508 + "Trick",
1509 + "trimmen",
1510 + "Trödel",
1511 + "Trost",
1512 + "Trumpf",
1513 + "tüfteln",
1514 + "Turban",
1515 + "Turm",
1516 + "Übermut",
1517 + "Ufer",
1518 + "Uhrwerk",
1519 + "umarmen",
1520 + "Umbau",
1521 + "Umfeld",
1522 + "Umgang",
1523 + "Umsturz",
1524 + "Unart",
1525 + "Unfug",
1526 + "Unimog",
1527 + "Unruhe",
1528 + "Unwucht",
1529 + "Uranerz",
1530 + "Urlaub",
1531 + "Urmensch",
1532 + "Utopie",
1533 + "Vakuum",
1534 + "Valuta",
1535 + "Vandale",
1536 + "Vase",
1537 + "Vektor",
1538 + "Ventil",
1539 + "Verb",
1540 + "Verdeck",
1541 + "Verfall",
1542 + "Vergaser",
1543 + "verhexen",
1544 + "Verlag",
1545 + "Vers",
1546 + "Vesper",
1547 + "Vieh",
1548 + "Viereck",
1549 + "Vinyl",
1550 + "Virus",
1551 + "Vitrine",
1552 + "Vollblut",
1553 + "Vorbote",
1554 + "Vorrat",
1555 + "Vorsicht",
1556 + "Vulkan",
1557 + "Wachstum",
1558 + "Wade",
1559 + "Wagemut",
1560 + "Wahlen",
1561 + "Wahrheit",
1562 + "Wald",
1563 + "Walhai",
1564 + "Wallach",
1565 + "Walnuss",
1566 + "Walzer",
1567 + "wandeln",
1568 + "Wanze",
1569 + "wärmen",
1570 + "Warnruf",
1571 + "Wäsche",
1572 + "Wasser",
1573 + "Weberei",
1574 + "wechseln",
1575 + "Wegegeld",
1576 + "wehren",
1577 + "Weiher",
1578 + "Weinglas",
1579 + "Weißbier",
1580 + "Weitwurf",
1581 + "Welle",
1582 + "Weltall",
1583 + "Werkbank",
1584 + "Werwolf",
1585 + "Wetter",
1586 + "wiehern",
1587 + "Wildgans",
1588 + "Wind",
1589 + "Wohl",
1590 + "Wohnort",
1591 + "Wolf",
1592 + "Wollust",
1593 + "Wortlaut",
1594 + "Wrack",
1595 + "Wunder",
1596 + "Wurfaxt",
1597 + "Wurst",
1598 + "Yacht",
1599 + "Yeti",
1600 + "Zacke",
1601 + "Zahl",
1602 + "zähmen",
1603 + "Zahnfee",
1604 + "Zäpfchen",
1605 + "Zaster",
1606 + "Zaumzeug",
1607 + "Zebra",
1608 + "zeigen",
1609 + "Zeitlupe",
1610 + "Zellkern",
1611 + "Zeltdach",
1612 + "Zensor",
1613 + "Zerfall",
1614 + "Zeug",
1615 + "Ziege",
1616 + "Zielfoto",
1617 + "Zimteis",
1618 + "Zobel",
1619 + "Zollhund",
1620 + "Zombie",
1621 + "Zöpfe",
1622 + "Zucht",
1623 + "Zufahrt",
1624 + "Zugfahrt",
1625 + "Zugvogel",
1626 + "Zündung",
1627 + "Zweck",
1628 + "Zyklop"
1629 + ];
1630 +}
\ No newline at end of file
cw_monero/lib/mnemonics/japanese.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class JapaneseMnemonics {
2 + static const words = [
3 + "あいこくしん",
4 + "あいさつ",
5 + "あいだ",
6 + "あおぞら",
7 + "あかちゃん",
8 + "あきる",
9 + "あけがた",
10 + "あける",
11 + "あこがれる",
12 + "あさい",
13 + "あさひ",
14 + "あしあと",
15 + "あじわう",
16 + "あずかる",
17 + "あずき",
18 + "あそぶ",
19 + "あたえる",
20 + "あたためる",
21 + "あたりまえ",
22 + "あたる",
23 + "あつい",
24 + "あつかう",
25 + "あっしゅく",
26 + "あつまり",
27 + "あつめる",
28 + "あてな",
29 + "あてはまる",
30 + "あひる",
31 + "あぶら",
32 + "あぶる",
33 + "あふれる",
34 + "あまい",
35 + "あまど",
36 + "あまやかす",
37 + "あまり",
38 + "あみもの",
39 + "あめりか",
40 + "あやまる",
41 + "あゆむ",
42 + "あらいぐま",
43 + "あらし",
44 + "あらすじ",
45 + "あらためる",
46 + "あらゆる",
47 + "あらわす",
48 + "ありがとう",
49 + "あわせる",
50 + "あわてる",
51 + "あんい",
52 + "あんがい",
53 + "あんこ",
54 + "あんぜん",
55 + "あんてい",
56 + "あんない",
57 + "あんまり",
58 + "いいだす",
59 + "いおん",
60 + "いがい",
61 + "いがく",
62 + "いきおい",
63 + "いきなり",
64 + "いきもの",
65 + "いきる",
66 + "いくじ",
67 + "いくぶん",
68 + "いけばな",
69 + "いけん",
70 + "いこう",
71 + "いこく",
72 + "いこつ",
73 + "いさましい",
74 + "いさん",
75 + "いしき",
76 + "いじゅう",
77 + "いじょう",
78 + "いじわる",
79 + "いずみ",
80 + "いずれ",
81 + "いせい",
82 + "いせえび",
83 + "いせかい",
84 + "いせき",
85 + "いぜん",
86 + "いそうろう",
87 + "いそがしい",
88 + "いだい",
89 + "いだく",
90 + "いたずら",
91 + "いたみ",
92 + "いたりあ",
93 + "いちおう",
94 + "いちじ",
95 + "いちど",
96 + "いちば",
97 + "いちぶ",
98 + "いちりゅう",
99 + "いつか",
100 + "いっしゅん",
101 + "いっせい",
102 + "いっそう",
103 + "いったん",
104 + "いっち",
105 + "いってい",
106 + "いっぽう",
107 + "いてざ",
108 + "いてん",
109 + "いどう",
110 + "いとこ",
111 + "いない",
112 + "いなか",
113 + "いねむり",
114 + "いのち",
115 + "いのる",
116 + "いはつ",
117 + "いばる",
118 + "いはん",
119 + "いびき",
120 + "いひん",
121 + "いふく",
122 + "いへん",
123 + "いほう",
124 + "いみん",
125 + "いもうと",
126 + "いもたれ",
127 + "いもり",
128 + "いやがる",
129 + "いやす",
130 + "いよかん",
131 + "いよく",
132 + "いらい",
133 + "いらすと",
134 + "いりぐち",
135 + "いりょう",
136 + "いれい",
137 + "いれもの",
138 + "いれる",
139 + "いろえんぴつ",
140 + "いわい",
141 + "いわう",
142 + "いわかん",
143 + "いわば",
144 + "いわゆる",
145 + "いんげんまめ",
146 + "いんさつ",
147 + "いんしょう",
148 + "いんよう",
149 + "うえき",
150 + "うえる",
151 + "うおざ",
152 + "うがい",
153 + "うかぶ",
154 + "うかべる",
155 + "うきわ",
156 + "うくらいな",
157 + "うくれれ",
158 + "うけたまわる",
159 + "うけつけ",
160 + "うけとる",
161 + "うけもつ",
162 + "うける",
163 + "うごかす",
164 + "うごく",
165 + "うこん",
166 + "うさぎ",
167 + "うしなう",
168 + "うしろがみ",
169 + "うすい",
170 + "うすぎ",
171 + "うすぐらい",
172 + "うすめる",
173 + "うせつ",
174 + "うちあわせ",
175 + "うちがわ",
176 + "うちき",
177 + "うちゅう",
178 + "うっかり",
179 + "うつくしい",
180 + "うったえる",
181 + "うつる",
182 + "うどん",
183 + "うなぎ",
184 + "うなじ",
185 + "うなずく",
186 + "うなる",
187 + "うねる",
188 + "うのう",
189 + "うぶげ",
190 + "うぶごえ",
191 + "うまれる",
192 + "うめる",
193 + "うもう",
194 + "うやまう",
195 + "うよく",
196 + "うらがえす",
197 + "うらぐち",
198 + "うらない",
199 + "うりあげ",
200 + "うりきれ",
201 + "うるさい",
202 + "うれしい",
203 + "うれゆき",
204 + "うれる",
205 + "うろこ",
206 + "うわき",
207 + "うわさ",
208 + "うんこう",
209 + "うんちん",
210 + "うんてん",
211 + "うんどう",
212 + "えいえん",
213 + "えいが",
214 + "えいきょう",
215 + "えいご",
216 + "えいせい",
217 + "えいぶん",
218 + "えいよう",
219 + "えいわ",
220 + "えおり",
221 + "えがお",
222 + "えがく",
223 + "えきたい",
224 + "えくせる",
225 + "えしゃく",
226 + "えすて",
227 + "えつらん",
228 + "えのぐ",
229 + "えほうまき",
230 + "えほん",
231 + "えまき",
232 + "えもじ",
233 + "えもの",
234 + "えらい",
235 + "えらぶ",
236 + "えりあ",
237 + "えんえん",
238 + "えんかい",
239 + "えんぎ",
240 + "えんげき",
241 + "えんしゅう",
242 + "えんぜつ",
243 + "えんそく",
244 + "えんちょう",
245 + "えんとつ",
246 + "おいかける",
247 + "おいこす",
248 + "おいしい",
249 + "おいつく",
250 + "おうえん",
251 + "おうさま",
252 + "おうじ",
253 + "おうせつ",
254 + "おうたい",
255 + "おうふく",
256 + "おうべい",
257 + "おうよう",
258 + "おえる",
259 + "おおい",
260 + "おおう",
261 + "おおどおり",
262 + "おおや",
263 + "おおよそ",
264 + "おかえり",
265 + "おかず",
266 + "おがむ",
267 + "おかわり",
268 + "おぎなう",
269 + "おきる",
270 + "おくさま",
271 + "おくじょう",
272 + "おくりがな",
273 + "おくる",
274 + "おくれる",
275 + "おこす",
276 + "おこなう",
277 + "おこる",
278 + "おさえる",
279 + "おさない",
280 + "おさめる",
281 + "おしいれ",
282 + "おしえる",
283 + "おじぎ",
284 + "おじさん",
285 + "おしゃれ",
286 + "おそらく",
287 + "おそわる",
288 + "おたがい",
289 + "おたく",
290 + "おだやか",
291 + "おちつく",
292 + "おっと",
293 + "おつり",
294 + "おでかけ",
295 + "おとしもの",
296 + "おとなしい",
297 + "おどり",
298 + "おどろかす",
299 + "おばさん",
300 + "おまいり",
301 + "おめでとう",
302 + "おもいで",
303 + "おもう",
304 + "おもたい",
305 + "おもちゃ",
306 + "おやつ",
307 + "おやゆび",
308 + "およぼす",
309 + "おらんだ",
310 + "おろす",
311 + "おんがく",
312 + "おんけい",
313 + "おんしゃ",
314 + "おんせん",
315 + "おんだん",
316 + "おんちゅう",
317 + "おんどけい",
318 + "かあつ",
319 + "かいが",
320 + "がいき",
321 + "がいけん",
322 + "がいこう",
323 + "かいさつ",
324 + "かいしゃ",
325 + "かいすいよく",
326 + "かいぜん",
327 + "かいぞうど",
328 + "かいつう",
329 + "かいてん",
330 + "かいとう",
331 + "かいふく",
332 + "がいへき",
333 + "かいほう",
334 + "かいよう",
335 + "がいらい",
336 + "かいわ",
337 + "かえる",
338 + "かおり",
339 + "かかえる",
340 + "かがく",
341 + "かがし",
342 + "かがみ",
343 + "かくご",
344 + "かくとく",
345 + "かざる",
346 + "がぞう",
347 + "かたい",
348 + "かたち",
349 + "がちょう",
350 + "がっきゅう",
351 + "がっこう",
352 + "がっさん",
353 + "がっしょう",
354 + "かなざわし",
355 + "かのう",
356 + "がはく",
357 + "かぶか",
358 + "かほう",
359 + "かほご",
360 + "かまう",
361 + "かまぼこ",
362 + "かめれおん",
363 + "かゆい",
364 + "かようび",
365 + "からい",
366 + "かるい",
367 + "かろう",
368 + "かわく",
369 + "かわら",
370 + "がんか",
371 + "かんけい",
372 + "かんこう",
373 + "かんしゃ",
374 + "かんそう",
375 + "かんたん",
376 + "かんち",
377 + "がんばる",
378 + "きあい",
379 + "きあつ",
380 + "きいろ",
381 + "ぎいん",
382 + "きうい",
383 + "きうん",
384 + "きえる",
385 + "きおう",
386 + "きおく",
387 + "きおち",
388 + "きおん",
389 + "きかい",
390 + "きかく",
391 + "きかんしゃ",
392 + "ききて",
393 + "きくばり",
394 + "きくらげ",
395 + "きけんせい",
396 + "きこう",
397 + "きこえる",
398 + "きこく",
399 + "きさい",
400 + "きさく",
401 + "きさま",
402 + "きさらぎ",
403 + "ぎじかがく",
404 + "ぎしき",
405 + "ぎじたいけん",
406 + "ぎじにってい",
407 + "ぎじゅつしゃ",
408 + "きすう",
409 + "きせい",
410 + "きせき",
411 + "きせつ",
412 + "きそう",
413 + "きぞく",
414 + "きぞん",
415 + "きたえる",
416 + "きちょう",
417 + "きつえん",
418 + "ぎっちり",
419 + "きつつき",
420 + "きつね",
421 + "きてい",
422 + "きどう",
423 + "きどく",
424 + "きない",
425 + "きなが",
426 + "きなこ",
427 + "きぬごし",
428 + "きねん",
429 + "きのう",
430 + "きのした",
431 + "きはく",
432 + "きびしい",
433 + "きひん",
434 + "きふく",
435 + "きぶん",
436 + "きぼう",
437 + "きほん",
438 + "きまる",
439 + "きみつ",
440 + "きむずかしい",
441 + "きめる",
442 + "きもだめし",
443 + "きもち",
444 + "きもの",
445 + "きゃく",
446 + "きやく",
447 + "ぎゅうにく",
448 + "きよう",
449 + "きょうりゅう",
450 + "きらい",
451 + "きらく",
452 + "きりん",
453 + "きれい",
454 + "きれつ",
455 + "きろく",
456 + "ぎろん",
457 + "きわめる",
458 + "ぎんいろ",
459 + "きんかくじ",
460 + "きんじょ",
461 + "きんようび",
462 + "ぐあい",
463 + "くいず",
464 + "くうかん",
465 + "くうき",
466 + "くうぐん",
467 + "くうこう",
468 + "ぐうせい",
469 + "くうそう",
470 + "ぐうたら",
471 + "くうふく",
472 + "くうぼ",
473 + "くかん",
474 + "くきょう",
475 + "くげん",
476 + "ぐこう",
477 + "くさい",
478 + "くさき",
479 + "くさばな",
480 + "くさる",
481 + "くしゃみ",
482 + "くしょう",
483 + "くすのき",
484 + "くすりゆび",
485 + "くせげ",
486 + "くせん",
487 + "ぐたいてき",
488 + "くださる",
489 + "くたびれる",
490 + "くちこみ",
491 + "くちさき",
492 + "くつした",
493 + "ぐっすり",
494 + "くつろぐ",
495 + "くとうてん",
496 + "くどく",
497 + "くなん",
498 + "くねくね",
499 + "くのう",
500 + "くふう",
501 + "くみあわせ",
502 + "くみたてる",
503 + "くめる",
504 + "くやくしょ",
505 + "くらす",
506 + "くらべる",
507 + "くるま",
508 + "くれる",
509 + "くろう",
510 + "くわしい",
511 + "ぐんかん",
512 + "ぐんしょく",
513 + "ぐんたい",
514 + "ぐんて",
515 + "けあな",
516 + "けいかく",
517 + "けいけん",
518 + "けいこ",
519 + "けいさつ",
520 + "げいじゅつ",
521 + "けいたい",
522 + "げいのうじん",
523 + "けいれき",
524 + "けいろ",
525 + "けおとす",
526 + "けおりもの",
527 + "げきか",
528 + "げきげん",
529 + "げきだん",
530 + "げきちん",
531 + "げきとつ",
532 + "げきは",
533 + "げきやく",
534 + "げこう",
535 + "げこくじょう",
536 + "げざい",
537 + "けさき",
538 + "げざん",
539 + "けしき",
540 + "けしごむ",
541 + "けしょう",
542 + "げすと",
543 + "けたば",
544 + "けちゃっぷ",
545 + "けちらす",
546 + "けつあつ",
547 + "けつい",
548 + "けつえき",
549 + "けっこん",
550 + "けつじょ",
551 + "けっせき",
552 + "けってい",
553 + "けつまつ",
554 + "げつようび",
555 + "げつれい",
556 + "けつろん",
557 + "げどく",
558 + "けとばす",
559 + "けとる",
560 + "けなげ",
561 + "けなす",
562 + "けなみ",
563 + "けぬき",
564 + "げねつ",
565 + "けねん",
566 + "けはい",
567 + "げひん",
568 + "けぶかい",
569 + "げぼく",
570 + "けまり",
571 + "けみかる",
572 + "けむし",
573 + "けむり",
574 + "けもの",
575 + "けらい",
576 + "けろけろ",
577 + "けわしい",
578 + "けんい",
579 + "けんえつ",
580 + "けんお",
581 + "けんか",
582 + "げんき",
583 + "けんげん",
584 + "けんこう",
585 + "けんさく",
586 + "けんしゅう",
587 + "けんすう",
588 + "げんそう",
589 + "けんちく",
590 + "けんてい",
591 + "けんとう",
592 + "けんない",
593 + "けんにん",
594 + "げんぶつ",
595 + "けんま",
596 + "けんみん",
597 + "けんめい",
598 + "けんらん",
599 + "けんり",
600 + "こあくま",
601 + "こいぬ",
602 + "こいびと",
603 + "ごうい",
604 + "こうえん",
605 + "こうおん",
606 + "こうかん",
607 + "ごうきゅう",
608 + "ごうけい",
609 + "こうこう",
610 + "こうさい",
611 + "こうじ",
612 + "こうすい",
613 + "ごうせい",
614 + "こうそく",
615 + "こうたい",
616 + "こうちゃ",
617 + "こうつう",
618 + "こうてい",
619 + "こうどう",
620 + "こうない",
621 + "こうはい",
622 + "ごうほう",
623 + "ごうまん",
624 + "こうもく",
625 + "こうりつ",
626 + "こえる",
627 + "こおり",
628 + "ごかい",
629 + "ごがつ",
630 + "ごかん",
631 + "こくご",
632 + "こくさい",
633 + "こくとう",
634 + "こくない",
635 + "こくはく",
636 + "こぐま",
637 + "こけい",
638 + "こける",
639 + "ここのか",
640 + "こころ",
641 + "こさめ",
642 + "こしつ",
643 + "こすう",
644 + "こせい",
645 + "こせき",
646 + "こぜん",
647 + "こそだて",
648 + "こたい",
649 + "こたえる",
650 + "こたつ",
651 + "こちょう",
652 + "こっか",
653 + "こつこつ",
654 + "こつばん",
655 + "こつぶ",
656 + "こてい",
657 + "こてん",
658 + "ことがら",
659 + "ことし",
660 + "ことば",
661 + "ことり",
662 + "こなごな",
663 + "こねこね",
664 + "このまま",
665 + "このみ",
666 + "このよ",
667 + "ごはん",
668 + "こひつじ",
669 + "こふう",
670 + "こふん",
671 + "こぼれる",
672 + "ごまあぶら",
673 + "こまかい",
674 + "ごますり",
675 + "こまつな",
676 + "こまる",
677 + "こむぎこ",
678 + "こもじ",
679 + "こもち",
680 + "こもの",
681 + "こもん",
682 + "こやく",
683 + "こやま",
684 + "こゆう",
685 + "こゆび",
686 + "こよい",
687 + "こよう",
688 + "こりる",
689 + "これくしょん",
690 + "ころっけ",
691 + "こわもて",
692 + "こわれる",
693 + "こんいん",
694 + "こんかい",
695 + "こんき",
696 + "こんしゅう",
697 + "こんすい",
698 + "こんだて",
699 + "こんとん",
700 + "こんなん",
701 + "こんびに",
702 + "こんぽん",
703 + "こんまけ",
704 + "こんや",
705 + "こんれい",
706 + "こんわく",
707 + "ざいえき",
708 + "さいかい",
709 + "さいきん",
710 + "ざいげん",
711 + "ざいこ",
712 + "さいしょ",
713 + "さいせい",
714 + "ざいたく",
715 + "ざいちゅう",
716 + "さいてき",
717 + "ざいりょう",
718 + "さうな",
719 + "さかいし",
720 + "さがす",
721 + "さかな",
722 + "さかみち",
723 + "さがる",
724 + "さぎょう",
725 + "さくし",
726 + "さくひん",
727 + "さくら",
728 + "さこく",
729 + "さこつ",
730 + "さずかる",
731 + "ざせき",
732 + "さたん",
733 + "さつえい",
734 + "ざつおん",
735 + "ざっか",
736 + "ざつがく",
737 + "さっきょく",
738 + "ざっし",
739 + "さつじん",
740 + "ざっそう",
741 + "さつたば",
742 + "さつまいも",
743 + "さてい",
744 + "さといも",
745 + "さとう",
746 + "さとおや",
747 + "さとし",
748 + "さとる",
749 + "さのう",
750 + "さばく",
751 + "さびしい",
752 + "さべつ",
753 + "さほう",
754 + "さほど",
755 + "さます",
756 + "さみしい",
757 + "さみだれ",
758 + "さむけ",
759 + "さめる",
760 + "さやえんどう",
761 + "さゆう",
762 + "さよう",
763 + "さよく",
764 + "さらだ",
765 + "ざるそば",
766 + "さわやか",
767 + "さわる",
768 + "さんいん",
769 + "さんか",
770 + "さんきゃく",
771 + "さんこう",
772 + "さんさい",
773 + "ざんしょ",
774 + "さんすう",
775 + "さんせい",
776 + "さんそ",
777 + "さんち",
778 + "さんま",
779 + "さんみ",
780 + "さんらん",
781 + "しあい",
782 + "しあげ",
783 + "しあさって",
784 + "しあわせ",
785 + "しいく",
786 + "しいん",
787 + "しうち",
788 + "しえい",
789 + "しおけ",
790 + "しかい",
791 + "しかく",
792 + "じかん",
793 + "しごと",
794 + "しすう",
795 + "じだい",
796 + "したうけ",
797 + "したぎ",
798 + "したて",
799 + "したみ",
800 + "しちょう",
801 + "しちりん",
802 + "しっかり",
803 + "しつじ",
804 + "しつもん",
805 + "してい",
806 + "してき",
807 + "してつ",
808 + "じてん",
809 + "じどう",
810 + "しなぎれ",
811 + "しなもの",
812 + "しなん",
813 + "しねま",
814 + "しねん",
815 + "しのぐ",
816 + "しのぶ",
817 + "しはい",
818 + "しばかり",
819 + "しはつ",
820 + "しはらい",
821 + "しはん",
822 + "しひょう",
823 + "しふく",
824 + "じぶん",
825 + "しへい",
826 + "しほう",
827 + "しほん",
828 + "しまう",
829 + "しまる",
830 + "しみん",
831 + "しむける",
832 + "じむしょ",
833 + "しめい",
834 + "しめる",
835 + "しもん",
836 + "しゃいん",
837 + "しゃうん",
838 + "しゃおん",
839 + "じゃがいも",
840 + "しやくしょ",
841 + "しゃくほう",
842 + "しゃけん",
843 + "しゃこ",
844 + "しゃざい",
845 + "しゃしん",
846 + "しゃせん",
847 + "しゃそう",
848 + "しゃたい",
849 + "しゃちょう",
850 + "しゃっきん",
851 + "じゃま",
852 + "しゃりん",
853 + "しゃれい",
854 + "じゆう",
855 + "じゅうしょ",
856 + "しゅくはく",
857 + "じゅしん",
858 + "しゅっせき",
859 + "しゅみ",
860 + "しゅらば",
861 + "じゅんばん",
862 + "しょうかい",
863 + "しょくたく",
864 + "しょっけん",
865 + "しょどう",
866 + "しょもつ",
867 + "しらせる",
868 + "しらべる",
869 + "しんか",
870 + "しんこう",
871 + "じんじゃ",
872 + "しんせいじ",
873 + "しんちく",
874 + "しんりん",
875 + "すあげ",
876 + "すあし",
877 + "すあな",
878 + "ずあん",
879 + "すいえい",
880 + "すいか",
881 + "すいとう",
882 + "ずいぶん",
883 + "すいようび",
884 + "すうがく",
885 + "すうじつ",
886 + "すうせん",
887 + "すおどり",
888 + "すきま",
889 + "すくう",
890 + "すくない",
891 + "すける",
892 + "すごい",
893 + "すこし",
894 + "ずさん",
895 + "すずしい",
896 + "すすむ",
897 + "すすめる",
898 + "すっかり",
899 + "ずっしり",
900 + "ずっと",
901 + "すてき",
902 + "すてる",
903 + "すねる",
904 + "すのこ",
905 + "すはだ",
906 + "すばらしい",
907 + "ずひょう",
908 + "ずぶぬれ",
909 + "すぶり",
910 + "すふれ",
911 + "すべて",
912 + "すべる",
913 + "ずほう",
914 + "すぼん",
915 + "すまい",
916 + "すめし",
917 + "すもう",
918 + "すやき",
919 + "すらすら",
920 + "するめ",
921 + "すれちがう",
922 + "すろっと",
923 + "すわる",
924 + "すんぜん",
925 + "すんぽう",
926 + "せあぶら",
927 + "せいかつ",
928 + "せいげん",
929 + "せいじ",
930 + "せいよう",
931 + "せおう",
932 + "せかいかん",
933 + "せきにん",
934 + "せきむ",
935 + "せきゆ",
936 + "せきらんうん",
937 + "せけん",
938 + "せこう",
939 + "せすじ",
940 + "せたい",
941 + "せたけ",
942 + "せっかく",
943 + "せっきゃく",
944 + "ぜっく",
945 + "せっけん",
946 + "せっこつ",
947 + "せっさたくま",
948 + "せつぞく",
949 + "せつだん",
950 + "せつでん",
951 + "せっぱん",
952 + "せつび",
953 + "せつぶん",
954 + "せつめい",
955 + "せつりつ",
956 + "せなか",
957 + "せのび",
958 + "せはば",
959 + "せびろ",
960 + "せぼね",
961 + "せまい",
962 + "せまる",
963 + "せめる",
964 + "せもたれ",
965 + "せりふ",
966 + "ぜんあく",
967 + "せんい",
968 + "せんえい",
969 + "せんか",
970 + "せんきょ",
971 + "せんく",
972 + "せんげん",
973 + "ぜんご",
974 + "せんさい",
975 + "せんしゅ",
976 + "せんすい",
977 + "せんせい",
978 + "せんぞ",
979 + "せんたく",
980 + "せんちょう",
981 + "せんてい",
982 + "せんとう",
983 + "せんぬき",
984 + "せんねん",
985 + "せんぱい",
986 + "ぜんぶ",
987 + "ぜんぽう",
988 + "せんむ",
989 + "せんめんじょ",
990 + "せんもん",
991 + "せんやく",
992 + "せんゆう",
993 + "せんよう",
994 + "ぜんら",
995 + "ぜんりゃく",
996 + "せんれい",
997 + "せんろ",
998 + "そあく",
999 + "そいとげる",
1000 + "そいね",
1001 + "そうがんきょう",
1002 + "そうき",
1003 + "そうご",
1004 + "そうしん",
1005 + "そうだん",
1006 + "そうなん",
1007 + "そうび",
1008 + "そうめん",
1009 + "そうり",
1010 + "そえもの",
1011 + "そえん",
1012 + "そがい",
1013 + "そげき",
1014 + "そこう",
1015 + "そこそこ",
1016 + "そざい",
1017 + "そしな",
1018 + "そせい",
1019 + "そせん",
1020 + "そそぐ",
1021 + "そだてる",
1022 + "そつう",
1023 + "そつえん",
1024 + "そっかん",
1025 + "そつぎょう",
1026 + "そっけつ",
1027 + "そっこう",
1028 + "そっせん",
1029 + "そっと",
1030 + "そとがわ",
1031 + "そとづら",
1032 + "そなえる",
1033 + "そなた",
1034 + "そふぼ",
1035 + "そぼく",
1036 + "そぼろ",
1037 + "そまつ",
1038 + "そまる",
1039 + "そむく",
1040 + "そむりえ",
1041 + "そめる",
1042 + "そもそも",
1043 + "そよかぜ",
1044 + "そらまめ",
1045 + "そろう",
1046 + "そんかい",
1047 + "そんけい",
1048 + "そんざい",
1049 + "そんしつ",
1050 + "そんぞく",
1051 + "そんちょう",
1052 + "ぞんび",
1053 + "ぞんぶん",
1054 + "そんみん",
1055 + "たあい",
1056 + "たいいん",
1057 + "たいうん",
1058 + "たいえき",
1059 + "たいおう",
1060 + "だいがく",
1061 + "たいき",
1062 + "たいぐう",
1063 + "たいけん",
1064 + "たいこ",
1065 + "たいざい",
1066 + "だいじょうぶ",
1067 + "だいすき",
1068 + "たいせつ",
1069 + "たいそう",
1070 + "だいたい",
1071 + "たいちょう",
1072 + "たいてい",
1073 + "だいどころ",
1074 + "たいない",
1075 + "たいねつ",
1076 + "たいのう",
1077 + "たいはん",
1078 + "だいひょう",
1079 + "たいふう",
1080 + "たいへん",
1081 + "たいほ",
1082 + "たいまつばな",
1083 + "たいみんぐ",
1084 + "たいむ",
1085 + "たいめん",
1086 + "たいやき",
1087 + "たいよう",
1088 + "たいら",
1089 + "たいりょく",
1090 + "たいる",
1091 + "たいわん",
1092 + "たうえ",
1093 + "たえる",
1094 + "たおす",
1095 + "たおる",
1096 + "たおれる",
1097 + "たかい",
1098 + "たかね",
1099 + "たきび",
1100 + "たくさん",
1101 + "たこく",
1102 + "たこやき",
1103 + "たさい",
1104 + "たしざん",
1105 + "だじゃれ",
1106 + "たすける",
1107 + "たずさわる",
1108 + "たそがれ",
1109 + "たたかう",
1110 + "たたく",
1111 + "ただしい",
1112 + "たたみ",
1113 + "たちばな",
1114 + "だっかい",
1115 + "だっきゃく",
1116 + "だっこ",
1117 + "だっしゅつ",
1118 + "だったい",
1119 + "たてる",
1120 + "たとえる",
1121 + "たなばた",
1122 + "たにん",
1123 + "たぬき",
1124 + "たのしみ",
1125 + "たはつ",
1126 + "たぶん",
1127 + "たべる",
1128 + "たぼう",
1129 + "たまご",
1130 + "たまる",
1131 + "だむる",
1132 + "ためいき",
1133 + "ためす",
1134 + "ためる",
1135 + "たもつ",
1136 + "たやすい",
1137 + "たよる",
1138 + "たらす",
1139 + "たりきほんがん",
1140 + "たりょう",
1141 + "たりる",
1142 + "たると",
1143 + "たれる",
1144 + "たれんと",
1145 + "たろっと",
1146 + "たわむれる",
1147 + "だんあつ",
1148 + "たんい",
1149 + "たんおん",
1150 + "たんか",
1151 + "たんき",
1152 + "たんけん",
1153 + "たんご",
1154 + "たんさん",
1155 + "たんじょうび",
1156 + "だんせい",
1157 + "たんそく",
1158 + "たんたい",
1159 + "だんち",
1160 + "たんてい",
1161 + "たんとう",
1162 + "だんな",
1163 + "たんにん",
1164 + "だんねつ",
1165 + "たんのう",
1166 + "たんぴん",
1167 + "だんぼう",
1168 + "たんまつ",
1169 + "たんめい",
1170 + "だんれつ",
1171 + "だんろ",
1172 + "だんわ",
1173 + "ちあい",
1174 + "ちあん",
1175 + "ちいき",
1176 + "ちいさい",
1177 + "ちえん",
1178 + "ちかい",
1179 + "ちから",
1180 + "ちきゅう",
1181 + "ちきん",
1182 + "ちけいず",
1183 + "ちけん",
1184 + "ちこく",
1185 + "ちさい",
1186 + "ちしき",
1187 + "ちしりょう",
1188 + "ちせい",
1189 + "ちそう",
1190 + "ちたい",
1191 + "ちたん",
1192 + "ちちおや",
1193 + "ちつじょ",
1194 + "ちてき",
1195 + "ちてん",
1196 + "ちぬき",
1197 + "ちぬり",
1198 + "ちのう",
1199 + "ちひょう",
1200 + "ちへいせん",
1201 + "ちほう",
1202 + "ちまた",
1203 + "ちみつ",
1204 + "ちみどろ",
1205 + "ちめいど",
1206 + "ちゃんこなべ",
1207 + "ちゅうい",
1208 + "ちゆりょく",
1209 + "ちょうし",
1210 + "ちょさくけん",
1211 + "ちらし",
1212 + "ちらみ",
1213 + "ちりがみ",
1214 + "ちりょう",
1215 + "ちるど",
1216 + "ちわわ",
1217 + "ちんたい",
1218 + "ちんもく",
1219 + "ついか",
1220 + "ついたち",
1221 + "つうか",
1222 + "つうじょう",
1223 + "つうはん",
1224 + "つうわ",
1225 + "つかう",
1226 + "つかれる",
1227 + "つくね",
1228 + "つくる",
1229 + "つけね",
1230 + "つける",
1231 + "つごう",
1232 + "つたえる",
1233 + "つづく",
1234 + "つつじ",
1235 + "つつむ",
1236 + "つとめる",
1237 + "つながる",
1238 + "つなみ",
1239 + "つねづね",
1240 + "つのる",
1241 + "つぶす",
1242 + "つまらない",
1243 + "つまる",
1244 + "つみき",
1245 + "つめたい",
1246 + "つもり",
1247 + "つもる",
1248 + "つよい",
1249 + "つるぼ",
1250 + "つるみく",
1251 + "つわもの",
1252 + "つわり",
1253 + "てあし",
1254 + "てあて",
1255 + "てあみ",
1256 + "ていおん",
1257 + "ていか",
1258 + "ていき",
1259 + "ていけい",
1260 + "ていこく",
1261 + "ていさつ",
1262 + "ていし",
1263 + "ていせい",
1264 + "ていたい",
1265 + "ていど",
1266 + "ていねい",
1267 + "ていひょう",
1268 + "ていへん",
1269 + "ていぼう",
1270 + "てうち",
1271 + "ておくれ",
1272 + "てきとう",
1273 + "てくび",
1274 + "でこぼこ",
1275 + "てさぎょう",
1276 + "てさげ",
1277 + "てすり",
1278 + "てそう",
1279 + "てちがい",
1280 + "てちょう",
1281 + "てつがく",
1282 + "てつづき",
1283 + "でっぱ",
1284 + "てつぼう",
1285 + "てつや",
1286 + "でぬかえ",
1287 + "てぬき",
1288 + "てぬぐい",
1289 + "てのひら",
1290 + "てはい",
1291 + "てぶくろ",
1292 + "てふだ",
1293 + "てほどき",
1294 + "てほん",
1295 + "てまえ",
1296 + "てまきずし",
1297 + "てみじか",
1298 + "てみやげ",
1299 + "てらす",
1300 + "てれび",
1301 + "てわけ",
1302 + "てわたし",
1303 + "でんあつ",
1304 + "てんいん",
1305 + "てんかい",
1306 + "てんき",
1307 + "てんぐ",
1308 + "てんけん",
1309 + "てんごく",
1310 + "てんさい",
1311 + "てんし",
1312 + "てんすう",
1313 + "でんち",
1314 + "てんてき",
1315 + "てんとう",
1316 + "てんない",
1317 + "てんぷら",
1318 + "てんぼうだい",
1319 + "てんめつ",
1320 + "てんらんかい",
1321 + "でんりょく",
1322 + "でんわ",
1323 + "どあい",
1324 + "といれ",
1325 + "どうかん",
1326 + "とうきゅう",
1327 + "どうぐ",
1328 + "とうし",
1329 + "とうむぎ",
1330 + "とおい",
1331 + "とおか",
1332 + "とおく",
1333 + "とおす",
1334 + "とおる",
1335 + "とかい",
1336 + "とかす",
1337 + "ときおり",
1338 + "ときどき",
1339 + "とくい",
1340 + "とくしゅう",
1341 + "とくてん",
1342 + "とくに",
1343 + "とくべつ",
1344 + "とけい",
1345 + "とける",
1346 + "とこや",
1347 + "とさか",
1348 + "としょかん",
1349 + "とそう",
1350 + "とたん",
1351 + "とちゅう",
1352 + "とっきゅう",
1353 + "とっくん",
1354 + "とつぜん",
1355 + "とつにゅう",
1356 + "とどける",
1357 + "ととのえる",
1358 + "とない",
1359 + "となえる",
1360 + "となり",
1361 + "とのさま",
1362 + "とばす",
1363 + "どぶがわ",
1364 + "とほう",
1365 + "とまる",
1366 + "とめる",
1367 + "ともだち",
1368 + "ともる",
1369 + "どようび",
1370 + "とらえる",
1371 + "とんかつ",
1372 + "どんぶり",
1373 + "ないかく",
1374 + "ないこう",
1375 + "ないしょ",
1376 + "ないす",
1377 + "ないせん",
1378 + "ないそう",
1379 + "なおす",
1380 + "ながい",
1381 + "なくす",
1382 + "なげる",
1383 + "なこうど",
1384 + "なさけ",
1385 + "なたでここ",
1386 + "なっとう",
1387 + "なつやすみ",
1388 + "ななおし",
1389 + "なにごと",
1390 + "なにもの",
1391 + "なにわ",
1392 + "なのか",
1393 + "なふだ",
1394 + "なまいき",
1395 + "なまえ",
1396 + "なまみ",
1397 + "なみだ",
1398 + "なめらか",
1399 + "なめる",
1400 + "なやむ",
1401 + "ならう",
1402 + "ならび",
1403 + "ならぶ",
1404 + "なれる",
1405 + "なわとび",
1406 + "なわばり",
1407 + "にあう",
1408 + "にいがた",
1409 + "にうけ",
1410 + "におい",
1411 + "にかい",
1412 + "にがて",
1413 + "にきび",
1414 + "にくしみ",
1415 + "にくまん",
1416 + "にげる",
1417 + "にさんかたんそ",
1418 + "にしき",
1419 + "にせもの",
1420 + "にちじょう",
1421 + "にちようび",
1422 + "にっか",
1423 + "にっき",
1424 + "にっけい",
1425 + "にっこう",
1426 + "にっさん",
1427 + "にっしょく",
1428 + "にっすう",
1429 + "にっせき",
1430 + "にってい",
1431 + "になう",
1432 + "にほん",
1433 + "にまめ",
1434 + "にもつ",
1435 + "にやり",
1436 + "にゅういん",
1437 + "にりんしゃ",
1438 + "にわとり",
1439 + "にんい",
1440 + "にんか",
1441 + "にんき",
1442 + "にんげん",
1443 + "にんしき",
1444 + "にんずう",
1445 + "にんそう",
1446 + "にんたい",
1447 + "にんち",
1448 + "にんてい",
1449 + "にんにく",
1450 + "にんぷ",
1451 + "にんまり",
1452 + "にんむ",
1453 + "にんめい",
1454 + "にんよう",
1455 + "ぬいくぎ",
1456 + "ぬかす",
1457 + "ぬぐいとる",
1458 + "ぬぐう",
1459 + "ぬくもり",
1460 + "ぬすむ",
1461 + "ぬまえび",
1462 + "ぬめり",
1463 + "ぬらす",
1464 + "ぬんちゃく",
1465 + "ねあげ",
1466 + "ねいき",
1467 + "ねいる",
1468 + "ねいろ",
1469 + "ねぐせ",
1470 + "ねくたい",
1471 + "ねくら",
1472 + "ねこぜ",
1473 + "ねこむ",
1474 + "ねさげ",
1475 + "ねすごす",
1476 + "ねそべる",
1477 + "ねだん",
1478 + "ねつい",
1479 + "ねっしん",
1480 + "ねつぞう",
1481 + "ねったいぎょ",
1482 + "ねぶそく",
1483 + "ねふだ",
1484 + "ねぼう",
1485 + "ねほりはほり",
1486 + "ねまき",
1487 + "ねまわし",
1488 + "ねみみ",
1489 + "ねむい",
1490 + "ねむたい",
1491 + "ねもと",
1492 + "ねらう",
1493 + "ねわざ",
1494 + "ねんいり",
1495 + "ねんおし",
1496 + "ねんかん",
1497 + "ねんきん",
1498 + "ねんぐ",
1499 + "ねんざ",
1500 + "ねんし",
1501 + "ねんちゃく",
1502 + "ねんど",
1503 + "ねんぴ",
1504 + "ねんぶつ",
1505 + "ねんまつ",
1506 + "ねんりょう",
1507 + "ねんれい",
1508 + "のいず",
1509 + "のおづま",
1510 + "のがす",
1511 + "のきなみ",
1512 + "のこぎり",
1513 + "のこす",
1514 + "のこる",
1515 + "のせる",
1516 + "のぞく",
1517 + "のぞむ",
1518 + "のたまう",
1519 + "のちほど",
1520 + "のっく",
1521 + "のばす",
1522 + "のはら",
1523 + "のべる",
1524 + "のぼる",
1525 + "のみもの",
1526 + "のやま",
1527 + "のらいぬ",
1528 + "のらねこ",
1529 + "のりもの",
1530 + "のりゆき",
1531 + "のれん",
1532 + "のんき",
1533 + "ばあい",
1534 + "はあく",
1535 + "ばあさん",
1536 + "ばいか",
1537 + "ばいく",
1538 + "はいけん",
1539 + "はいご",
1540 + "はいしん",
1541 + "はいすい",
1542 + "はいせん",
1543 + "はいそう",
1544 + "はいち",
1545 + "ばいばい",
1546 + "はいれつ",
1547 + "はえる",
1548 + "はおる",
1549 + "はかい",
1550 + "ばかり",
1551 + "はかる",
1552 + "はくしゅ",
1553 + "はけん",
1554 + "はこぶ",
1555 + "はさみ",
1556 + "はさん",
1557 + "はしご",
1558 + "ばしょ",
1559 + "はしる",
1560 + "はせる",
1561 + "ぱそこん",
1562 + "はそん",
1563 + "はたん",
1564 + "はちみつ",
1565 + "はつおん",
1566 + "はっかく",
1567 + "はづき",
1568 + "はっきり",
1569 + "はっくつ",
1570 + "はっけん",
1571 + "はっこう",
1572 + "はっさん",
1573 + "はっしん",
1574 + "はったつ",
1575 + "はっちゅう",
1576 + "はってん",
1577 + "はっぴょう",
1578 + "はっぽう",
1579 + "はなす",
1580 + "はなび",
1581 + "はにかむ",
1582 + "はぶらし",
1583 + "はみがき",
1584 + "はむかう",
1585 + "はめつ",
1586 + "はやい",
1587 + "はやし",
1588 + "はらう",
1589 + "はろうぃん",
1590 + "はわい",
1591 + "はんい",
1592 + "はんえい",
1593 + "はんおん",
1594 + "はんかく",
1595 + "はんきょう",
1596 + "ばんぐみ",
1597 + "はんこ",
1598 + "はんしゃ",
1599 + "はんすう",
1600 + "はんだん",
1601 + "ぱんち",
1602 + "ぱんつ",
1603 + "はんてい",
1604 + "はんとし",
1605 + "はんのう",
1606 + "はんぱ",
1607 + "はんぶん",
1608 + "はんぺん",
1609 + "はんぼうき",
1610 + "はんめい",
1611 + "はんらん",
1612 + "はんろん",
1613 + "ひいき",
1614 + "ひうん",
1615 + "ひえる",
1616 + "ひかく",
1617 + "ひかり",
1618 + "ひかる",
1619 + "ひかん",
1620 + "ひくい",
1621 + "ひけつ",
1622 + "ひこうき",
1623 + "ひこく",
1624 + "ひさい",
1625 + "ひさしぶり",
1626 + "ひさん",
1627 + "びじゅつかん",
1628 + "ひしょ"
1629 + ];
1630 +}
\ No newline at end of file
cw_monero/lib/mnemonics/portuguese.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class PortugueseMnemonics {
2 + static const words = [
3 + "abaular",
4 + "abdominal",
5 + "abeto",
6 + "abissinio",
7 + "abjeto",
8 + "ablucao",
9 + "abnegar",
10 + "abotoar",
11 + "abrutalhar",
12 + "absurdo",
13 + "abutre",
14 + "acautelar",
15 + "accessorios",
16 + "acetona",
17 + "achocolatado",
18 + "acirrar",
19 + "acne",
20 + "acovardar",
21 + "acrostico",
22 + "actinomicete",
23 + "acustico",
24 + "adaptavel",
25 + "adeus",
26 + "adivinho",
27 + "adjunto",
28 + "admoestar",
29 + "adnominal",
30 + "adotivo",
31 + "adquirir",
32 + "adriatico",
33 + "adsorcao",
34 + "adutora",
35 + "advogar",
36 + "aerossol",
37 + "afazeres",
38 + "afetuoso",
39 + "afixo",
40 + "afluir",
41 + "afortunar",
42 + "afrouxar",
43 + "aftosa",
44 + "afunilar",
45 + "agentes",
46 + "agito",
47 + "aglutinar",
48 + "aiatola",
49 + "aimore",
50 + "aino",
51 + "aipo",
52 + "airoso",
53 + "ajeitar",
54 + "ajoelhar",
55 + "ajudante",
56 + "ajuste",
57 + "alazao",
58 + "albumina",
59 + "alcunha",
60 + "alegria",
61 + "alexandre",
62 + "alforriar",
63 + "alguns",
64 + "alhures",
65 + "alivio",
66 + "almoxarife",
67 + "alotropico",
68 + "alpiste",
69 + "alquimista",
70 + "alsaciano",
71 + "altura",
72 + "aluviao",
73 + "alvura",
74 + "amazonico",
75 + "ambulatorio",
76 + "ametodico",
77 + "amizades",
78 + "amniotico",
79 + "amovivel",
80 + "amurada",
81 + "anatomico",
82 + "ancorar",
83 + "anexo",
84 + "anfora",
85 + "aniversario",
86 + "anjo",
87 + "anotar",
88 + "ansioso",
89 + "anturio",
90 + "anuviar",
91 + "anverso",
92 + "anzol",
93 + "aonde",
94 + "apaziguar",
95 + "apito",
96 + "aplicavel",
97 + "apoteotico",
98 + "aprimorar",
99 + "aprumo",
100 + "apto",
101 + "apuros",
102 + "aquoso",
103 + "arauto",
104 + "arbusto",
105 + "arduo",
106 + "aresta",
107 + "arfar",
108 + "arguto",
109 + "aritmetico",
110 + "arlequim",
111 + "armisticio",
112 + "aromatizar",
113 + "arpoar",
114 + "arquivo",
115 + "arrumar",
116 + "arsenio",
117 + "arturiano",
118 + "aruaque",
119 + "arvores",
120 + "asbesto",
121 + "ascorbico",
122 + "aspirina",
123 + "asqueroso",
124 + "assustar",
125 + "astuto",
126 + "atazanar",
127 + "ativo",
128 + "atletismo",
129 + "atmosferico",
130 + "atormentar",
131 + "atroz",
132 + "aturdir",
133 + "audivel",
134 + "auferir",
135 + "augusto",
136 + "aula",
137 + "aumento",
138 + "aurora",
139 + "autuar",
140 + "avatar",
141 + "avexar",
142 + "avizinhar",
143 + "avolumar",
144 + "avulso",
145 + "axiomatico",
146 + "azerbaijano",
147 + "azimute",
148 + "azoto",
149 + "azulejo",
150 + "bacteriologista",
151 + "badulaque",
152 + "baforada",
153 + "baixote",
154 + "bajular",
155 + "balzaquiana",
156 + "bambuzal",
157 + "banzo",
158 + "baoba",
159 + "baqueta",
160 + "barulho",
161 + "bastonete",
162 + "batuta",
163 + "bauxita",
164 + "bavaro",
165 + "bazuca",
166 + "bcrepuscular",
167 + "beato",
168 + "beduino",
169 + "begonia",
170 + "behaviorista",
171 + "beisebol",
172 + "belzebu",
173 + "bemol",
174 + "benzido",
175 + "beocio",
176 + "bequer",
177 + "berro",
178 + "besuntar",
179 + "betume",
180 + "bexiga",
181 + "bezerro",
182 + "biatlon",
183 + "biboca",
184 + "bicuspide",
185 + "bidirecional",
186 + "bienio",
187 + "bifurcar",
188 + "bigorna",
189 + "bijuteria",
190 + "bimotor",
191 + "binormal",
192 + "bioxido",
193 + "bipolarizacao",
194 + "biquini",
195 + "birutice",
196 + "bisturi",
197 + "bituca",
198 + "biunivoco",
199 + "bivalve",
200 + "bizarro",
201 + "blasfemo",
202 + "blenorreia",
203 + "blindar",
204 + "bloqueio",
205 + "blusao",
206 + "boazuda",
207 + "bofete",
208 + "bojudo",
209 + "bolso",
210 + "bombordo",
211 + "bonzo",
212 + "botina",
213 + "boquiaberto",
214 + "bostoniano",
215 + "botulismo",
216 + "bourbon",
217 + "bovino",
218 + "boximane",
219 + "bravura",
220 + "brevidade",
221 + "britar",
222 + "broxar",
223 + "bruno",
224 + "bruxuleio",
225 + "bubonico",
226 + "bucolico",
227 + "buda",
228 + "budista",
229 + "bueiro",
230 + "buffer",
231 + "bugre",
232 + "bujao",
233 + "bumerangue",
234 + "burundines",
235 + "busto",
236 + "butique",
237 + "buzios",
238 + "caatinga",
239 + "cabuqui",
240 + "cacunda",
241 + "cafuzo",
242 + "cajueiro",
243 + "camurca",
244 + "canudo",
245 + "caquizeiro",
246 + "carvoeiro",
247 + "casulo",
248 + "catuaba",
249 + "cauterizar",
250 + "cebolinha",
251 + "cedula",
252 + "ceifeiro",
253 + "celulose",
254 + "cerzir",
255 + "cesto",
256 + "cetro",
257 + "ceus",
258 + "cevar",
259 + "chavena",
260 + "cheroqui",
261 + "chita",
262 + "chovido",
263 + "chuvoso",
264 + "ciatico",
265 + "cibernetico",
266 + "cicuta",
267 + "cidreira",
268 + "cientistas",
269 + "cifrar",
270 + "cigarro",
271 + "cilio",
272 + "cimo",
273 + "cinzento",
274 + "cioso",
275 + "cipriota",
276 + "cirurgico",
277 + "cisto",
278 + "citrico",
279 + "ciumento",
280 + "civismo",
281 + "clavicula",
282 + "clero",
283 + "clitoris",
284 + "cluster",
285 + "coaxial",
286 + "cobrir",
287 + "cocota",
288 + "codorniz",
289 + "coexistir",
290 + "cogumelo",
291 + "coito",
292 + "colusao",
293 + "compaixao",
294 + "comutativo",
295 + "contentamento",
296 + "convulsivo",
297 + "coordenativa",
298 + "coquetel",
299 + "correto",
300 + "corvo",
301 + "costureiro",
302 + "cotovia",
303 + "covil",
304 + "cozinheiro",
305 + "cretino",
306 + "cristo",
307 + "crivo",
308 + "crotalo",
309 + "cruzes",
310 + "cubo",
311 + "cucuia",
312 + "cueiro",
313 + "cuidar",
314 + "cujo",
315 + "cultural",
316 + "cunilingua",
317 + "cupula",
318 + "curvo",
319 + "custoso",
320 + "cutucar",
321 + "czarismo",
322 + "dablio",
323 + "dacota",
324 + "dados",
325 + "daguerreotipo",
326 + "daiquiri",
327 + "daltonismo",
328 + "damista",
329 + "dantesco",
330 + "daquilo",
331 + "darwinista",
332 + "dasein",
333 + "dativo",
334 + "deao",
335 + "debutantes",
336 + "decurso",
337 + "deduzir",
338 + "defunto",
339 + "degustar",
340 + "dejeto",
341 + "deltoide",
342 + "demover",
343 + "denunciar",
344 + "deputado",
345 + "deque",
346 + "dervixe",
347 + "desvirtuar",
348 + "deturpar",
349 + "deuteronomio",
350 + "devoto",
351 + "dextrose",
352 + "dezoito",
353 + "diatribe",
354 + "dicotomico",
355 + "didatico",
356 + "dietista",
357 + "difuso",
358 + "digressao",
359 + "diluvio",
360 + "diminuto",
361 + "dinheiro",
362 + "dinossauro",
363 + "dioxido",
364 + "diplomatico",
365 + "dique",
366 + "dirimivel",
367 + "disturbio",
368 + "diurno",
369 + "divulgar",
370 + "dizivel",
371 + "doar",
372 + "dobro",
373 + "docura",
374 + "dodoi",
375 + "doer",
376 + "dogue",
377 + "doloso",
378 + "domo",
379 + "donzela",
380 + "doping",
381 + "dorsal",
382 + "dossie",
383 + "dote",
384 + "doutro",
385 + "doze",
386 + "dravidico",
387 + "dreno",
388 + "driver",
389 + "dropes",
390 + "druso",
391 + "dubnio",
392 + "ducto",
393 + "dueto",
394 + "dulija",
395 + "dundum",
396 + "duodeno",
397 + "duquesa",
398 + "durou",
399 + "duvidoso",
400 + "duzia",
401 + "ebano",
402 + "ebrio",
403 + "eburneo",
404 + "echarpe",
405 + "eclusa",
406 + "ecossistema",
407 + "ectoplasma",
408 + "ecumenismo",
409 + "eczema",
410 + "eden",
411 + "editorial",
412 + "edredom",
413 + "edulcorar",
414 + "efetuar",
415 + "efigie",
416 + "efluvio",
417 + "egiptologo",
418 + "egresso",
419 + "egua",
420 + "einsteiniano",
421 + "eira",
422 + "eivar",
423 + "eixos",
424 + "ejetar",
425 + "elastomero",
426 + "eldorado",
427 + "elixir",
428 + "elmo",
429 + "eloquente",
430 + "elucidativo",
431 + "emaranhar",
432 + "embutir",
433 + "emerito",
434 + "emfa",
435 + "emitir",
436 + "emotivo",
437 + "empuxo",
438 + "emulsao",
439 + "enamorar",
440 + "encurvar",
441 + "enduro",
442 + "enevoar",
443 + "enfurnar",
444 + "enguico",
445 + "enho",
446 + "enigmista",
447 + "enlutar",
448 + "enormidade",
449 + "enpreendimento",
450 + "enquanto",
451 + "enriquecer",
452 + "enrugar",
453 + "entusiastico",
454 + "enunciar",
455 + "envolvimento",
456 + "enxuto",
457 + "enzimatico",
458 + "eolico",
459 + "epiteto",
460 + "epoxi",
461 + "epura",
462 + "equivoco",
463 + "erario",
464 + "erbio",
465 + "ereto",
466 + "erguido",
467 + "erisipela",
468 + "ermo",
469 + "erotizar",
470 + "erros",
471 + "erupcao",
472 + "ervilha",
473 + "esburacar",
474 + "escutar",
475 + "esfuziante",
476 + "esguio",
477 + "esloveno",
478 + "esmurrar",
479 + "esoterismo",
480 + "esperanca",
481 + "espirito",
482 + "espurio",
483 + "essencialmente",
484 + "esturricar",
485 + "esvoacar",
486 + "etario",
487 + "eterno",
488 + "etiquetar",
489 + "etnologo",
490 + "etos",
491 + "etrusco",
492 + "euclidiano",
493 + "euforico",
494 + "eugenico",
495 + "eunuco",
496 + "europio",
497 + "eustaquio",
498 + "eutanasia",
499 + "evasivo",
500 + "eventualidade",
501 + "evitavel",
502 + "evoluir",
503 + "exaustor",
504 + "excursionista",
505 + "exercito",
506 + "exfoliado",
507 + "exito",
508 + "exotico",
509 + "expurgo",
510 + "exsudar",
511 + "extrusora",
512 + "exumar",
513 + "fabuloso",
514 + "facultativo",
515 + "fado",
516 + "fagulha",
517 + "faixas",
518 + "fajuto",
519 + "faltoso",
520 + "famoso",
521 + "fanzine",
522 + "fapesp",
523 + "faquir",
524 + "fartura",
525 + "fastio",
526 + "faturista",
527 + "fausto",
528 + "favorito",
529 + "faxineira",
530 + "fazer",
531 + "fealdade",
532 + "febril",
533 + "fecundo",
534 + "fedorento",
535 + "feerico",
536 + "feixe",
537 + "felicidade",
538 + "felpudo",
539 + "feltro",
540 + "femur",
541 + "fenotipo",
542 + "fervura",
543 + "festivo",
544 + "feto",
545 + "feudo",
546 + "fevereiro",
547 + "fezinha",
548 + "fiasco",
549 + "fibra",
550 + "ficticio",
551 + "fiduciario",
552 + "fiesp",
553 + "fifa",
554 + "figurino",
555 + "fijiano",
556 + "filtro",
557 + "finura",
558 + "fiorde",
559 + "fiquei",
560 + "firula",
561 + "fissurar",
562 + "fitoteca",
563 + "fivela",
564 + "fixo",
565 + "flavio",
566 + "flexor",
567 + "flibusteiro",
568 + "flotilha",
569 + "fluxograma",
570 + "fobos",
571 + "foco",
572 + "fofura",
573 + "foguista",
574 + "foie",
575 + "foliculo",
576 + "fominha",
577 + "fonte",
578 + "forum",
579 + "fosso",
580 + "fotossintese",
581 + "foxtrote",
582 + "fraudulento",
583 + "frevo",
584 + "frivolo",
585 + "frouxo",
586 + "frutose",
587 + "fuba",
588 + "fucsia",
589 + "fugitivo",
590 + "fuinha",
591 + "fujao",
592 + "fulustreco",
593 + "fumo",
594 + "funileiro",
595 + "furunculo",
596 + "fustigar",
597 + "futurologo",
598 + "fuxico",
599 + "fuzue",
600 + "gabriel",
601 + "gado",
602 + "gaelico",
603 + "gafieira",
604 + "gaguejo",
605 + "gaivota",
606 + "gajo",
607 + "galvanoplastico",
608 + "gamo",
609 + "ganso",
610 + "garrucha",
611 + "gastronomo",
612 + "gatuno",
613 + "gaussiano",
614 + "gaviao",
615 + "gaxeta",
616 + "gazeteiro",
617 + "gear",
618 + "geiser",
619 + "geminiano",
620 + "generoso",
621 + "genuino",
622 + "geossinclinal",
623 + "gerundio",
624 + "gestual",
625 + "getulista",
626 + "gibi",
627 + "gigolo",
628 + "gilete",
629 + "ginseng",
630 + "giroscopio",
631 + "glaucio",
632 + "glacial",
633 + "gleba",
634 + "glifo",
635 + "glote",
636 + "glutonia",
637 + "gnostico",
638 + "goela",
639 + "gogo",
640 + "goitaca",
641 + "golpista",
642 + "gomo",
643 + "gonzo",
644 + "gorro",
645 + "gostou",
646 + "goticula",
647 + "gourmet",
648 + "governo",
649 + "gozo",
650 + "graxo",
651 + "grevista",
652 + "grito",
653 + "grotesco",
654 + "gruta",
655 + "guaxinim",
656 + "gude",
657 + "gueto",
658 + "guizo",
659 + "guloso",
660 + "gume",
661 + "guru",
662 + "gustativo",
663 + "grelhado",
664 + "gutural",
665 + "habitue",
666 + "haitiano",
667 + "halterofilista",
668 + "hamburguer",
669 + "hanseniase",
670 + "happening",
671 + "harpista",
672 + "hastear",
673 + "haveres",
674 + "hebreu",
675 + "hectometro",
676 + "hedonista",
677 + "hegira",
678 + "helena",
679 + "helminto",
680 + "hemorroidas",
681 + "henrique",
682 + "heptassilabo",
683 + "hertziano",
684 + "hesitar",
685 + "heterossexual",
686 + "heuristico",
687 + "hexagono",
688 + "hiato",
689 + "hibrido",
690 + "hidrostatico",
691 + "hieroglifo",
692 + "hifenizar",
693 + "higienizar",
694 + "hilario",
695 + "himen",
696 + "hino",
697 + "hippie",
698 + "hirsuto",
699 + "historiografia",
700 + "hitlerista",
701 + "hodometro",
702 + "hoje",
703 + "holograma",
704 + "homus",
705 + "honroso",
706 + "hoquei",
707 + "horto",
708 + "hostilizar",
709 + "hotentote",
710 + "huguenote",
711 + "humilde",
712 + "huno",
713 + "hurra",
714 + "hutu",
715 + "iaia",
716 + "ialorixa",
717 + "iambico",
718 + "iansa",
719 + "iaque",
720 + "iara",
721 + "iatista",
722 + "iberico",
723 + "ibis",
724 + "icar",
725 + "iceberg",
726 + "icosagono",
727 + "idade",
728 + "ideologo",
729 + "idiotice",
730 + "idoso",
731 + "iemenita",
732 + "iene",
733 + "igarape",
734 + "iglu",
735 + "ignorar",
736 + "igreja",
737 + "iguaria",
738 + "iidiche",
739 + "ilativo",
740 + "iletrado",
741 + "ilharga",
742 + "ilimitado",
743 + "ilogismo",
744 + "ilustrissimo",
745 + "imaturo",
746 + "imbuzeiro",
747 + "imerso",
748 + "imitavel",
749 + "imovel",
750 + "imputar",
751 + "imutavel",
752 + "inaveriguavel",
753 + "incutir",
754 + "induzir",
755 + "inextricavel",
756 + "infusao",
757 + "ingua",
758 + "inhame",
759 + "iniquo",
760 + "injusto",
761 + "inning",
762 + "inoxidavel",
763 + "inquisitorial",
764 + "insustentavel",
765 + "intumescimento",
766 + "inutilizavel",
767 + "invulneravel",
768 + "inzoneiro",
769 + "iodo",
770 + "iogurte",
771 + "ioio",
772 + "ionosfera",
773 + "ioruba",
774 + "iota",
775 + "ipsilon",
776 + "irascivel",
777 + "iris",
778 + "irlandes",
779 + "irmaos",
780 + "iroques",
781 + "irrupcao",
782 + "isca",
783 + "isento",
784 + "islandes",
785 + "isotopo",
786 + "isqueiro",
787 + "israelita",
788 + "isso",
789 + "isto",
790 + "iterbio",
791 + "itinerario",
792 + "itrio",
793 + "iuane",
794 + "iugoslavo",
795 + "jabuticabeira",
796 + "jacutinga",
797 + "jade",
798 + "jagunco",
799 + "jainista",
800 + "jaleco",
801 + "jambo",
802 + "jantarada",
803 + "japones",
804 + "jaqueta",
805 + "jarro",
806 + "jasmim",
807 + "jato",
808 + "jaula",
809 + "javel",
810 + "jazz",
811 + "jegue",
812 + "jeitoso",
813 + "jejum",
814 + "jenipapo",
815 + "jeova",
816 + "jequitiba",
817 + "jersei",
818 + "jesus",
819 + "jetom",
820 + "jiboia",
821 + "jihad",
822 + "jilo",
823 + "jingle",
824 + "jipe",
825 + "jocoso",
826 + "joelho",
827 + "joguete",
828 + "joio",
829 + "jojoba",
830 + "jorro",
831 + "jota",
832 + "joule",
833 + "joviano",
834 + "jubiloso",
835 + "judoca",
836 + "jugular",
837 + "juizo",
838 + "jujuba",
839 + "juliano",
840 + "jumento",
841 + "junto",
842 + "jururu",
843 + "justo",
844 + "juta",
845 + "juventude",
846 + "labutar",
847 + "laguna",
848 + "laico",
849 + "lajota",
850 + "lanterninha",
851 + "lapso",
852 + "laquear",
853 + "lastro",
854 + "lauto",
855 + "lavrar",
856 + "laxativo",
857 + "lazer",
858 + "leasing",
859 + "lebre",
860 + "lecionar",
861 + "ledo",
862 + "leguminoso",
863 + "leitura",
864 + "lele",
865 + "lemure",
866 + "lento",
867 + "leonardo",
868 + "leopardo",
869 + "lepton",
870 + "leque",
871 + "leste",
872 + "letreiro",
873 + "leucocito",
874 + "levitico",
875 + "lexicologo",
876 + "lhama",
877 + "lhufas",
878 + "liame",
879 + "licoroso",
880 + "lidocaina",
881 + "liliputiano",
882 + "limusine",
883 + "linotipo",
884 + "lipoproteina",
885 + "liquidos",
886 + "lirismo",
887 + "lisura",
888 + "liturgico",
889 + "livros",
890 + "lixo",
891 + "lobulo",
892 + "locutor",
893 + "lodo",
894 + "logro",
895 + "lojista",
896 + "lombriga",
897 + "lontra",
898 + "loop",
899 + "loquaz",
900 + "lorota",
901 + "losango",
902 + "lotus",
903 + "louvor",
904 + "luar",
905 + "lubrificavel",
906 + "lucros",
907 + "lugubre",
908 + "luis",
909 + "luminoso",
910 + "luneta",
911 + "lustroso",
912 + "luto",
913 + "luvas",
914 + "luxuriante",
915 + "luzeiro",
916 + "maduro",
917 + "maestro",
918 + "mafioso",
919 + "magro",
920 + "maiuscula",
921 + "majoritario",
922 + "malvisto",
923 + "mamute",
924 + "manutencao",
925 + "mapoteca",
926 + "maquinista",
927 + "marzipa",
928 + "masturbar",
929 + "matuto",
930 + "mausoleu",
931 + "mavioso",
932 + "maxixe",
933 + "mazurca",
934 + "meandro",
935 + "mecha",
936 + "medusa",
937 + "mefistofelico",
938 + "megera",
939 + "meirinho",
940 + "melro",
941 + "memorizar",
942 + "menu",
943 + "mequetrefe",
944 + "mertiolate",
945 + "mestria",
946 + "metroviario",
947 + "mexilhao",
948 + "mezanino",
949 + "miau",
950 + "microssegundo",
951 + "midia",
952 + "migratorio",
953 + "mimosa",
954 + "minuto",
955 + "miosotis",
956 + "mirtilo",
957 + "misturar",
958 + "mitzvah",
959 + "miudos",
960 + "mixuruca",
961 + "mnemonico",
962 + "moagem",
963 + "mobilizar",
964 + "modulo",
965 + "moer",
966 + "mofo",
967 + "mogno",
968 + "moita",
969 + "molusco",
970 + "monumento",
971 + "moqueca",
972 + "morubixaba",
973 + "mostruario",
974 + "motriz",
975 + "mouse",
976 + "movivel",
977 + "mozarela",
978 + "muarra",
979 + "muculmano",
980 + "mudo",
981 + "mugir",
982 + "muitos",
983 + "mumunha",
984 + "munir",
985 + "muon",
986 + "muquira",
987 + "murros",
988 + "musselina",
989 + "nacoes",
990 + "nado",
991 + "naftalina",
992 + "nago",
993 + "naipe",
994 + "naja",
995 + "nalgum",
996 + "namoro",
997 + "nanquim",
998 + "napolitano",
999 + "naquilo",
1000 + "nascimento",
1001 + "nautilo",
1002 + "navios",
1003 + "nazista",
1004 + "nebuloso",
1005 + "nectarina",
1006 + "nefrologo",
1007 + "negus",
1008 + "nelore",
1009 + "nenufar",
1010 + "nepotismo",
1011 + "nervura",
1012 + "neste",
1013 + "netuno",
1014 + "neutron",
1015 + "nevoeiro",
1016 + "newtoniano",
1017 + "nexo",
1018 + "nhenhenhem",
1019 + "nhoque",
1020 + "nigeriano",
1021 + "niilista",
1022 + "ninho",
1023 + "niobio",
1024 + "niponico",
1025 + "niquelar",
1026 + "nirvana",
1027 + "nisto",
1028 + "nitroglicerina",
1029 + "nivoso",
1030 + "nobreza",
1031 + "nocivo",
1032 + "noel",
1033 + "nogueira",
1034 + "noivo",
1035 + "nojo",
1036 + "nominativo",
1037 + "nonuplo",
1038 + "noruegues",
1039 + "nostalgico",
1040 + "noturno",
1041 + "nouveau",
1042 + "nuanca",
1043 + "nublar",
1044 + "nucleotideo",
1045 + "nudista",
1046 + "nulo",
1047 + "numismatico",
1048 + "nunquinha",
1049 + "nupcias",
1050 + "nutritivo",
1051 + "nuvens",
1052 + "oasis",
1053 + "obcecar",
1054 + "obeso",
1055 + "obituario",
1056 + "objetos",
1057 + "oblongo",
1058 + "obnoxio",
1059 + "obrigatorio",
1060 + "obstruir",
1061 + "obtuso",
1062 + "obus",
1063 + "obvio",
1064 + "ocaso",
1065 + "occipital",
1066 + "oceanografo",
1067 + "ocioso",
1068 + "oclusivo",
1069 + "ocorrer",
1070 + "ocre",
1071 + "octogono",
1072 + "odalisca",
1073 + "odisseia",
1074 + "odorifico",
1075 + "oersted",
1076 + "oeste",
1077 + "ofertar",
1078 + "ofidio",
1079 + "oftalmologo",
1080 + "ogiva",
1081 + "ogum",
1082 + "oigale",
1083 + "oitavo",
1084 + "oitocentos",
1085 + "ojeriza",
1086 + "olaria",
1087 + "oleoso",
1088 + "olfato",
1089 + "olhos",
1090 + "oliveira",
1091 + "olmo",
1092 + "olor",
1093 + "olvidavel",
1094 + "ombudsman",
1095 + "omeleteira",
1096 + "omitir",
1097 + "omoplata",
1098 + "onanismo",
1099 + "ondular",
1100 + "oneroso",
1101 + "onomatopeico",
1102 + "ontologico",
1103 + "onus",
1104 + "onze",
1105 + "opalescente",
1106 + "opcional",
1107 + "operistico",
1108 + "opio",
1109 + "oposto",
1110 + "oprobrio",
1111 + "optometrista",
1112 + "opusculo",
1113 + "oratorio",
1114 + "orbital",
1115 + "orcar",
1116 + "orfao",
1117 + "orixa",
1118 + "orla",
1119 + "ornitologo",
1120 + "orquidea",
1121 + "ortorrombico",
1122 + "orvalho",
1123 + "osculo",
1124 + "osmotico",
1125 + "ossudo",
1126 + "ostrogodo",
1127 + "otario",
1128 + "otite",
1129 + "ouro",
1130 + "ousar",
1131 + "outubro",
1132 + "ouvir",
1133 + "ovario",
1134 + "overnight",
1135 + "oviparo",
1136 + "ovni",
1137 + "ovoviviparo",
1138 + "ovulo",
1139 + "oxala",
1140 + "oxente",
1141 + "oxiuro",
1142 + "oxossi",
1143 + "ozonizar",
1144 + "paciente",
1145 + "pactuar",
1146 + "padronizar",
1147 + "paete",
1148 + "pagodeiro",
1149 + "paixao",
1150 + "pajem",
1151 + "paludismo",
1152 + "pampas",
1153 + "panturrilha",
1154 + "papudo",
1155 + "paquistanes",
1156 + "pastoso",
1157 + "patua",
1158 + "paulo",
1159 + "pauzinhos",
1160 + "pavoroso",
1161 + "paxa",
1162 + "pazes",
1163 + "peao",
1164 + "pecuniario",
1165 + "pedunculo",
1166 + "pegaso",
1167 + "peixinho",
1168 + "pejorativo",
1169 + "pelvis",
1170 + "penuria",
1171 + "pequno",
1172 + "petunia",
1173 + "pezada",
1174 + "piauiense",
1175 + "pictorico",
1176 + "pierro",
1177 + "pigmeu",
1178 + "pijama",
1179 + "pilulas",
1180 + "pimpolho",
1181 + "pintura",
1182 + "piorar",
1183 + "pipocar",
1184 + "piqueteiro",
1185 + "pirulito",
1186 + "pistoleiro",
1187 + "pituitaria",
1188 + "pivotar",
1189 + "pixote",
1190 + "pizzaria",
1191 + "plistoceno",
1192 + "plotar",
1193 + "pluviometrico",
1194 + "pneumonico",
1195 + "poco",
1196 + "podridao",
1197 + "poetisa",
1198 + "pogrom",
1199 + "pois",
1200 + "polvorosa",
1201 + "pomposo",
1202 + "ponderado",
1203 + "pontudo",
1204 + "populoso",
1205 + "poquer",
1206 + "porvir",
1207 + "posudo",
1208 + "potro",
1209 + "pouso",
1210 + "povoar",
1211 + "prazo",
1212 + "prezar",
1213 + "privilegios",
1214 + "proximo",
1215 + "prussiano",
1216 + "pseudopode",
1217 + "psoriase",
1218 + "pterossauros",
1219 + "ptialina",
1220 + "ptolemaico",
1221 + "pudor",
1222 + "pueril",
1223 + "pufe",
1224 + "pugilista",
1225 + "puir",
1226 + "pujante",
1227 + "pulverizar",
1228 + "pumba",
1229 + "punk",
1230 + "purulento",
1231 + "pustula",
1232 + "putsch",
1233 + "puxe",
1234 + "quatrocentos",
1235 + "quetzal",
1236 + "quixotesco",
1237 + "quotizavel",
1238 + "rabujice",
1239 + "racista",
1240 + "radonio",
1241 + "rafia",
1242 + "ragu",
1243 + "rajado",
1244 + "ralo",
1245 + "rampeiro",
1246 + "ranzinza",
1247 + "raptor",
1248 + "raquitismo",
1249 + "raro",
1250 + "rasurar",
1251 + "ratoeira",
1252 + "ravioli",
1253 + "razoavel",
1254 + "reavivar",
1255 + "rebuscar",
1256 + "recusavel",
1257 + "reduzivel",
1258 + "reexposicao",
1259 + "refutavel",
1260 + "regurgitar",
1261 + "reivindicavel",
1262 + "rejuvenescimento",
1263 + "relva",
1264 + "remuneravel",
1265 + "renunciar",
1266 + "reorientar",
1267 + "repuxo",
1268 + "requisito",
1269 + "resumo",
1270 + "returno",
1271 + "reutilizar",
1272 + "revolvido",
1273 + "rezonear",
1274 + "riacho",
1275 + "ribossomo",
1276 + "ricota",
1277 + "ridiculo",
1278 + "rifle",
1279 + "rigoroso",
1280 + "rijo",
1281 + "rimel",
1282 + "rins",
1283 + "rios",
1284 + "riqueza",
1285 + "respeito",
1286 + "rissole",
1287 + "ritualistico",
1288 + "rivalizar",
1289 + "rixa",
1290 + "robusto",
1291 + "rococo",
1292 + "rodoviario",
1293 + "roer",
1294 + "rogo",
1295 + "rojao",
1296 + "rolo",
1297 + "rompimento",
1298 + "ronronar",
1299 + "roqueiro",
1300 + "rorqual",
1301 + "rosto",
1302 + "rotundo",
1303 + "rouxinol",
1304 + "roxo",
1305 + "royal",
1306 + "ruas",
1307 + "rucula",
1308 + "rudimentos",
1309 + "ruela",
1310 + "rufo",
1311 + "rugoso",
1312 + "ruivo",
1313 + "rule",
1314 + "rumoroso",
1315 + "runico",
1316 + "ruptura",
1317 + "rural",
1318 + "rustico",
1319 + "rutilar",
1320 + "saariano",
1321 + "sabujo",
1322 + "sacudir",
1323 + "sadomasoquista",
1324 + "safra",
1325 + "sagui",
1326 + "sais",
1327 + "samurai",
1328 + "santuario",
1329 + "sapo",
1330 + "saquear",
1331 + "sartriano",
1332 + "saturno",
1333 + "saude",
1334 + "sauva",
1335 + "saveiro",
1336 + "saxofonista",
1337 + "sazonal",
1338 + "scherzo",
1339 + "script",
1340 + "seara",
1341 + "seborreia",
1342 + "secura",
1343 + "seduzir",
1344 + "sefardim",
1345 + "seguro",
1346 + "seja",
1347 + "selvas",
1348 + "sempre",
1349 + "senzala",
1350 + "sepultura",
1351 + "sequoia",
1352 + "sestercio",
1353 + "setuplo",
1354 + "seus",
1355 + "seviciar",
1356 + "sezonismo",
1357 + "shalom",
1358 + "siames",
1359 + "sibilante",
1360 + "sicrano",
1361 + "sidra",
1362 + "sifilitico",
1363 + "signos",
1364 + "silvo",
1365 + "simultaneo",
1366 + "sinusite",
1367 + "sionista",
1368 + "sirio",
1369 + "sisudo",
1370 + "situar",
1371 + "sivan",
1372 + "slide",
1373 + "slogan",
1374 + "soar",
1375 + "sobrio",
1376 + "socratico",
1377 + "sodomizar",
1378 + "soerguer",
1379 + "software",
1380 + "sogro",
1381 + "soja",
1382 + "solver",
1383 + "somente",
1384 + "sonso",
1385 + "sopro",
1386 + "soquete",
1387 + "sorveteiro",
1388 + "sossego",
1389 + "soturno",
1390 + "sousafone",
1391 + "sovinice",
1392 + "sozinho",
1393 + "suavizar",
1394 + "subverter",
1395 + "sucursal",
1396 + "sudoriparo",
1397 + "sufragio",
1398 + "sugestoes",
1399 + "suite",
1400 + "sujo",
1401 + "sultao",
1402 + "sumula",
1403 + "suntuoso",
1404 + "suor",
1405 + "supurar",
1406 + "suruba",
1407 + "susto",
1408 + "suturar",
1409 + "suvenir",
1410 + "tabuleta",
1411 + "taco",
1412 + "tadjique",
1413 + "tafeta",
1414 + "tagarelice",
1415 + "taitiano",
1416 + "talvez",
1417 + "tampouco",
1418 + "tanzaniano",
1419 + "taoista",
1420 + "tapume",
1421 + "taquion",
1422 + "tarugo",
1423 + "tascar",
1424 + "tatuar",
1425 + "tautologico",
1426 + "tavola",
1427 + "taxionomista",
1428 + "tchecoslovaco",
1429 + "teatrologo",
1430 + "tectonismo",
1431 + "tedioso",
1432 + "teflon",
1433 + "tegumento",
1434 + "teixo",
1435 + "telurio",
1436 + "temporas",
1437 + "tenue",
1438 + "teosofico",
1439 + "tepido",
1440 + "tequila",
1441 + "terrorista",
1442 + "testosterona",
1443 + "tetrico",
1444 + "teutonico",
1445 + "teve",
1446 + "texugo",
1447 + "tiara",
1448 + "tibia",
1449 + "tiete",
1450 + "tifoide",
1451 + "tigresa",
1452 + "tijolo",
1453 + "tilintar",
1454 + "timpano",
1455 + "tintureiro",
1456 + "tiquete",
1457 + "tiroteio",
1458 + "tisico",
1459 + "titulos",
1460 + "tive",
1461 + "toar",
1462 + "toboga",
1463 + "tofu",
1464 + "togoles",
1465 + "toicinho",
1466 + "tolueno",
1467 + "tomografo",
1468 + "tontura",
1469 + "toponimo",
1470 + "toquio",
1471 + "torvelinho",
1472 + "tostar",
1473 + "toto",
1474 + "touro",
1475 + "toxina",
1476 + "trazer",
1477 + "trezentos",
1478 + "trivialidade",
1479 + "trovoar",
1480 + "truta",
1481 + "tuaregue",
1482 + "tubular",
1483 + "tucano",
1484 + "tudo",
1485 + "tufo",
1486 + "tuiste",
1487 + "tulipa",
1488 + "tumultuoso",
1489 + "tunisino",
1490 + "tupiniquim",
1491 + "turvo",
1492 + "tutu",
1493 + "ucraniano",
1494 + "udenista",
1495 + "ufanista",
1496 + "ufologo",
1497 + "ugaritico",
1498 + "uiste",
1499 + "uivo",
1500 + "ulceroso",
1501 + "ulema",
1502 + "ultravioleta",
1503 + "umbilical",
1504 + "umero",
1505 + "umido",
1506 + "umlaut",
1507 + "unanimidade",
1508 + "unesco",
1509 + "ungulado",
1510 + "unheiro",
1511 + "univoco",
1512 + "untuoso",
1513 + "urano",
1514 + "urbano",
1515 + "urdir",
1516 + "uretra",
1517 + "urgente",
1518 + "urinol",
1519 + "urna",
1520 + "urologo",
1521 + "urro",
1522 + "ursulina",
1523 + "urtiga",
1524 + "urupe",
1525 + "usavel",
1526 + "usbeque",
1527 + "usei",
1528 + "usineiro",
1529 + "usurpar",
1530 + "utero",
1531 + "utilizar",
1532 + "utopico",
1533 + "uvular",
1534 + "uxoricidio",
1535 + "vacuo",
1536 + "vadio",
1537 + "vaguear",
1538 + "vaivem",
1539 + "valvula",
1540 + "vampiro",
1541 + "vantajoso",
1542 + "vaporoso",
1543 + "vaquinha",
1544 + "varziano",
1545 + "vasto",
1546 + "vaticinio",
1547 + "vaudeville",
1548 + "vazio",
1549 + "veado",
1550 + "vedico",
1551 + "veemente",
1552 + "vegetativo",
1553 + "veio",
1554 + "veja",
1555 + "veludo",
1556 + "venusiano",
1557 + "verdade",
1558 + "verve",
1559 + "vestuario",
1560 + "vetusto",
1561 + "vexatorio",
1562 + "vezes",
1563 + "viavel",
1564 + "vibratorio",
1565 + "victor",
1566 + "vicunha",
1567 + "vidros",
1568 + "vietnamita",
1569 + "vigoroso",
1570 + "vilipendiar",
1571 + "vime",
1572 + "vintem",
1573 + "violoncelo",
1574 + "viquingue",
1575 + "virus",
1576 + "visualizar",
1577 + "vituperio",
1578 + "viuvo",
1579 + "vivo",
1580 + "vizir",
1581 + "voar",
1582 + "vociferar",
1583 + "vodu",
1584 + "vogar",
1585 + "voile",
1586 + "volver",
1587 + "vomito",
1588 + "vontade",
1589 + "vortice",
1590 + "vosso",
1591 + "voto",
1592 + "vovozinha",
1593 + "voyeuse",
1594 + "vozes",
1595 + "vulva",
1596 + "vupt",
1597 + "western",
1598 + "xadrez",
1599 + "xale",
1600 + "xampu",
1601 + "xango",
1602 + "xarope",
1603 + "xaual",
1604 + "xavante",
1605 + "xaxim",
1606 + "xenonio",
1607 + "xepa",
1608 + "xerox",
1609 + "xicara",
1610 + "xifopago",
1611 + "xiita",
1612 + "xilogravura",
1613 + "xinxim",
1614 + "xistoso",
1615 + "xixi",
1616 + "xodo",
1617 + "xogum",
1618 + "xucro",
1619 + "zabumba",
1620 + "zagueiro",
1621 + "zambiano",
1622 + "zanzar",
1623 + "zarpar",
1624 + "zebu",
1625 + "zefiro",
1626 + "zeloso",
1627 + "zenite",
1628 + "zumbi"
1629 + ];
1630 +}
\ No newline at end of file
cw_monero/lib/mnemonics/russian.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class RussianMnemonics {
2 + static const words = [
3 + "абажур",
4 + "абзац",
5 + "абонент",
6 + "абрикос",
7 + "абсурд",
8 + "авангард",
9 + "август",
10 + "авиация",
11 + "авоська",
12 + "автор",
13 + "агат",
14 + "агент",
15 + "агитатор",
16 + "агнец",
17 + "агония",
18 + "агрегат",
19 + "адвокат",
20 + "адмирал",
21 + "адрес",
22 + "ажиотаж",
23 + "азарт",
24 + "азбука",
25 + "азот",
26 + "аист",
27 + "айсберг",
28 + "академия",
29 + "аквариум",
30 + "аккорд",
31 + "акробат",
32 + "аксиома",
33 + "актер",
34 + "акула",
35 + "акция",
36 + "алгоритм",
37 + "алебарда",
38 + "аллея",
39 + "алмаз",
40 + "алтарь",
41 + "алфавит",
42 + "алхимик",
43 + "алый",
44 + "альбом",
45 + "алюминий",
46 + "амбар",
47 + "аметист",
48 + "амнезия",
49 + "ампула",
50 + "амфора",
51 + "анализ",
52 + "ангел",
53 + "анекдот",
54 + "анимация",
55 + "анкета",
56 + "аномалия",
57 + "ансамбль",
58 + "антенна",
59 + "апатия",
60 + "апельсин",
61 + "апофеоз",
62 + "аппарат",
63 + "апрель",
64 + "аптека",
65 + "арабский",
66 + "арбуз",
67 + "аргумент",
68 + "арест",
69 + "ария",
70 + "арка",
71 + "армия",
72 + "аромат",
73 + "арсенал",
74 + "артист",
75 + "архив",
76 + "аршин",
77 + "асбест",
78 + "аскетизм",
79 + "аспект",
80 + "ассорти",
81 + "астроном",
82 + "асфальт",
83 + "атака",
84 + "ателье",
85 + "атлас",
86 + "атом",
87 + "атрибут",
88 + "аудитор",
89 + "аукцион",
90 + "аура",
91 + "афера",
92 + "афиша",
93 + "ахинея",
94 + "ацетон",
95 + "аэропорт",
96 + "бабушка",
97 + "багаж",
98 + "бадья",
99 + "база",
100 + "баклажан",
101 + "балкон",
102 + "бампер",
103 + "банк",
104 + "барон",
105 + "бассейн",
106 + "батарея",
107 + "бахрома",
108 + "башня",
109 + "баян",
110 + "бегство",
111 + "бедро",
112 + "бездна",
113 + "бекон",
114 + "белый",
115 + "бензин",
116 + "берег",
117 + "беседа",
118 + "бетонный",
119 + "биатлон",
120 + "библия",
121 + "бивень",
122 + "бигуди",
123 + "бидон",
124 + "бизнес",
125 + "бикини",
126 + "билет",
127 + "бинокль",
128 + "биология",
129 + "биржа",
130 + "бисер",
131 + "битва",
132 + "бицепс",
133 + "благо",
134 + "бледный",
135 + "близкий",
136 + "блок",
137 + "блуждать",
138 + "блюдо",
139 + "бляха",
140 + "бобер",
141 + "богатый",
142 + "бодрый",
143 + "боевой",
144 + "бокал",
145 + "большой",
146 + "борьба",
147 + "босой",
148 + "ботинок",
149 + "боцман",
150 + "бочка",
151 + "боярин",
152 + "брать",
153 + "бревно",
154 + "бригада",
155 + "бросать",
156 + "брызги",
157 + "брюки",
158 + "бублик",
159 + "бугор",
160 + "будущее",
161 + "буква",
162 + "бульвар",
163 + "бумага",
164 + "бунт",
165 + "бурный",
166 + "бусы",
167 + "бутылка",
168 + "буфет",
169 + "бухта",
170 + "бушлат",
171 + "бывалый",
172 + "быль",
173 + "быстрый",
174 + "быть",
175 + "бюджет",
176 + "бюро",
177 + "бюст",
178 + "вагон",
179 + "важный",
180 + "ваза",
181 + "вакцина",
182 + "валюта",
183 + "вампир",
184 + "ванная",
185 + "вариант",
186 + "вассал",
187 + "вата",
188 + "вафля",
189 + "вахта",
190 + "вдова",
191 + "вдыхать",
192 + "ведущий",
193 + "веер",
194 + "вежливый",
195 + "везти",
196 + "веко",
197 + "великий",
198 + "вена",
199 + "верить",
200 + "веселый",
201 + "ветер",
202 + "вечер",
203 + "вешать",
204 + "вещь",
205 + "веяние",
206 + "взаимный",
207 + "взбучка",
208 + "взвод",
209 + "взгляд",
210 + "вздыхать",
211 + "взлетать",
212 + "взмах",
213 + "взнос",
214 + "взор",
215 + "взрыв",
216 + "взывать",
217 + "взятка",
218 + "вибрация",
219 + "визит",
220 + "вилка",
221 + "вино",
222 + "вирус",
223 + "висеть",
224 + "витрина",
225 + "вихрь",
226 + "вишневый",
227 + "включать",
228 + "вкус",
229 + "власть",
230 + "влечь",
231 + "влияние",
232 + "влюблять",
233 + "внешний",
234 + "внимание",
235 + "внук",
236 + "внятный",
237 + "вода",
238 + "воевать",
239 + "вождь",
240 + "воздух",
241 + "войти",
242 + "вокзал",
243 + "волос",
244 + "вопрос",
245 + "ворота",
246 + "восток",
247 + "впадать",
248 + "впускать",
249 + "врач",
250 + "время",
251 + "вручать",
252 + "всадник",
253 + "всеобщий",
254 + "вспышка",
255 + "встреча",
256 + "вторник",
257 + "вулкан",
258 + "вурдалак",
259 + "входить",
260 + "въезд",
261 + "выбор",
262 + "вывод",
263 + "выгодный",
264 + "выделять",
265 + "выезжать",
266 + "выживать",
267 + "вызывать",
268 + "выигрыш",
269 + "вылезать",
270 + "выносить",
271 + "выпивать",
272 + "высокий",
273 + "выходить",
274 + "вычет",
275 + "вышка",
276 + "выяснять",
277 + "вязать",
278 + "вялый",
279 + "гавань",
280 + "гадать",
281 + "газета",
282 + "гаишник",
283 + "галстук",
284 + "гамма",
285 + "гарантия",
286 + "гастроли",
287 + "гвардия",
288 + "гвоздь",
289 + "гектар",
290 + "гель",
291 + "генерал",
292 + "геолог",
293 + "герой",
294 + "гешефт",
295 + "гибель",
296 + "гигант",
297 + "гильза",
298 + "гимн",
299 + "гипотеза",
300 + "гитара",
301 + "глаз",
302 + "глина",
303 + "глоток",
304 + "глубокий",
305 + "глыба",
306 + "глядеть",
307 + "гнать",
308 + "гнев",
309 + "гнить",
310 + "гном",
311 + "гнуть",
312 + "говорить",
313 + "годовой",
314 + "голова",
315 + "гонка",
316 + "город",
317 + "гость",
318 + "готовый",
319 + "граница",
320 + "грех",
321 + "гриб",
322 + "громкий",
323 + "группа",
324 + "грызть",
325 + "грязный",
326 + "губа",
327 + "гудеть",
328 + "гулять",
329 + "гуманный",
330 + "густой",
331 + "гуща",
332 + "давать",
333 + "далекий",
334 + "дама",
335 + "данные",
336 + "дарить",
337 + "дать",
338 + "дача",
339 + "дверь",
340 + "движение",
341 + "двор",
342 + "дебют",
343 + "девушка",
344 + "дедушка",
345 + "дежурный",
346 + "дезертир",
347 + "действие",
348 + "декабрь",
349 + "дело",
350 + "демократ",
351 + "день",
352 + "депутат",
353 + "держать",
354 + "десяток",
355 + "детский",
356 + "дефицит",
357 + "дешевый",
358 + "деятель",
359 + "джаз",
360 + "джинсы",
361 + "джунгли",
362 + "диалог",
363 + "диван",
364 + "диета",
365 + "дизайн",
366 + "дикий",
367 + "динамика",
368 + "диплом",
369 + "директор",
370 + "диск",
371 + "дитя",
372 + "дичь",
373 + "длинный",
374 + "дневник",
375 + "добрый",
376 + "доверие",
377 + "договор",
378 + "дождь",
379 + "доза",
380 + "документ",
381 + "должен",
382 + "домашний",
383 + "допрос",
384 + "дорога",
385 + "доход",
386 + "доцент",
387 + "дочь",
388 + "дощатый",
389 + "драка",
390 + "древний",
391 + "дрожать",
392 + "друг",
393 + "дрянь",
394 + "дубовый",
395 + "дуга",
396 + "дудка",
397 + "дукат",
398 + "дуло",
399 + "думать",
400 + "дупло",
401 + "дурак",
402 + "дуть",
403 + "духи",
404 + "душа",
405 + "дуэт",
406 + "дымить",
407 + "дыня",
408 + "дыра",
409 + "дыханье",
410 + "дышать",
411 + "дьявол",
412 + "дюжина",
413 + "дюйм",
414 + "дюна",
415 + "дядя",
416 + "дятел",
417 + "егерь",
418 + "единый",
419 + "едкий",
420 + "ежевика",
421 + "ежик",
422 + "езда",
423 + "елка",
424 + "емкость",
425 + "ерунда",
426 + "ехать",
427 + "жадный",
428 + "жажда",
429 + "жалеть",
430 + "жанр",
431 + "жара",
432 + "жать",
433 + "жгучий",
434 + "ждать",
435 + "жевать",
436 + "желание",
437 + "жемчуг",
438 + "женщина",
439 + "жертва",
440 + "жесткий",
441 + "жечь",
442 + "живой",
443 + "жидкость",
444 + "жизнь",
445 + "жилье",
446 + "жирный",
447 + "житель",
448 + "журнал",
449 + "жюри",
450 + "забывать",
451 + "завод",
452 + "загадка",
453 + "задача",
454 + "зажечь",
455 + "зайти",
456 + "закон",
457 + "замечать",
458 + "занимать",
459 + "западный",
460 + "зарплата",
461 + "засыпать",
462 + "затрата",
463 + "захват",
464 + "зацепка",
465 + "зачет",
466 + "защита",
467 + "заявка",
468 + "звать",
469 + "звезда",
470 + "звонить",
471 + "звук",
472 + "здание",
473 + "здешний",
474 + "здоровье",
475 + "зебра",
476 + "зевать",
477 + "зеленый",
478 + "земля",
479 + "зенит",
480 + "зеркало",
481 + "зефир",
482 + "зигзаг",
483 + "зима",
484 + "зиять",
485 + "злак",
486 + "злой",
487 + "змея",
488 + "знать",
489 + "зной",
490 + "зодчий",
491 + "золотой",
492 + "зомби",
493 + "зона",
494 + "зоопарк",
495 + "зоркий",
496 + "зрачок",
497 + "зрение",
498 + "зритель",
499 + "зубной",
500 + "зыбкий",
501 + "зять",
502 + "игла",
503 + "иголка",
504 + "играть",
505 + "идея",
506 + "идиот",
507 + "идол",
508 + "идти",
509 + "иерархия",
510 + "избрать",
511 + "известие",
512 + "изгонять",
513 + "издание",
514 + "излагать",
515 + "изменять",
516 + "износ",
517 + "изоляция",
518 + "изрядный",
519 + "изучать",
520 + "изымать",
521 + "изящный",
522 + "икона",
523 + "икра",
524 + "иллюзия",
525 + "имбирь",
526 + "иметь",
527 + "имидж",
528 + "иммунный",
529 + "империя",
530 + "инвестор",
531 + "индивид",
532 + "инерция",
533 + "инженер",
534 + "иномарка",
535 + "институт",
536 + "интерес",
537 + "инфекция",
538 + "инцидент",
539 + "ипподром",
540 + "ирис",
541 + "ирония",
542 + "искать",
543 + "история",
544 + "исходить",
545 + "исчезать",
546 + "итог",
547 + "июль",
548 + "июнь",
549 + "кабинет",
550 + "кавалер",
551 + "кадр",
552 + "казарма",
553 + "кайф",
554 + "кактус",
555 + "калитка",
556 + "камень",
557 + "канал",
558 + "капитан",
559 + "картина",
560 + "касса",
561 + "катер",
562 + "кафе",
563 + "качество",
564 + "каша",
565 + "каюта",
566 + "квартира",
567 + "квинтет",
568 + "квота",
569 + "кедр",
570 + "кекс",
571 + "кенгуру",
572 + "кепка",
573 + "керосин",
574 + "кетчуп",
575 + "кефир",
576 + "кибитка",
577 + "кивнуть",
578 + "кидать",
579 + "километр",
580 + "кино",
581 + "киоск",
582 + "кипеть",
583 + "кирпич",
584 + "кисть",
585 + "китаец",
586 + "класс",
587 + "клетка",
588 + "клиент",
589 + "клоун",
590 + "клуб",
591 + "клык",
592 + "ключ",
593 + "клятва",
594 + "книга",
595 + "кнопка",
596 + "кнут",
597 + "князь",
598 + "кобура",
599 + "ковер",
600 + "коготь",
601 + "кодекс",
602 + "кожа",
603 + "козел",
604 + "койка",
605 + "коктейль",
606 + "колено",
607 + "компания",
608 + "конец",
609 + "копейка",
610 + "короткий",
611 + "костюм",
612 + "котел",
613 + "кофе",
614 + "кошка",
615 + "красный",
616 + "кресло",
617 + "кричать",
618 + "кровь",
619 + "крупный",
620 + "крыша",
621 + "крючок",
622 + "кубок",
623 + "кувшин",
624 + "кудрявый",
625 + "кузов",
626 + "кукла",
627 + "культура",
628 + "кумир",
629 + "купить",
630 + "курс",
631 + "кусок",
632 + "кухня",
633 + "куча",
634 + "кушать",
635 + "кювет",
636 + "лабиринт",
637 + "лавка",
638 + "лагерь",
639 + "ладонь",
640 + "лазерный",
641 + "лайнер",
642 + "лакей",
643 + "лампа",
644 + "ландшафт",
645 + "лапа",
646 + "ларек",
647 + "ласковый",
648 + "лауреат",
649 + "лачуга",
650 + "лаять",
651 + "лгать",
652 + "лебедь",
653 + "левый",
654 + "легкий",
655 + "ледяной",
656 + "лежать",
657 + "лекция",
658 + "лента",
659 + "лепесток",
660 + "лесной",
661 + "лето",
662 + "лечь",
663 + "леший",
664 + "лживый",
665 + "либерал",
666 + "ливень",
667 + "лига",
668 + "лидер",
669 + "ликовать",
670 + "лиловый",
671 + "лимон",
672 + "линия",
673 + "липа",
674 + "лирика",
675 + "лист",
676 + "литр",
677 + "лифт",
678 + "лихой",
679 + "лицо",
680 + "личный",
681 + "лишний",
682 + "лобовой",
683 + "ловить",
684 + "логика",
685 + "лодка",
686 + "ложка",
687 + "лозунг",
688 + "локоть",
689 + "ломать",
690 + "лоно",
691 + "лопата",
692 + "лорд",
693 + "лось",
694 + "лоток",
695 + "лохматый",
696 + "лошадь",
697 + "лужа",
698 + "лукавый",
699 + "луна",
700 + "лупить",
701 + "лучший",
702 + "лыжный",
703 + "лысый",
704 + "львиный",
705 + "льгота",
706 + "льдина",
707 + "любить",
708 + "людской",
709 + "люстра",
710 + "лютый",
711 + "лягушка",
712 + "магазин",
713 + "мадам",
714 + "мазать",
715 + "майор",
716 + "максимум",
717 + "мальчик",
718 + "манера",
719 + "март",
720 + "масса",
721 + "мать",
722 + "мафия",
723 + "махать",
724 + "мачта",
725 + "машина",
726 + "маэстро",
727 + "маяк",
728 + "мгла",
729 + "мебель",
730 + "медведь",
731 + "мелкий",
732 + "мемуары",
733 + "менять",
734 + "мера",
735 + "место",
736 + "метод",
737 + "механизм",
738 + "мечтать",
739 + "мешать",
740 + "миграция",
741 + "мизинец",
742 + "микрофон",
743 + "миллион",
744 + "минута",
745 + "мировой",
746 + "миссия",
747 + "митинг",
748 + "мишень",
749 + "младший",
750 + "мнение",
751 + "мнимый",
752 + "могила",
753 + "модель",
754 + "мозг",
755 + "мойка",
756 + "мокрый",
757 + "молодой",
758 + "момент",
759 + "монах",
760 + "море",
761 + "мост",
762 + "мотор",
763 + "мохнатый",
764 + "мочь",
765 + "мошенник",
766 + "мощный",
767 + "мрачный",
768 + "мстить",
769 + "мудрый",
770 + "мужчина",
771 + "музыка",
772 + "мука",
773 + "мумия",
774 + "мундир",
775 + "муравей",
776 + "мусор",
777 + "мутный",
778 + "муфта",
779 + "муха",
780 + "мучить",
781 + "мушкетер",
782 + "мыло",
783 + "мысль",
784 + "мыть",
785 + "мычать",
786 + "мышь",
787 + "мэтр",
788 + "мюзикл",
789 + "мягкий",
790 + "мякиш",
791 + "мясо",
792 + "мятый",
793 + "мячик",
794 + "набор",
795 + "навык",
796 + "нагрузка",
797 + "надежда",
798 + "наемный",
799 + "нажать",
800 + "называть",
801 + "наивный",
802 + "накрыть",
803 + "налог",
804 + "намерен",
805 + "наносить",
806 + "написать",
807 + "народ",
808 + "натура",
809 + "наука",
810 + "нация",
811 + "начать",
812 + "небо",
813 + "невеста",
814 + "негодяй",
815 + "неделя",
816 + "нежный",
817 + "незнание",
818 + "нелепый",
819 + "немалый",
820 + "неправда",
821 + "нервный",
822 + "нести",
823 + "нефть",
824 + "нехватка",
825 + "нечистый",
826 + "неясный",
827 + "нива",
828 + "нижний",
829 + "низкий",
830 + "никель",
831 + "нирвана",
832 + "нить",
833 + "ничья",
834 + "ниша",
835 + "нищий",
836 + "новый",
837 + "нога",
838 + "ножницы",
839 + "ноздря",
840 + "ноль",
841 + "номер",
842 + "норма",
843 + "нота",
844 + "ночь",
845 + "ноша",
846 + "ноябрь",
847 + "нрав",
848 + "нужный",
849 + "нутро",
850 + "нынешний",
851 + "нырнуть",
852 + "ныть",
853 + "нюанс",
854 + "нюхать",
855 + "няня",
856 + "оазис",
857 + "обаяние",
858 + "обвинять",
859 + "обгонять",
860 + "обещать",
861 + "обжигать",
862 + "обзор",
863 + "обида",
864 + "область",
865 + "обмен",
866 + "обнимать",
867 + "оборона",
868 + "образ",
869 + "обучение",
870 + "обходить",
871 + "обширный",
872 + "общий",
873 + "объект",
874 + "обычный",
875 + "обязать",
876 + "овальный",
877 + "овес",
878 + "овощи",
879 + "овраг",
880 + "овца",
881 + "овчарка",
882 + "огненный",
883 + "огонь",
884 + "огромный",
885 + "огурец",
886 + "одежда",
887 + "одинокий",
888 + "одобрить",
889 + "ожидать",
890 + "ожог",
891 + "озарение",
892 + "озеро",
893 + "означать",
894 + "оказать",
895 + "океан",
896 + "оклад",
897 + "окно",
898 + "округ",
899 + "октябрь",
900 + "окурок",
901 + "олень",
902 + "опасный",
903 + "операция",
904 + "описать",
905 + "оплата",
906 + "опора",
907 + "оппонент",
908 + "опрос",
909 + "оптимизм",
910 + "опускать",
911 + "опыт",
912 + "орать",
913 + "орбита",
914 + "орган",
915 + "орден",
916 + "орел",
917 + "оригинал",
918 + "оркестр",
919 + "орнамент",
920 + "оружие",
921 + "осадок",
922 + "освещать",
923 + "осень",
924 + "осина",
925 + "осколок",
926 + "осмотр",
927 + "основной",
928 + "особый",
929 + "осуждать",
930 + "отбор",
931 + "отвечать",
932 + "отдать",
933 + "отец",
934 + "отзыв",
935 + "открытие",
936 + "отмечать",
937 + "относить",
938 + "отпуск",
939 + "отрасль",
940 + "отставка",
941 + "оттенок",
942 + "отходить",
943 + "отчет",
944 + "отъезд",
945 + "офицер",
946 + "охапка",
947 + "охота",
948 + "охрана",
949 + "оценка",
950 + "очаг",
951 + "очередь",
952 + "очищать",
953 + "очки",
954 + "ошейник",
955 + "ошибка",
956 + "ощущение",
957 + "павильон",
958 + "падать",
959 + "паек",
960 + "пакет",
961 + "палец",
962 + "память",
963 + "панель",
964 + "папка",
965 + "партия",
966 + "паспорт",
967 + "патрон",
968 + "пауза",
969 + "пафос",
970 + "пахнуть",
971 + "пациент",
972 + "пачка",
973 + "пашня",
974 + "певец",
975 + "педагог",
976 + "пейзаж",
977 + "пельмень",
978 + "пенсия",
979 + "пепел",
980 + "период",
981 + "песня",
982 + "петля",
983 + "пехота",
984 + "печать",
985 + "пешеход",
986 + "пещера",
987 + "пианист",
988 + "пиво",
989 + "пиджак",
990 + "пиковый",
991 + "пилот",
992 + "пионер",
993 + "пирог",
994 + "писать",
995 + "пить",
996 + "пицца",
997 + "пишущий",
998 + "пища",
999 + "план",
1000 + "плечо",
1001 + "плита",
1002 + "плохой",
1003 + "плыть",
1004 + "плюс",
1005 + "пляж",
1006 + "победа",
1007 + "повод",
1008 + "погода",
1009 + "подумать",
1010 + "поехать",
1011 + "пожимать",
1012 + "позиция",
1013 + "поиск",
1014 + "покой",
1015 + "получать",
1016 + "помнить",
1017 + "пони",
1018 + "поощрять",
1019 + "попадать",
1020 + "порядок",
1021 + "пост",
1022 + "поток",
1023 + "похожий",
1024 + "поцелуй",
1025 + "почва",
1026 + "пощечина",
1027 + "поэт",
1028 + "пояснить",
1029 + "право",
1030 + "предмет",
1031 + "проблема",
1032 + "пруд",
1033 + "прыгать",
1034 + "прямой",
1035 + "психолог",
1036 + "птица",
1037 + "публика",
1038 + "пугать",
1039 + "пудра",
1040 + "пузырь",
1041 + "пуля",
1042 + "пункт",
1043 + "пурга",
1044 + "пустой",
1045 + "путь",
1046 + "пухлый",
1047 + "пучок",
1048 + "пушистый",
1049 + "пчела",
1050 + "пшеница",
1051 + "пыль",
1052 + "пытка",
1053 + "пыхтеть",
1054 + "пышный",
1055 + "пьеса",
1056 + "пьяный",
1057 + "пятно",
1058 + "работа",
1059 + "равный",
1060 + "радость",
1061 + "развитие",
1062 + "район",
1063 + "ракета",
1064 + "рамка",
1065 + "ранний",
1066 + "рапорт",
1067 + "рассказ",
1068 + "раунд",
1069 + "рация",
1070 + "рвать",
1071 + "реальный",
1072 + "ребенок",
1073 + "реветь",
1074 + "регион",
1075 + "редакция",
1076 + "реестр",
1077 + "режим",
1078 + "резкий",
1079 + "рейтинг",
1080 + "река",
1081 + "религия",
1082 + "ремонт",
1083 + "рента",
1084 + "реплика",
1085 + "ресурс",
1086 + "реформа",
1087 + "рецепт",
1088 + "речь",
1089 + "решение",
1090 + "ржавый",
1091 + "рисунок",
1092 + "ритм",
1093 + "рифма",
1094 + "робкий",
1095 + "ровный",
1096 + "рогатый",
1097 + "родитель",
1098 + "рождение",
1099 + "розовый",
1100 + "роковой",
1101 + "роль",
1102 + "роман",
1103 + "ронять",
1104 + "рост",
1105 + "рота",
1106 + "роща",
1107 + "рояль",
1108 + "рубль",
1109 + "ругать",
1110 + "руда",
1111 + "ружье",
1112 + "руины",
1113 + "рука",
1114 + "руль",
1115 + "румяный",
1116 + "русский",
1117 + "ручка",
1118 + "рыба",
1119 + "рывок",
1120 + "рыдать",
1121 + "рыжий",
1122 + "рынок",
1123 + "рысь",
1124 + "рыть",
1125 + "рыхлый",
1126 + "рыцарь",
1127 + "рычаг",
1128 + "рюкзак",
1129 + "рюмка",
1130 + "рябой",
1131 + "рядовой",
1132 + "сабля",
1133 + "садовый",
1134 + "сажать",
1135 + "салон",
1136 + "самолет",
1137 + "сани",
1138 + "сапог",
1139 + "сарай",
1140 + "сатира",
1141 + "сауна",
1142 + "сахар",
1143 + "сбегать",
1144 + "сбивать",
1145 + "сбор",
1146 + "сбыт",
1147 + "свадьба",
1148 + "свет",
1149 + "свидание",
1150 + "свобода",
1151 + "связь",
1152 + "сгорать",
1153 + "сдвигать",
1154 + "сеанс",
1155 + "северный",
1156 + "сегмент",
1157 + "седой",
1158 + "сезон",
1159 + "сейф",
1160 + "секунда",
1161 + "сельский",
1162 + "семья",
1163 + "сентябрь",
1164 + "сердце",
1165 + "сеть",
1166 + "сечение",
1167 + "сеять",
1168 + "сигнал",
1169 + "сидеть",
1170 + "сизый",
1171 + "сила",
1172 + "символ",
1173 + "синий",
1174 + "сирота",
1175 + "система",
1176 + "ситуация",
1177 + "сиять",
1178 + "сказать",
1179 + "скважина",
1180 + "скелет",
1181 + "скидка",
1182 + "склад",
1183 + "скорый",
1184 + "скрывать",
1185 + "скучный",
1186 + "слава",
1187 + "слеза",
1188 + "слияние",
1189 + "слово",
1190 + "случай",
1191 + "слышать",
1192 + "слюна",
1193 + "смех",
1194 + "смирение",
1195 + "смотреть",
1196 + "смутный",
1197 + "смысл",
1198 + "смятение",
1199 + "снаряд",
1200 + "снег",
1201 + "снижение",
1202 + "сносить",
1203 + "снять",
1204 + "событие",
1205 + "совет",
1206 + "согласие",
1207 + "сожалеть",
1208 + "сойти",
1209 + "сокол",
1210 + "солнце",
1211 + "сомнение",
1212 + "сонный",
1213 + "сообщать",
1214 + "соперник",
1215 + "сорт",
1216 + "состав",
1217 + "сотня",
1218 + "соус",
1219 + "социолог",
1220 + "сочинять",
1221 + "союз",
1222 + "спать",
1223 + "спешить",
1224 + "спина",
1225 + "сплошной",
1226 + "способ",
1227 + "спутник",
1228 + "средство",
1229 + "срок",
1230 + "срывать",
1231 + "стать",
1232 + "ствол",
1233 + "стена",
1234 + "стихи",
1235 + "сторона",
1236 + "страна",
1237 + "студент",
1238 + "стыд",
1239 + "субъект",
1240 + "сувенир",
1241 + "сугроб",
1242 + "судьба",
1243 + "суета",
1244 + "суждение",
1245 + "сукно",
1246 + "сулить",
1247 + "сумма",
1248 + "сунуть",
1249 + "супруг",
1250 + "суровый",
1251 + "сустав",
1252 + "суть",
1253 + "сухой",
1254 + "суша",
1255 + "существо",
1256 + "сфера",
1257 + "схема",
1258 + "сцена",
1259 + "счастье",
1260 + "счет",
1261 + "считать",
1262 + "сшивать",
1263 + "съезд",
1264 + "сынок",
1265 + "сыпать",
1266 + "сырье",
1267 + "сытый",
1268 + "сыщик",
1269 + "сюжет",
1270 + "сюрприз",
1271 + "таблица",
1272 + "таежный",
1273 + "таинство",
1274 + "тайна",
1275 + "такси",
1276 + "талант",
1277 + "таможня",
1278 + "танец",
1279 + "тарелка",
1280 + "таскать",
1281 + "тахта",
1282 + "тачка",
1283 + "таять",
1284 + "тварь",
1285 + "твердый",
1286 + "творить",
1287 + "театр",
1288 + "тезис",
1289 + "текст",
1290 + "тело",
1291 + "тема",
1292 + "тень",
1293 + "теория",
1294 + "теплый",
1295 + "терять",
1296 + "тесный",
1297 + "тетя",
1298 + "техника",
1299 + "течение",
1300 + "тигр",
1301 + "типичный",
1302 + "тираж",
1303 + "титул",
1304 + "тихий",
1305 + "тишина",
1306 + "ткань",
1307 + "товарищ",
1308 + "толпа",
1309 + "тонкий",
1310 + "топливо",
1311 + "торговля",
1312 + "тоска",
1313 + "точка",
1314 + "тощий",
1315 + "традиция",
1316 + "тревога",
1317 + "трибуна",
1318 + "трогать",
1319 + "труд",
1320 + "трюк",
1321 + "тряпка",
1322 + "туалет",
1323 + "тугой",
1324 + "туловище",
1325 + "туман",
1326 + "тундра",
1327 + "тупой",
1328 + "турнир",
1329 + "тусклый",
1330 + "туфля",
1331 + "туча",
1332 + "туша",
1333 + "тыкать",
1334 + "тысяча",
1335 + "тьма",
1336 + "тюльпан",
1337 + "тюрьма",
1338 + "тяга",
1339 + "тяжелый",
1340 + "тянуть",
1341 + "убеждать",
1342 + "убирать",
1343 + "убогий",
1344 + "убыток",
1345 + "уважение",
1346 + "уверять",
1347 + "увлекать",
1348 + "угнать",
1349 + "угол",
1350 + "угроза",
1351 + "удар",
1352 + "удивлять",
1353 + "удобный",
1354 + "уезд",
1355 + "ужас",
1356 + "ужин",
1357 + "узел",
1358 + "узкий",
1359 + "узнавать",
1360 + "узор",
1361 + "уйма",
1362 + "уклон",
1363 + "укол",
1364 + "уксус",
1365 + "улетать",
1366 + "улица",
1367 + "улучшать",
1368 + "улыбка",
1369 + "уметь",
1370 + "умиление",
1371 + "умный",
1372 + "умолять",
1373 + "умысел",
1374 + "унижать",
1375 + "уносить",
1376 + "уныние",
1377 + "упасть",
1378 + "уплата",
1379 + "упор",
1380 + "упрекать",
1381 + "упускать",
1382 + "уран",
1383 + "урна",
1384 + "уровень",
1385 + "усадьба",
1386 + "усердие",
1387 + "усилие",
1388 + "ускорять",
1389 + "условие",
1390 + "усмешка",
1391 + "уснуть",
1392 + "успеть",
1393 + "усыпать",
1394 + "утешать",
1395 + "утка",
1396 + "уточнять",
1397 + "утро",
1398 + "утюг",
1399 + "уходить",
1400 + "уцелеть",
1401 + "участие",
1402 + "ученый",
1403 + "учитель",
1404 + "ушко",
1405 + "ущерб",
1406 + "уютный",
1407 + "уяснять",
1408 + "фабрика",
1409 + "фаворит",
1410 + "фаза",
1411 + "файл",
1412 + "факт",
1413 + "фамилия",
1414 + "фантазия",
1415 + "фара",
1416 + "фасад",
1417 + "февраль",
1418 + "фельдшер",
1419 + "феномен",
1420 + "ферма",
1421 + "фигура",
1422 + "физика",
1423 + "фильм",
1424 + "финал",
1425 + "фирма",
1426 + "фишка",
1427 + "флаг",
1428 + "флейта",
1429 + "флот",
1430 + "фокус",
1431 + "фольклор",
1432 + "фонд",
1433 + "форма",
1434 + "фото",
1435 + "фраза",
1436 + "фреска",
1437 + "фронт",
1438 + "фрукт",
1439 + "функция",
1440 + "фуражка",
1441 + "футбол",
1442 + "фыркать",
1443 + "халат",
1444 + "хамство",
1445 + "хаос",
1446 + "характер",
1447 + "хата",
1448 + "хватать",
1449 + "хвост",
1450 + "хижина",
1451 + "хилый",
1452 + "химия",
1453 + "хирург",
1454 + "хитрый",
1455 + "хищник",
1456 + "хлам",
1457 + "хлеб",
1458 + "хлопать",
1459 + "хмурый",
1460 + "ходить",
1461 + "хозяин",
1462 + "хоккей",
1463 + "холодный",
1464 + "хороший",
1465 + "хотеть",
1466 + "хохотать",
1467 + "храм",
1468 + "хрен",
1469 + "хриплый",
1470 + "хроника",
1471 + "хрупкий",
1472 + "художник",
1473 + "хулиган",
1474 + "хутор",
1475 + "царь",
1476 + "цвет",
1477 + "цель",
1478 + "цемент",
1479 + "центр",
1480 + "цепь",
1481 + "церковь",
1482 + "цикл",
1483 + "цилиндр",
1484 + "циничный",
1485 + "цирк",
1486 + "цистерна",
1487 + "цитата",
1488 + "цифра",
1489 + "цыпленок",
1490 + "чадо",
1491 + "чайник",
1492 + "часть",
1493 + "чашка",
1494 + "человек",
1495 + "чемодан",
1496 + "чепуха",
1497 + "черный",
1498 + "честь",
1499 + "четкий",
1500 + "чехол",
1501 + "чиновник",
1502 + "число",
1503 + "читать",
1504 + "членство",
1505 + "чреватый",
1506 + "чтение",
1507 + "чувство",
1508 + "чугунный",
1509 + "чудо",
1510 + "чужой",
1511 + "чукча",
1512 + "чулок",
1513 + "чума",
1514 + "чуткий",
1515 + "чучело",
1516 + "чушь",
1517 + "шаблон",
1518 + "шагать",
1519 + "шайка",
1520 + "шакал",
1521 + "шалаш",
1522 + "шампунь",
1523 + "шанс",
1524 + "шапка",
1525 + "шарик",
1526 + "шасси",
1527 + "шатер",
1528 + "шахта",
1529 + "шашлык",
1530 + "швейный",
1531 + "швырять",
1532 + "шевелить",
1533 + "шедевр",
1534 + "шейка",
1535 + "шелковый",
1536 + "шептать",
1537 + "шерсть",
1538 + "шестерка",
1539 + "шикарный",
1540 + "шинель",
1541 + "шипеть",
1542 + "широкий",
1543 + "шить",
1544 + "шишка",
1545 + "шкаф",
1546 + "школа",
1547 + "шкура",
1548 + "шланг",
1549 + "шлем",
1550 + "шлюпка",
1551 + "шляпа",
1552 + "шнур",
1553 + "шоколад",
1554 + "шорох",
1555 + "шоссе",
1556 + "шофер",
1557 + "шпага",
1558 + "шпион",
1559 + "шприц",
1560 + "шрам",
1561 + "шрифт",
1562 + "штаб",
1563 + "штора",
1564 + "штраф",
1565 + "штука",
1566 + "штык",
1567 + "шуба",
1568 + "шуметь",
1569 + "шуршать",
1570 + "шутка",
1571 + "щадить",
1572 + "щедрый",
1573 + "щека",
1574 + "щель",
1575 + "щенок",
1576 + "щепка",
1577 + "щетка",
1578 + "щука",
1579 + "эволюция",
1580 + "эгоизм",
1581 + "экзамен",
1582 + "экипаж",
1583 + "экономия",
1584 + "экран",
1585 + "эксперт",
1586 + "элемент",
1587 + "элита",
1588 + "эмблема",
1589 + "эмигрант",
1590 + "эмоция",
1591 + "энергия",
1592 + "эпизод",
1593 + "эпоха",
1594 + "эскиз",
1595 + "эссе",
1596 + "эстрада",
1597 + "этап",
1598 + "этика",
1599 + "этюд",
1600 + "эфир",
1601 + "эффект",
1602 + "эшелон",
1603 + "юбилей",
1604 + "юбка",
1605 + "южный",
1606 + "юмор",
1607 + "юноша",
1608 + "юрист",
1609 + "яблоко",
1610 + "явление",
1611 + "ягода",
1612 + "ядерный",
1613 + "ядовитый",
1614 + "ядро",
1615 + "язва",
1616 + "язык",
1617 + "яйцо",
1618 + "якорь",
1619 + "январь",
1620 + "японец",
1621 + "яркий",
1622 + "ярмарка",
1623 + "ярость",
1624 + "ярус",
1625 + "ясный",
1626 + "яхта",
1627 + "ячейка",
1628 + "ящик"
1629 + ];
1630 +}
\ No newline at end of file
cw_monero/lib/mnemonics/spanish.dart new
+1630
@@ -0,0 +1,1630 @@
1 +class SpanishMnemonics {
2 + static const words = [
3 + "ábaco",
4 + "abdomen",
5 + "abeja",
6 + "abierto",
7 + "abogado",
8 + "abono",
9 + "aborto",
10 + "abrazo",
11 + "abrir",
12 + "abuelo",
13 + "abuso",
14 + "acabar",
15 + "academia",
16 + "acceso",
17 + "acción",
18 + "aceite",
19 + "acelga",
20 + "acento",
21 + "aceptar",
22 + "ácido",
23 + "aclarar",
24 + "acné",
25 + "acoger",
26 + "acoso",
27 + "activo",
28 + "acto",
29 + "actriz",
30 + "actuar",
31 + "acudir",
32 + "acuerdo",
33 + "acusar",
34 + "adicto",
35 + "admitir",
36 + "adoptar",
37 + "adorno",
38 + "aduana",
39 + "adulto",
40 + "aéreo",
41 + "afectar",
42 + "afición",
43 + "afinar",
44 + "afirmar",
45 + "ágil",
46 + "agitar",
47 + "agonía",
48 + "agosto",
49 + "agotar",
50 + "agregar",
51 + "agrio",
52 + "agua",
53 + "agudo",
54 + "águila",
55 + "aguja",
56 + "ahogo",
57 + "ahorro",
58 + "aire",
59 + "aislar",
60 + "ajedrez",
61 + "ajeno",
62 + "ajuste",
63 + "alacrán",
64 + "alambre",
65 + "alarma",
66 + "alba",
67 + "álbum",
68 + "alcalde",
69 + "aldea",
70 + "alegre",
71 + "alejar",
72 + "alerta",
73 + "aleta",
74 + "alfiler",
75 + "alga",
76 + "algodón",
77 + "aliado",
78 + "aliento",
79 + "alivio",
80 + "alma",
81 + "almeja",
82 + "almíbar",
83 + "altar",
84 + "alteza",
85 + "altivo",
86 + "alto",
87 + "altura",
88 + "alumno",
89 + "alzar",
90 + "amable",
91 + "amante",
92 + "amapola",
93 + "amargo",
94 + "amasar",
95 + "ámbar",
96 + "ámbito",
97 + "ameno",
98 + "amigo",
99 + "amistad",
100 + "amor",
101 + "amparo",
102 + "amplio",
103 + "ancho",
104 + "anciano",
105 + "ancla",
106 + "andar",
107 + "andén",
108 + "anemia",
109 + "ángulo",
110 + "anillo",
111 + "ánimo",
112 + "anís",
113 + "anotar",
114 + "antena",
115 + "antiguo",
116 + "antojo",
117 + "anual",
118 + "anular",
119 + "anuncio",
120 + "añadir",
121 + "añejo",
122 + "año",
123 + "apagar",
124 + "aparato",
125 + "apetito",
126 + "apio",
127 + "aplicar",
128 + "apodo",
129 + "aporte",
130 + "apoyo",
131 + "aprender",
132 + "aprobar",
133 + "apuesta",
134 + "apuro",
135 + "arado",
136 + "araña",
137 + "arar",
138 + "árbitro",
139 + "árbol",
140 + "arbusto",
141 + "archivo",
142 + "arco",
143 + "arder",
144 + "ardilla",
145 + "arduo",
146 + "área",
147 + "árido",
148 + "aries",
149 + "armonía",
150 + "arnés",
151 + "aroma",
152 + "arpa",
153 + "arpón",
154 + "arreglo",
155 + "arroz",
156 + "arruga",
157 + "arte",
158 + "artista",
159 + "asa",
160 + "asado",
161 + "asalto",
162 + "ascenso",
163 + "asegurar",
164 + "aseo",
165 + "asesor",
166 + "asiento",
167 + "asilo",
168 + "asistir",
169 + "asno",
170 + "asombro",
171 + "áspero",
172 + "astilla",
173 + "astro",
174 + "astuto",
175 + "asumir",
176 + "asunto",
177 + "atajo",
178 + "ataque",
179 + "atar",
180 + "atento",
181 + "ateo",
182 + "ático",
183 + "atleta",
184 + "átomo",
185 + "atraer",
186 + "atroz",
187 + "atún",
188 + "audaz",
189 + "audio",
190 + "auge",
191 + "aula",
192 + "aumento",
193 + "ausente",
194 + "autor",
195 + "aval",
196 + "avance",
197 + "avaro",
198 + "ave",
199 + "avellana",
200 + "avena",
201 + "avestruz",
202 + "avión",
203 + "aviso",
204 + "ayer",
205 + "ayuda",
206 + "ayuno",
207 + "azafrán",
208 + "azar",
209 + "azote",
210 + "azúcar",
211 + "azufre",
212 + "azul",
213 + "baba",
214 + "babor",
215 + "bache",
216 + "bahía",
217 + "baile",
218 + "bajar",
219 + "balanza",
220 + "balcón",
221 + "balde",
222 + "bambú",
223 + "banco",
224 + "banda",
225 + "baño",
226 + "barba",
227 + "barco",
228 + "barniz",
229 + "barro",
230 + "báscula",
231 + "bastón",
232 + "basura",
233 + "batalla",
234 + "batería",
235 + "batir",
236 + "batuta",
237 + "baúl",
238 + "bazar",
239 + "bebé",
240 + "bebida",
241 + "bello",
242 + "besar",
243 + "beso",
244 + "bestia",
245 + "bicho",
246 + "bien",
247 + "bingo",
248 + "blanco",
249 + "bloque",
250 + "blusa",
251 + "boa",
252 + "bobina",
253 + "bobo",
254 + "boca",
255 + "bocina",
256 + "boda",
257 + "bodega",
258 + "boina",
259 + "bola",
260 + "bolero",
261 + "bolsa",
262 + "bomba",
263 + "bondad",
264 + "bonito",
265 + "bono",
266 + "bonsái",
267 + "borde",
268 + "borrar",
269 + "bosque",
270 + "bote",
271 + "botín",
272 + "bóveda",
273 + "bozal",
274 + "bravo",
275 + "brazo",
276 + "brecha",
277 + "breve",
278 + "brillo",
279 + "brinco",
280 + "brisa",
281 + "broca",
282 + "broma",
283 + "bronce",
284 + "brote",
285 + "bruja",
286 + "brusco",
287 + "bruto",
288 + "buceo",
289 + "bucle",
290 + "bueno",
291 + "buey",
292 + "bufanda",
293 + "bufón",
294 + "búho",
295 + "buitre",
296 + "bulto",
297 + "burbuja",
298 + "burla",
299 + "burro",
300 + "buscar",
301 + "butaca",
302 + "buzón",
303 + "caballo",
304 + "cabeza",
305 + "cabina",
306 + "cabra",
307 + "cacao",
308 + "cadáver",
309 + "cadena",
310 + "caer",
311 + "café",
312 + "caída",
313 + "caimán",
314 + "caja",
315 + "cajón",
316 + "cal",
317 + "calamar",
318 + "calcio",
319 + "caldo",
320 + "calidad",
321 + "calle",
322 + "calma",
323 + "calor",
324 + "calvo",
325 + "cama",
326 + "cambio",
327 + "camello",
328 + "camino",
329 + "campo",
330 + "cáncer",
331 + "candil",
332 + "canela",
333 + "canguro",
334 + "canica",
335 + "canto",
336 + "caña",
337 + "cañón",
338 + "caoba",
339 + "caos",
340 + "capaz",
341 + "capitán",
342 + "capote",
343 + "captar",
344 + "capucha",
345 + "cara",
346 + "carbón",
347 + "cárcel",
348 + "careta",
349 + "carga",
350 + "cariño",
351 + "carne",
352 + "carpeta",
353 + "carro",
354 + "carta",
355 + "casa",
356 + "casco",
357 + "casero",
358 + "caspa",
359 + "castor",
360 + "catorce",
361 + "catre",
362 + "caudal",
363 + "causa",
364 + "cazo",
365 + "cebolla",
366 + "ceder",
367 + "cedro",
368 + "celda",
369 + "célebre",
370 + "celoso",
371 + "célula",
372 + "cemento",
373 + "ceniza",
374 + "centro",
375 + "cerca",
376 + "cerdo",
377 + "cereza",
378 + "cero",
379 + "cerrar",
380 + "certeza",
381 + "césped",
382 + "cetro",
383 + "chacal",
384 + "chaleco",
385 + "champú",
386 + "chancla",
387 + "chapa",
388 + "charla",
389 + "chico",
390 + "chiste",
391 + "chivo",
392 + "choque",
393 + "choza",
394 + "chuleta",
395 + "chupar",
396 + "ciclón",
397 + "ciego",
398 + "cielo",
399 + "cien",
400 + "cierto",
401 + "cifra",
402 + "cigarro",
403 + "cima",
404 + "cinco",
405 + "cine",
406 + "cinta",
407 + "ciprés",
408 + "circo",
409 + "ciruela",
410 + "cisne",
411 + "cita",
412 + "ciudad",
413 + "clamor",
414 + "clan",
415 + "claro",
416 + "clase",
417 + "clave",
418 + "cliente",
419 + "clima",
420 + "clínica",
421 + "cobre",
422 + "cocción",
423 + "cochino",
424 + "cocina",
425 + "coco",
426 + "código",
427 + "codo",
428 + "cofre",
429 + "coger",
430 + "cohete",
431 + "cojín",
432 + "cojo",
433 + "cola",
434 + "colcha",
435 + "colegio",
436 + "colgar",
437 + "colina",
438 + "collar",
439 + "colmo",
440 + "columna",
441 + "combate",
442 + "comer",
443 + "comida",
444 + "cómodo",
445 + "compra",
446 + "conde",
447 + "conejo",
448 + "conga",
449 + "conocer",
450 + "consejo",
451 + "contar",
452 + "copa",
453 + "copia",
454 + "corazón",
455 + "corbata",
456 + "corcho",
457 + "cordón",
458 + "corona",
459 + "correr",
460 + "coser",
461 + "cosmos",
462 + "costa",
463 + "cráneo",
464 + "cráter",
465 + "crear",
466 + "crecer",
467 + "creído",
468 + "crema",
469 + "cría",
470 + "crimen",
471 + "cripta",
472 + "crisis",
473 + "cromo",
474 + "crónica",
475 + "croqueta",
476 + "crudo",
477 + "cruz",
478 + "cuadro",
479 + "cuarto",
480 + "cuatro",
481 + "cubo",
482 + "cubrir",
483 + "cuchara",
484 + "cuello",
485 + "cuento",
486 + "cuerda",
487 + "cuesta",
488 + "cueva",
489 + "cuidar",
490 + "culebra",
491 + "culpa",
492 + "culto",
493 + "cumbre",
494 + "cumplir",
495 + "cuna",
496 + "cuneta",
497 + "cuota",
498 + "cupón",
499 + "cúpula",
500 + "curar",
501 + "curioso",
502 + "curso",
503 + "curva",
504 + "cutis",
505 + "dama",
506 + "danza",
507 + "dar",
508 + "dardo",
509 + "dátil",
510 + "deber",
511 + "débil",
512 + "década",
513 + "decir",
514 + "dedo",
515 + "defensa",
516 + "definir",
517 + "dejar",
518 + "delfín",
519 + "delgado",
520 + "delito",
521 + "demora",
522 + "denso",
523 + "dental",
524 + "deporte",
525 + "derecho",
526 + "derrota",
527 + "desayuno",
528 + "deseo",
529 + "desfile",
530 + "desnudo",
531 + "destino",
532 + "desvío",
533 + "detalle",
534 + "detener",
535 + "deuda",
536 + "día",
537 + "diablo",
538 + "diadema",
539 + "diamante",
540 + "diana",
541 + "diario",
542 + "dibujo",
543 + "dictar",
544 + "diente",
545 + "dieta",
546 + "diez",
547 + "difícil",
548 + "digno",
549 + "dilema",
550 + "diluir",
551 + "dinero",
552 + "directo",
553 + "dirigir",
554 + "disco",
555 + "diseño",
556 + "disfraz",
557 + "diva",
558 + "divino",
559 + "doble",
560 + "doce",
561 + "dolor",
562 + "domingo",
563 + "don",
564 + "donar",
565 + "dorado",
566 + "dormir",
567 + "dorso",
568 + "dos",
569 + "dosis",
570 + "dragón",
571 + "droga",
572 + "ducha",
573 + "duda",
574 + "duelo",
575 + "dueño",
576 + "dulce",
577 + "dúo",
578 + "duque",
579 + "durar",
580 + "dureza",
581 + "duro",
582 + "ébano",
583 + "ebrio",
584 + "echar",
585 + "eco",
586 + "ecuador",
587 + "edad",
588 + "edición",
589 + "edificio",
590 + "editor",
591 + "educar",
592 + "efecto",
593 + "eficaz",
594 + "eje",
595 + "ejemplo",
596 + "elefante",
597 + "elegir",
598 + "elemento",
599 + "elevar",
600 + "elipse",
601 + "élite",
602 + "elixir",
603 + "elogio",
604 + "eludir",
605 + "embudo",
606 + "emitir",
607 + "emoción",
608 + "empate",
609 + "empeño",
610 + "empleo",
611 + "empresa",
612 + "enano",
613 + "encargo",
614 + "enchufe",
615 + "encía",
616 + "enemigo",
617 + "enero",
618 + "enfado",
619 + "enfermo",
620 + "engaño",
621 + "enigma",
622 + "enlace",
623 + "enorme",
624 + "enredo",
625 + "ensayo",
626 + "enseñar",
627 + "entero",
628 + "entrar",
629 + "envase",
630 + "envío",
631 + "época",
632 + "equipo",
633 + "erizo",
634 + "escala",
635 + "escena",
636 + "escolar",
637 + "escribir",
638 + "escudo",
639 + "esencia",
640 + "esfera",
641 + "esfuerzo",
642 + "espada",
643 + "espejo",
644 + "espía",
645 + "esposa",
646 + "espuma",
647 + "esquí",
648 + "estar",
649 + "este",
650 + "estilo",
651 + "estufa",
652 + "etapa",
653 + "eterno",
654 + "ética",
655 + "etnia",
656 + "evadir",
657 + "evaluar",
658 + "evento",
659 + "evitar",
660 + "exacto",
661 + "examen",
662 + "exceso",
663 + "excusa",
664 + "exento",
665 + "exigir",
666 + "exilio",
667 + "existir",
668 + "éxito",
669 + "experto",
670 + "explicar",
671 + "exponer",
672 + "extremo",
673 + "fábrica",
674 + "fábula",
675 + "fachada",
676 + "fácil",
677 + "factor",
678 + "faena",
679 + "faja",
680 + "falda",
681 + "fallo",
682 + "falso",
683 + "faltar",
684 + "fama",
685 + "familia",
686 + "famoso",
687 + "faraón",
688 + "farmacia",
689 + "farol",
690 + "farsa",
691 + "fase",
692 + "fatiga",
693 + "fauna",
694 + "favor",
695 + "fax",
696 + "febrero",
697 + "fecha",
698 + "feliz",
699 + "feo",
700 + "feria",
701 + "feroz",
702 + "fértil",
703 + "fervor",
704 + "festín",
705 + "fiable",
706 + "fianza",
707 + "fiar",
708 + "fibra",
709 + "ficción",
710 + "ficha",
711 + "fideo",
712 + "fiebre",
713 + "fiel",
714 + "fiera",
715 + "fiesta",
716 + "figura",
717 + "fijar",
718 + "fijo",
719 + "fila",
720 + "filete",
721 + "filial",
722 + "filtro",
723 + "fin",
724 + "finca",
725 + "fingir",
726 + "finito",
727 + "firma",
728 + "flaco",
729 + "flauta",
730 + "flecha",
731 + "flor",
732 + "flota",
733 + "fluir",
734 + "flujo",
735 + "flúor",
736 + "fobia",
737 + "foca",
738 + "fogata",
739 + "fogón",
740 + "folio",
741 + "folleto",
742 + "fondo",
743 + "forma",
744 + "forro",
745 + "fortuna",
746 + "forzar",
747 + "fosa",
748 + "foto",
749 + "fracaso",
750 + "frágil",
751 + "franja",
752 + "frase",
753 + "fraude",
754 + "freír",
755 + "freno",
756 + "fresa",
757 + "frío",
758 + "frito",
759 + "fruta",
760 + "fuego",
761 + "fuente",
762 + "fuerza",
763 + "fuga",
764 + "fumar",
765 + "función",
766 + "funda",
767 + "furgón",
768 + "furia",
769 + "fusil",
770 + "fútbol",
771 + "futuro",
772 + "gacela",
773 + "gafas",
774 + "gaita",
775 + "gajo",
776 + "gala",
777 + "galería",
778 + "gallo",
779 + "gamba",
780 + "ganar",
781 + "gancho",
782 + "ganga",
783 + "ganso",
784 + "garaje",
785 + "garza",
786 + "gasolina",
787 + "gastar",
788 + "gato",
789 + "gavilán",
790 + "gemelo",
791 + "gemir",
792 + "gen",
793 + "género",
794 + "genio",
795 + "gente",
796 + "geranio",
797 + "gerente",
798 + "germen",
799 + "gesto",
800 + "gigante",
801 + "gimnasio",
802 + "girar",
803 + "giro",
804 + "glaciar",
805 + "globo",
806 + "gloria",
807 + "gol",
808 + "golfo",
809 + "goloso",
810 + "golpe",
811 + "goma",
812 + "gordo",
813 + "gorila",
814 + "gorra",
815 + "gota",
816 + "goteo",
817 + "gozar",
818 + "grada",
819 + "gráfico",
820 + "grano",
821 + "grasa",
822 + "gratis",
823 + "grave",
824 + "grieta",
825 + "grillo",
826 + "gripe",
827 + "gris",
828 + "grito",
829 + "grosor",
830 + "grúa",
831 + "grueso",
832 + "grumo",
833 + "grupo",
834 + "guante",
835 + "guapo",
836 + "guardia",
837 + "guerra",
838 + "guía",
839 + "guiño",
840 + "guion",
841 + "guiso",
842 + "guitarra",
843 + "gusano",
844 + "gustar",
845 + "haber",
846 + "hábil",
847 + "hablar",
848 + "hacer",
849 + "hacha",
850 + "hada",
851 + "hallar",
852 + "hamaca",
853 + "harina",
854 + "haz",
855 + "hazaña",
856 + "hebilla",
857 + "hebra",
858 + "hecho",
859 + "helado",
860 + "helio",
861 + "hembra",
862 + "herir",
863 + "hermano",
864 + "héroe",
865 + "hervir",
866 + "hielo",
867 + "hierro",
868 + "hígado",
869 + "higiene",
870 + "hijo",
871 + "himno",
872 + "historia",
873 + "hocico",
874 + "hogar",
875 + "hoguera",
876 + "hoja",
877 + "hombre",
878 + "hongo",
879 + "honor",
880 + "honra",
881 + "hora",
882 + "hormiga",
883 + "horno",
884 + "hostil",
885 + "hoyo",
886 + "hueco",
887 + "huelga",
888 + "huerta",
889 + "hueso",
890 + "huevo",
891 + "huida",
892 + "huir",
893 + "humano",
894 + "húmedo",
895 + "humilde",
896 + "humo",
897 + "hundir",
898 + "huracán",
899 + "hurto",
900 + "icono",
901 + "ideal",
902 + "idioma",
903 + "ídolo",
904 + "iglesia",
905 + "iglú",
906 + "igual",
907 + "ilegal",
908 + "ilusión",
909 + "imagen",
910 + "imán",
911 + "imitar",
912 + "impar",
913 + "imperio",
914 + "imponer",
915 + "impulso",
916 + "incapaz",
917 + "índice",
918 + "inerte",
919 + "infiel",
920 + "informe",
921 + "ingenio",
922 + "inicio",
923 + "inmenso",
924 + "inmune",
925 + "innato",
926 + "insecto",
927 + "instante",
928 + "interés",
929 + "íntimo",
930 + "intuir",
931 + "inútil",
932 + "invierno",
933 + "ira",
934 + "iris",
935 + "ironía",
936 + "isla",
937 + "islote",
938 + "jabalí",
939 + "jabón",
940 + "jamón",
941 + "jarabe",
942 + "jardín",
943 + "jarra",
944 + "jaula",
945 + "jazmín",
946 + "jefe",
947 + "jeringa",
948 + "jinete",
949 + "jornada",
950 + "joroba",
951 + "joven",
952 + "joya",
953 + "juerga",
954 + "jueves",
955 + "juez",
956 + "jugador",
957 + "jugo",
958 + "juguete",
959 + "juicio",
960 + "junco",
961 + "jungla",
962 + "junio",
963 + "juntar",
964 + "júpiter",
965 + "jurar",
966 + "justo",
967 + "juvenil",
968 + "juzgar",
969 + "kilo",
970 + "koala",
971 + "labio",
972 + "lacio",
973 + "lacra",
974 + "lado",
975 + "ladrón",
976 + "lagarto",
977 + "lágrima",
978 + "laguna",
979 + "laico",
980 + "lamer",
981 + "lámina",
982 + "lámpara",
983 + "lana",
984 + "lancha",
985 + "langosta",
986 + "lanza",
987 + "lápiz",
988 + "largo",
989 + "larva",
990 + "lástima",
991 + "lata",
992 + "látex",
993 + "latir",
994 + "laurel",
995 + "lavar",
996 + "lazo",
997 + "leal",
998 + "lección",
999 + "leche",
1000 + "lector",
1001 + "leer",
1002 + "legión",
1003 + "legumbre",
1004 + "lejano",
1005 + "lengua",
1006 + "lento",
1007 + "leña",
1008 + "león",
1009 + "leopardo",
1010 + "lesión",
1011 + "letal",
1012 + "letra",
1013 + "leve",
1014 + "leyenda",
1015 + "libertad",
1016 + "libro",
1017 + "licor",
1018 + "líder",
1019 + "lidiar",
1020 + "lienzo",
1021 + "liga",
1022 + "ligero",
1023 + "lima",
1024 + "límite",
1025 + "limón",
1026 + "limpio",
1027 + "lince",
1028 + "lindo",
1029 + "línea",
1030 + "lingote",
1031 + "lino",
1032 + "linterna",
1033 + "líquido",
1034 + "liso",
1035 + "lista",
1036 + "litera",
1037 + "litio",
1038 + "litro",
1039 + "llaga",
1040 + "llama",
1041 + "llanto",
1042 + "llave",
1043 + "llegar",
1044 + "llenar",
1045 + "llevar",
1046 + "llorar",
1047 + "llover",
1048 + "lluvia",
1049 + "lobo",
1050 + "loción",
1051 + "loco",
1052 + "locura",
1053 + "lógica",
1054 + "logro",
1055 + "lombriz",
1056 + "lomo",
1057 + "lonja",
1058 + "lote",
1059 + "lucha",
1060 + "lucir",
1061 + "lugar",
1062 + "lujo",
1063 + "luna",
1064 + "lunes",
1065 + "lupa",
1066 + "lustro",
1067 + "luto",
1068 + "luz",
1069 + "maceta",
1070 + "macho",
1071 + "madera",
1072 + "madre",
1073 + "maduro",
1074 + "maestro",
1075 + "mafia",
1076 + "magia",
1077 + "mago",
1078 + "maíz",
1079 + "maldad",
1080 + "maleta",
1081 + "malla",
1082 + "malo",
1083 + "mamá",
1084 + "mambo",
1085 + "mamut",
1086 + "manco",
1087 + "mando",
1088 + "manejar",
1089 + "manga",
1090 + "maniquí",
1091 + "manjar",
1092 + "mano",
1093 + "manso",
1094 + "manta",
1095 + "mañana",
1096 + "mapa",
1097 + "máquina",
1098 + "mar",
1099 + "marco",
1100 + "marea",
1101 + "marfil",
1102 + "margen",
1103 + "marido",
1104 + "mármol",
1105 + "marrón",
1106 + "martes",
1107 + "marzo",
1108 + "masa",
1109 + "máscara",
1110 + "masivo",
1111 + "matar",
1112 + "materia",
1113 + "matiz",
1114 + "matriz",
1115 + "máximo",
1116 + "mayor",
1117 + "mazorca",
1118 + "mecha",
1119 + "medalla",
1120 + "medio",
1121 + "médula",
1122 + "mejilla",
1123 + "mejor",
1124 + "melena",
1125 + "melón",
1126 + "memoria",
1127 + "menor",
1128 + "mensaje",
1129 + "mente",
1130 + "menú",
1131 + "mercado",
1132 + "merengue",
1133 + "mérito",
1134 + "mes",
1135 + "mesón",
1136 + "meta",
1137 + "meter",
1138 + "método",
1139 + "metro",
1140 + "mezcla",
1141 + "miedo",
1142 + "miel",
1143 + "miembro",
1144 + "miga",
1145 + "mil",
1146 + "milagro",
1147 + "militar",
1148 + "millón",
1149 + "mimo",
1150 + "mina",
1151 + "minero",
1152 + "mínimo",
1153 + "minuto",
1154 + "miope",
1155 + "mirar",
1156 + "misa",
1157 + "miseria",
1158 + "misil",
1159 + "mismo",
1160 + "mitad",
1161 + "mito",
1162 + "mochila",
1163 + "moción",
1164 + "moda",
1165 + "modelo",
1166 + "moho",
1167 + "mojar",
1168 + "molde",
1169 + "moler",
1170 + "molino",
1171 + "momento",
1172 + "momia",
1173 + "monarca",
1174 + "moneda",
1175 + "monja",
1176 + "monto",
1177 + "moño",
1178 + "morada",
1179 + "morder",
1180 + "moreno",
1181 + "morir",
1182 + "morro",
1183 + "morsa",
1184 + "mortal",
1185 + "mosca",
1186 + "mostrar",
1187 + "motivo",
1188 + "mover",
1189 + "móvil",
1190 + "mozo",
1191 + "mucho",
1192 + "mudar",
1193 + "mueble",
1194 + "muela",
1195 + "muerte",
1196 + "muestra",
1197 + "mugre",
1198 + "mujer",
1199 + "mula",
1200 + "muleta",
1201 + "multa",
1202 + "mundo",
1203 + "muñeca",
1204 + "mural",
1205 + "muro",
1206 + "músculo",
1207 + "museo",
1208 + "musgo",
1209 + "música",
1210 + "muslo",
1211 + "nácar",
1212 + "nación",
1213 + "nadar",
1214 + "naipe",
1215 + "naranja",
1216 + "nariz",
1217 + "narrar",
1218 + "nasal",
1219 + "natal",
1220 + "nativo",
1221 + "natural",
1222 + "náusea",
1223 + "naval",
1224 + "nave",
1225 + "navidad",
1226 + "necio",
1227 + "néctar",
1228 + "negar",
1229 + "negocio",
1230 + "negro",
1231 + "neón",
1232 + "nervio",
1233 + "neto",
1234 + "neutro",
1235 + "nevar",
1236 + "nevera",
1237 + "nicho",
1238 + "nido",
1239 + "niebla",
1240 + "nieto",
1241 + "niñez",
1242 + "niño",
1243 + "nítido",
1244 + "nivel",
1245 + "nobleza",
1246 + "noche",
1247 + "nómina",
1248 + "noria",
1249 + "norma",
1250 + "norte",
1251 + "nota",
1252 + "noticia",
1253 + "novato",
1254 + "novela",
1255 + "novio",
1256 + "nube",
1257 + "nuca",
1258 + "núcleo",
1259 + "nudillo",
1260 + "nudo",
1261 + "nuera",
1262 + "nueve",
1263 + "nuez",
1264 + "nulo",
1265 + "número",
1266 + "nutria",
1267 + "oasis",
1268 + "obeso",
1269 + "obispo",
1270 + "objeto",
1271 + "obra",
1272 + "obrero",
1273 + "observar",
1274 + "obtener",
1275 + "obvio",
1276 + "oca",
1277 + "ocaso",
1278 + "océano",
1279 + "ochenta",
1280 + "ocho",
1281 + "ocio",
1282 + "ocre",
1283 + "octavo",
1284 + "octubre",
1285 + "oculto",
1286 + "ocupar",
1287 + "ocurrir",
1288 + "odiar",
1289 + "odio",
1290 + "odisea",
1291 + "oeste",
1292 + "ofensa",
1293 + "oferta",
1294 + "oficio",
1295 + "ofrecer",
1296 + "ogro",
1297 + "oído",
1298 + "oír",
1299 + "ojo",
1300 + "ola",
1301 + "oleada",
1302 + "olfato",
1303 + "olivo",
1304 + "olla",
1305 + "olmo",
1306 + "olor",
1307 + "olvido",
1308 + "ombligo",
1309 + "onda",
1310 + "onza",
1311 + "opaco",
1312 + "opción",
1313 + "ópera",
1314 + "opinar",
1315 + "oponer",
1316 + "optar",
1317 + "óptica",
1318 + "opuesto",
1319 + "oración",
1320 + "orador",
1321 + "oral",
1322 + "órbita",
1323 + "orca",
1324 + "orden",
1325 + "oreja",
1326 + "órgano",
1327 + "orgía",
1328 + "orgullo",
1329 + "oriente",
1330 + "origen",
1331 + "orilla",
1332 + "oro",
1333 + "orquesta",
1334 + "oruga",
1335 + "osadía",
1336 + "oscuro",
1337 + "osezno",
1338 + "oso",
1339 + "ostra",
1340 + "otoño",
1341 + "otro",
1342 + "oveja",
1343 + "óvulo",
1344 + "óxido",
1345 + "oxígeno",
1346 + "oyente",
1347 + "ozono",
1348 + "pacto",
1349 + "padre",
1350 + "paella",
1351 + "página",
1352 + "pago",
1353 + "país",
1354 + "pájaro",
1355 + "palabra",
1356 + "palco",
1357 + "paleta",
1358 + "pálido",
1359 + "palma",
1360 + "paloma",
1361 + "palpar",
1362 + "pan",
1363 + "panal",
1364 + "pánico",
1365 + "pantera",
1366 + "pañuelo",
1367 + "papá",
1368 + "papel",
1369 + "papilla",
1370 + "paquete",
1371 + "parar",
1372 + "parcela",
1373 + "pared",
1374 + "parir",
1375 + "paro",
1376 + "párpado",
1377 + "parque",
1378 + "párrafo",
1379 + "parte",
1380 + "pasar",
1381 + "paseo",
1382 + "pasión",
1383 + "paso",
1384 + "pasta",
1385 + "pata",
1386 + "patio",
1387 + "patria",
1388 + "pausa",
1389 + "pauta",
1390 + "pavo",
1391 + "payaso",
1392 + "peatón",
1393 + "pecado",
1394 + "pecera",
1395 + "pecho",
1396 + "pedal",
1397 + "pedir",
1398 + "pegar",
1399 + "peine",
1400 + "pelar",
1401 + "peldaño",
1402 + "pelea",
1403 + "peligro",
1404 + "pellejo",
1405 + "pelo",
1406 + "peluca",
1407 + "pena",
1408 + "pensar",
1409 + "peñón",
1410 + "peón",
1411 + "peor",
1412 + "pepino",
1413 + "pequeño",
1414 + "pera",
1415 + "percha",
1416 + "perder",
1417 + "pereza",
1418 + "perfil",
1419 + "perico",
1420 + "perla",
1421 + "permiso",
1422 + "perro",
1423 + "persona",
1424 + "pesa",
1425 + "pesca",
1426 + "pésimo",
1427 + "pestaña",
1428 + "pétalo",
1429 + "petróleo",
1430 + "pez",
1431 + "pezuña",
1432 + "picar",
1433 + "pichón",
1434 + "pie",
1435 + "piedra",
1436 + "pierna",
1437 + "pieza",
1438 + "pijama",
1439 + "pilar",
1440 + "piloto",
1441 + "pimienta",
1442 + "pino",
1443 + "pintor",
1444 + "pinza",
1445 + "piña",
1446 + "piojo",
1447 + "pipa",
1448 + "pirata",
1449 + "pisar",
1450 + "piscina",
1451 + "piso",
1452 + "pista",
1453 + "pitón",
1454 + "pizca",
1455 + "placa",
1456 + "plan",
1457 + "plata",
1458 + "playa",
1459 + "plaza",
1460 + "pleito",
1461 + "pleno",
1462 + "plomo",
1463 + "pluma",
1464 + "plural",
1465 + "pobre",
1466 + "poco",
1467 + "poder",
1468 + "podio",
1469 + "poema",
1470 + "poesía",
1471 + "poeta",
1472 + "polen",
1473 + "policía",
1474 + "pollo",
1475 + "polvo",
1476 + "pomada",
1477 + "pomelo",
1478 + "pomo",
1479 + "pompa",
1480 + "poner",
1481 + "porción",
1482 + "portal",
1483 + "posada",
1484 + "poseer",
1485 + "posible",
1486 + "poste",
1487 + "potencia",
1488 + "potro",
1489 + "pozo",
1490 + "prado",
1491 + "precoz",
1492 + "pregunta",
1493 + "premio",
1494 + "prensa",
1495 + "preso",
1496 + "previo",
1497 + "primo",
1498 + "príncipe",
1499 + "prisión",
1500 + "privar",
1501 + "proa",
1502 + "probar",
1503 + "proceso",
1504 + "producto",
1505 + "proeza",
1506 + "profesor",
1507 + "programa",
1508 + "prole",
1509 + "promesa",
1510 + "pronto",
1511 + "propio",
1512 + "próximo",
1513 + "prueba",
1514 + "público",
1515 + "puchero",
1516 + "pudor",
1517 + "pueblo",
1518 + "puerta",
1519 + "puesto",
1520 + "pulga",
1521 + "pulir",
1522 + "pulmón",
1523 + "pulpo",
1524 + "pulso",
1525 + "puma",
1526 + "punto",
1527 + "puñal",
1528 + "puño",
1529 + "pupa",
1530 + "pupila",
1531 + "puré",
1532 + "quedar",
1533 + "queja",
1534 + "quemar",
1535 + "querer",
1536 + "queso",
1537 + "quieto",
1538 + "química",
1539 + "quince",
1540 + "quitar",
1541 + "rábano",
1542 + "rabia",
1543 + "rabo",
1544 + "ración",
1545 + "radical",
1546 + "raíz",
1547 + "rama",
1548 + "rampa",
1549 + "rancho",
1550 + "rango",
1551 + "rapaz",
1552 + "rápido",
1553 + "rapto",
1554 + "rasgo",
1555 + "raspa",
1556 + "rato",
1557 + "rayo",
1558 + "raza",
1559 + "razón",
1560 + "reacción",
1561 + "realidad",
1562 + "rebaño",
1563 + "rebote",
1564 + "recaer",
1565 + "receta",
1566 + "rechazo",
1567 + "recoger",
1568 + "recreo",
1569 + "recto",
1570 + "recurso",
1571 + "red",
1572 + "redondo",
1573 + "reducir",
1574 + "reflejo",
1575 + "reforma",
1576 + "refrán",
1577 + "refugio",
1578 + "regalo",
1579 + "regir",
1580 + "regla",
1581 + "regreso",
1582 + "rehén",
1583 + "reino",
1584 + "reír",
1585 + "reja",
1586 + "relato",
1587 + "relevo",
1588 + "relieve",
1589 + "relleno",
1590 + "reloj",
1591 + "remar",
1592 + "remedio",
1593 + "remo",
1594 + "rencor",
1595 + "rendir",
1596 + "renta",
1597 + "reparto",
1598 + "repetir",
1599 + "reposo",
1600 + "reptil",
1601 + "res",
1602 + "rescate",
1603 + "resina",
1604 + "respeto",
1605 + "resto",
1606 + "resumen",
1607 + "retiro",
1608 + "retorno",
1609 + "retrato",
1610 + "reunir",
1611 + "revés",
1612 + "revista",
1613 + "rey",
1614 + "rezar",
1615 + "rico",
1616 + "riego",
1617 + "rienda",
1618 + "riesgo",
1619 + "rifa",
1620 + "rígido",
1621 + "rigor",
1622 + "rincón",
1623 + "riñón",
1624 + "río",
1625 + "riqueza",
1626 + "risa",
1627 + "ritmo",
1628 + "rito"
1629 + ];
1630 +}
\ No newline at end of file
cw_monero/lib/monero_account_list.dart new
+76
@@ -0,0 +1,76 @@
1 +import 'package:mobx/mobx.dart';
2 +import 'package:cw_monero/account.dart';
3 +import 'package:cw_monero/api/account_list.dart' as account_list;
4 +
5 +part 'monero_account_list.g.dart';
6 +
7 +class MoneroAccountList = MoneroAccountListBase with _$MoneroAccountList;
8 +
9 +abstract class MoneroAccountListBase with Store {
10 + MoneroAccountListBase()
11 + : accounts = ObservableList<Account>(),
12 + _isRefreshing = false,
13 + _isUpdating = false {
14 + refresh();
15 + print(account_list.accountSizeNative());
16 + }
17 +
18 + @observable
19 + ObservableList<Account> accounts;
20 + bool _isRefreshing;
21 + bool _isUpdating;
22 +
23 + void update() async {
24 + if (_isUpdating) {
25 + return;
26 + }
27 +
28 + try {
29 + _isUpdating = true;
30 + refresh();
31 + final accounts = getAll();
32 +
33 + if (accounts.isNotEmpty) {
34 + this.accounts.clear();
35 + this.accounts.addAll(accounts);
36 + }
37 +
38 + _isUpdating = false;
39 + } catch (e) {
40 + _isUpdating = false;
41 + rethrow;
42 + }
43 + }
44 +
45 + List<Account> getAll() => account_list
46 + .getAllAccount()
47 + .map((accountRow) => Account.fromRow(accountRow))
48 + .toList();
49 +
50 + Future addAccount({String label}) async {
51 + await account_list.addAccount(label: label);
52 + update();
53 + }
54 +
55 + Future setLabelAccount({int accountIndex, String label}) async {
56 + await account_list.setLabelForAccount(
57 + accountIndex: accountIndex, label: label);
58 + update();
59 + }
60 +
61 + void refresh() {
62 + if (_isRefreshing) {
63 + return;
64 + }
65 +
66 + try {
67 + _isRefreshing = true;
68 + account_list.refreshAccounts();
69 + _isRefreshing = false;
70 + } catch (e) {
71 + _isRefreshing = false;
72 + print(e);
73 + rethrow;
74 + }
75 + }
76 +}
cw_monero/lib/monero_amount_format.dart new
+17
@@ -0,0 +1,17 @@
1 +import 'package:intl/intl.dart';
2 +import 'package:cw_core/crypto_amount_format.dart';
3 +
4 +const moneroAmountLength = 12;
5 +const moneroAmountDivider = 1000000000000;
6 +final moneroAmountFormat = NumberFormat()
7 + ..maximumFractionDigits = moneroAmountLength
8 + ..minimumFractionDigits = 1;
9 +
10 +String moneroAmountToString({int amount}) => moneroAmountFormat
11 + .format(cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider));
12 +
13 +double moneroAmountToDouble({int amount}) =>
14 + cryptoAmountToDouble(amount: amount, divider: moneroAmountDivider);
15 +
16 +int moneroParseAmount({String amount}) =>
17 + (double.parse(amount) * moneroAmountDivider).toInt();
cw_monero/lib/monero_balance.dart new
+30
@@ -0,0 +1,30 @@
1 +import 'package:cw_core/balance.dart';
2 +import 'package:flutter/foundation.dart';
3 +import 'package:cw_monero/monero_amount_format.dart';
4 +
5 +class MoneroBalance extends Balance {
6 + MoneroBalance({@required this.fullBalance, @required this.unlockedBalance})
7 + : formattedFullBalance = moneroAmountToString(amount: fullBalance),
8 + formattedUnlockedBalance =
9 + moneroAmountToString(amount: unlockedBalance),
10 + super(unlockedBalance, fullBalance);
11 +
12 + MoneroBalance.fromString(
13 + {@required this.formattedFullBalance,
14 + @required this.formattedUnlockedBalance})
15 + : fullBalance = moneroParseAmount(amount: formattedFullBalance),
16 + unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
17 + super(moneroParseAmount(amount: formattedUnlockedBalance),
18 + moneroParseAmount(amount: formattedFullBalance));
19 +
20 + final int fullBalance;
21 + final int unlockedBalance;
22 + final String formattedFullBalance;
23 + final String formattedUnlockedBalance;
24 +
25 + @override
26 + String get formattedAvailableBalance => formattedUnlockedBalance;
27 +
28 + @override
29 + String get formattedAdditionalBalance => formattedFullBalance;
30 +}
cw_monero/lib/monero_subaddress_list.dart new
+84
@@ -0,0 +1,84 @@
1 +import 'package:cw_monero/api/structs/subaddress_row.dart';
2 +import 'package:flutter/services.dart';
3 +import 'package:mobx/mobx.dart';
4 +import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
5 +import 'package:cw_monero/subaddress.dart';
6 +
7 +part 'monero_subaddress_list.g.dart';
8 +
9 +class MoneroSubaddressList = MoneroSubaddressListBase
10 + with _$MoneroSubaddressList;
11 +
12 +abstract class MoneroSubaddressListBase with Store {
13 + MoneroSubaddressListBase() {
14 + _isRefreshing = false;
15 + _isUpdating = false;
16 + subaddresses = ObservableList<Subaddress>();
17 + }
18 +
19 + @observable
20 + ObservableList<Subaddress> subaddresses;
21 +
22 + bool _isRefreshing;
23 + bool _isUpdating;
24 +
25 + void update({int accountIndex}) {
26 + if (_isUpdating) {
27 + return;
28 + }
29 +
30 + try {
31 + _isUpdating = true;
32 + refresh(accountIndex: accountIndex);
33 + subaddresses.clear();
34 + subaddresses.addAll(getAll());
35 + _isUpdating = false;
36 + } catch (e) {
37 + _isUpdating = false;
38 + rethrow;
39 + }
40 + }
41 +
42 + List<Subaddress> getAll() {
43 + var subaddresses = subaddress_list.getAllSubaddresses();
44 +
45 + if (subaddresses.length > 2) {
46 + final primary = subaddresses.first;
47 + final rest = subaddresses.sublist(1).reversed;
48 + subaddresses = [primary] + rest.toList();
49 + }
50 +
51 + return subaddresses
52 + .map((subaddressRow) => Subaddress.fromRow(subaddressRow))
53 + .toList();
54 + }
55 +
56 + Future addSubaddress({int accountIndex, String label}) async {
57 + await subaddress_list.addSubaddress(
58 + accountIndex: accountIndex, label: label);
59 + update(accountIndex: accountIndex);
60 + }
61 +
62 + Future setLabelSubaddress(
63 + {int accountIndex, int addressIndex, String label}) async {
64 + await subaddress_list.setLabelForSubaddress(
65 + accountIndex: accountIndex, addressIndex: addressIndex, label: label);
66 + update(accountIndex: accountIndex);
67 + }
68 +
69 + void refresh({int accountIndex}) {
70 + if (_isRefreshing) {
71 + return;
72 + }
73 +
74 + try {
75 + _isRefreshing = true;
76 + subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
77 + _isRefreshing = false;
78 + } on PlatformException catch (e) {
79 + _isRefreshing = false;
80 + print(e);
81 + rethrow;
82 + }
83 + }
84 +}
cw_monero/lib/monero_transaction_creation_credentials.dart new
+11
@@ -0,0 +1,11 @@
1 +//import 'package:cake_wallet/entities/transaction_creation_credentials.dart';
2 +import 'package:cw_monero/monero_transaction_priority.dart';
3 +//import 'package:cake_wallet/view_model/send/output.dart';
4 +import 'package:cw_core/output_info.dart';
5 +
6 +class MoneroTransactionCreationCredentials {
7 + MoneroTransactionCreationCredentials({this.outputs, this.priority});
8 +
9 + final List<OutputInfo> outputs;
10 + final MoneroTransactionPriority priority;
11 +}
cw_monero/lib/monero_transaction_creation_exception.dart new
+8
@@ -0,0 +1,8 @@
1 +class MoneroTransactionCreationException implements Exception {
2 + MoneroTransactionCreationException(this.message);
3 +
4 + final String message;
5 +
6 + @override
7 + String toString() => message;
8 +}
\ No newline at end of file
cw_monero/lib/monero_transaction_history.dart new
+27
@@ -0,0 +1,27 @@
1 +import 'dart:core';
2 +import 'package:mobx/mobx.dart';
3 +import 'package:cw_core/transaction_history.dart';
4 +import 'package:cw_monero/monero_transaction_info.dart';
5 +
6 +part 'monero_transaction_history.g.dart';
7 +
8 +class MoneroTransactionHistory = MoneroTransactionHistoryBase
9 + with _$MoneroTransactionHistory;
10 +
11 +abstract class MoneroTransactionHistoryBase
12 + extends TransactionHistoryBase<MoneroTransactionInfo> with Store {
13 + MoneroTransactionHistoryBase() {
14 + transactions = ObservableMap<String, MoneroTransactionInfo>();
15 + }
16 +
17 + @override
18 + Future<void> save() async {}
19 +
20 + @override
21 + void addOne(MoneroTransactionInfo transaction) =>
22 + transactions[transaction.id] = transaction;
23 +
24 + @override
25 + void addMany(Map<String, MoneroTransactionInfo> transactions) =>
26 + this.transactions.addAll(transactions);
27 +}
cw_monero/lib/monero_transaction_info.dart new
+68
@@ -0,0 +1,68 @@
1 +import 'package:cw_core/transaction_info.dart';
2 +import 'package:cw_monero/monero_amount_format.dart';
3 +import 'package:cw_monero/api/structs/transaction_info_row.dart';
4 +import 'package:cw_core/parseBoolFromString.dart';
5 +import 'package:cw_core/transaction_direction.dart';
6 +import 'package:cw_core/format_amount.dart';
7 +import 'package:cw_monero/api/transaction_history.dart';
8 +
9 +class MoneroTransactionInfo extends TransactionInfo {
10 + MoneroTransactionInfo(this.id, this.height, this.direction, this.date,
11 + this.isPending, this.amount, this.accountIndex, this.addressIndex, this.fee);
12 +
13 + MoneroTransactionInfo.fromMap(Map map)
14 + : id = (map['hash'] ?? '') as String,
15 + height = (map['height'] ?? 0) as int,
16 + direction =
17 + parseTransactionDirectionFromNumber(map['direction'] as String) ??
18 + TransactionDirection.incoming,
19 + date = DateTime.fromMillisecondsSinceEpoch(
20 + (int.parse(map['timestamp'] as String) ?? 0) * 1000),
21 + isPending = parseBoolFromString(map['isPending'] as String),
22 + amount = map['amount'] as int,
23 + accountIndex = int.parse(map['accountIndex'] as String),
24 + addressIndex = map['addressIndex'] as int,
25 + key = getTxKey((map['hash'] ?? '') as String),
26 + fee = map['fee'] as int ?? 0;
27 +
28 + MoneroTransactionInfo.fromRow(TransactionInfoRow row)
29 + : id = row.getHash(),
30 + height = row.blockHeight,
31 + direction = parseTransactionDirectionFromInt(row.direction) ??
32 + TransactionDirection.incoming,
33 + date = DateTime.fromMillisecondsSinceEpoch(row.getDatetime() * 1000),
34 + isPending = row.isPending != 0,
35 + amount = row.getAmount(),
36 + accountIndex = row.subaddrAccount,
37 + addressIndex = row.subaddrIndex,
38 + key = getTxKey(row.getHash()),
39 + fee = row.fee;
40 +
41 + final String id;
42 + final int height;
43 + final TransactionDirection direction;
44 + final DateTime date;
45 + final int accountIndex;
46 + final bool isPending;
47 + final int amount;
48 + final int fee;
49 + final int addressIndex;
50 + String recipientAddress;
51 + String key;
52 +
53 + String _fiatAmount;
54 +
55 + @override
56 + String amountFormatted() =>
57 + '${formatAmount(moneroAmountToString(amount: amount))} XMR';
58 +
59 + @override
60 + String fiatAmount() => _fiatAmount ?? '';
61 +
62 + @override
63 + void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
64 +
65 + @override
66 + String feeFormatted() =>
67 + '${formatAmount(moneroAmountToString(amount: fee))} XMR';
68 +}
cw_monero/lib/monero_transaction_priority.dart new
+74
@@ -0,0 +1,74 @@
1 +import 'package:cw_core/transaction_priority.dart';
2 +import 'package:cw_core/wallet_type.dart';
3 +//import 'package:cake_wallet/generated/i18n.dart';
4 +import 'package:cw_core/enumerable_item.dart';
5 +
6 +class MoneroTransactionPriority extends TransactionPriority {
7 + const MoneroTransactionPriority({String title, int raw})
8 + : super(title: title, raw: raw);
9 +
10 + static const all = [
11 + MoneroTransactionPriority.slow,
12 + MoneroTransactionPriority.regular,
13 + MoneroTransactionPriority.medium,
14 + MoneroTransactionPriority.fast,
15 + MoneroTransactionPriority.fastest
16 + ];
17 + static const slow = MoneroTransactionPriority(title: 'Slow', raw: 0);
18 + static const regular = MoneroTransactionPriority(title: 'Regular', raw: 1);
19 + static const medium = MoneroTransactionPriority(title: 'Medium', raw: 2);
20 + static const fast = MoneroTransactionPriority(title: 'Fast', raw: 3);
21 + static const fastest = MoneroTransactionPriority(title: 'Fastest', raw: 4);
22 + static const standard = slow;
23 +
24 +
25 + static List<MoneroTransactionPriority> forWalletType(WalletType type) {
26 + switch (type) {
27 + case WalletType.monero:
28 + return MoneroTransactionPriority.all;
29 + case WalletType.bitcoin:
30 + return [
31 + MoneroTransactionPriority.slow,
32 + MoneroTransactionPriority.regular,
33 + MoneroTransactionPriority.fast
34 + ];
35 + default:
36 + return [];
37 + }
38 + }
39 +
40 + static MoneroTransactionPriority deserialize({int raw}) {
41 + switch (raw) {
42 + case 0:
43 + return slow;
44 + case 1:
45 + return regular;
46 + case 2:
47 + return medium;
48 + case 3:
49 + return fast;
50 + case 4:
51 + return fastest;
52 + default:
53 + return null;
54 + }
55 + }
56 +
57 + @override
58 + String toString() {
59 + switch (this) {
60 + case MoneroTransactionPriority.slow:
61 + return 'Slow'; // S.current.transaction_priority_slow;
62 + case MoneroTransactionPriority.regular:
63 + return 'Regular'; // S.current.transaction_priority_regular;
64 + case MoneroTransactionPriority.medium:
65 + return 'Medium'; // S.current.transaction_priority_medium;
66 + case MoneroTransactionPriority.fast:
67 + return 'Fast'; // S.current.transaction_priority_fast;
68 + case MoneroTransactionPriority.fastest:
69 + return 'Fastest'; // S.current.transaction_priority_fastest;
70 + default:
71 + return '';
72 + }
73 + }
74 +}
cw_monero/lib/monero_wallet.dart new
+413
@@ -0,0 +1,413 @@
1 +import 'dart:async';
2 +import 'package:cw_core/transaction_priority.dart';
3 +import 'package:cw_monero/monero_amount_format.dart';
4 +import 'package:cw_monero/monero_transaction_creation_exception.dart';
5 +import 'package:cw_monero/monero_transaction_info.dart';
6 +import 'package:cw_monero/monero_wallet_addresses.dart';
7 +import 'package:cw_monero/monero_wallet_utils.dart';
8 +import 'package:cw_monero/api/structs/pending_transaction.dart';
9 +import 'package:flutter/foundation.dart';
10 +import 'package:mobx/mobx.dart';
11 +import 'package:cw_monero/api/transaction_history.dart'
12 + as monero_transaction_history;
13 +import 'package:cw_monero/api/wallet.dart';
14 +import 'package:cw_monero/api/wallet.dart' as monero_wallet;
15 +import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
16 +import 'package:cw_monero/api/monero_output.dart';
17 +import 'package:cw_monero/monero_transaction_creation_credentials.dart';
18 +import 'package:cw_monero/pending_monero_transaction.dart';
19 +import 'package:cw_monero/monero_wallet_keys.dart';
20 +import 'package:cw_monero/monero_balance.dart';
21 +import 'package:cw_monero/monero_transaction_history.dart';
22 +import 'package:cw_monero/account.dart';
23 +import 'package:cw_core/pending_transaction.dart';
24 +import 'package:cw_core/wallet_base.dart';
25 +import 'package:cw_core/sync_status.dart';
26 +import 'package:cw_core/wallet_info.dart';
27 +import 'package:cw_core/node.dart';
28 +import 'package:cw_monero/monero_transaction_priority.dart';
29 +
30 +part 'monero_wallet.g.dart';
31 +
32 +const moneroBlockSize = 1000;
33 +
34 +class MoneroWallet = MoneroWalletBase with _$MoneroWallet;
35 +
36 +abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
37 + MoneroTransactionHistory, MoneroTransactionInfo> with Store {
38 + MoneroWalletBase({WalletInfo walletInfo})
39 + : super(walletInfo) {
40 + transactionHistory = MoneroTransactionHistory();
41 + balance = MoneroBalance(
42 + fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
43 + unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0));
44 + _isTransactionUpdating = false;
45 + _hasSyncAfterStartup = false;
46 + walletAddresses = MoneroWalletAddresses(walletInfo);
47 + _onAccountChangeReaction = reaction((_) => walletAddresses.account,
48 + (Account account) {
49 + balance = MoneroBalance(
50 + fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
51 + unlockedBalance:
52 + monero_wallet.getUnlockedBalance(accountIndex: account.id));
53 + walletAddresses.updateSubaddressList(accountIndex: account.id);
54 + });
55 + }
56 +
57 + static const int _autoSaveInterval = 30;
58 +
59 + @override
60 + MoneroWalletAddresses walletAddresses;
61 +
62 + @override
63 + @observable
64 + SyncStatus syncStatus;
65 +
66 + @override
67 + @observable
68 + MoneroBalance balance;
69 +
70 + @override
71 + String get seed => monero_wallet.getSeed();
72 +
73 + @override
74 + MoneroWalletKeys get keys => MoneroWalletKeys(
75 + privateSpendKey: monero_wallet.getSecretSpendKey(),
76 + privateViewKey: monero_wallet.getSecretViewKey(),
77 + publicSpendKey: monero_wallet.getPublicSpendKey(),
78 + publicViewKey: monero_wallet.getPublicViewKey());
79 +
80 + SyncListener _listener;
81 + ReactionDisposer _onAccountChangeReaction;
82 + bool _isTransactionUpdating;
83 + bool _hasSyncAfterStartup;
84 + Timer _autoSaveTimer;
85 +
86 + Future<void> init() async {
87 + await walletAddresses.init();
88 + balance = MoneroBalance(
89 + fullBalance: monero_wallet.getFullBalance(accountIndex: walletAddresses.account.id),
90 + unlockedBalance:
91 + monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id));
92 + _setListeners();
93 + await updateTransactions();
94 +
95 + if (walletInfo.isRecovery) {
96 + monero_wallet.setRecoveringFromSeed(isRecovery: walletInfo.isRecovery);
97 +
98 + if (monero_wallet.getCurrentHeight() <= 1) {
99 + monero_wallet.setRefreshFromBlockHeight(
100 + height: walletInfo.restoreHeight);
101 + }
102 + }
103 +
104 + _autoSaveTimer = Timer.periodic(
105 + Duration(seconds: _autoSaveInterval),
106 + (_) async => await save());
107 + }
108 +
109 + @override
110 + void close() {
111 + _listener?.stop();
112 + _onAccountChangeReaction?.reaction?.dispose();
113 + _autoSaveTimer?.cancel();
114 + }
115 +
116 + @override
117 + Future<void> connectToNode({@required Node node}) async {
118 + try {
119 + syncStatus = ConnectingSyncStatus();
120 + await monero_wallet.setupNode(
121 + address: node.uri.toString(),
122 + login: node.login,
123 + password: node.password,
124 + useSSL: node.isSSL,
125 + isLightWallet: false); // FIXME: hardcoded value
126 + syncStatus = ConnectedSyncStatus();
127 + } catch (e) {
128 + syncStatus = FailedSyncStatus();
129 + print(e);
130 + }
131 + }
132 +
133 + @override
134 + Future<void> startSync() async {
135 + try {
136 + _setInitialHeight();
137 + } catch (_) {}
138 +
139 + try {
140 + syncStatus = StartingSyncStatus();
141 + monero_wallet.startRefresh();
142 + _setListeners();
143 + _listener?.start();
144 + } catch (e) {
145 + syncStatus = FailedSyncStatus();
146 + print(e);
147 + rethrow;
148 + }
149 + }
150 +
151 + @override
152 + Future<PendingTransaction> createTransaction(Object credentials) async {
153 + final _credentials = credentials as MoneroTransactionCreationCredentials;
154 + final outputs = _credentials.outputs;
155 + final hasMultiDestination = outputs.length > 1;
156 + final unlockedBalance =
157 + monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
158 +
159 + PendingTransactionDescription pendingTransactionDescription;
160 +
161 + if (!(syncStatus is SyncedSyncStatus)) {
162 + throw MoneroTransactionCreationException('The wallet is not synced.');
163 + }
164 +
165 + if (hasMultiDestination) {
166 + if (outputs.any((item) => item.sendAll
167 + || item.formattedCryptoAmount <= 0)) {
168 + throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
169 + }
170 +
171 + final int totalAmount = outputs.fold(0, (acc, value) =>
172 + acc + value.formattedCryptoAmount);
173 +
174 + if (unlockedBalance < totalAmount) {
175 + throw MoneroTransactionCreationException('Wrong balance. Not enough XMR on your balance.');
176 + }
177 +
178 + final moneroOutputs = outputs.map((output) {
179 + final outputAddress = output.isParsedAddress
180 + ? output.extractedAddress
181 + : output.address;
182 +
183 + return MoneroOutput(
184 + address: outputAddress,
185 + amount: output.cryptoAmount.replaceAll(',', '.'));
186 + }).toList();
187 +
188 + pendingTransactionDescription =
189 + await transaction_history.createTransactionMultDest(
190 + outputs: moneroOutputs,
191 + priorityRaw: _credentials.priority.serialize(),
192 + accountIndex: walletAddresses.account.id);
193 + } else {
194 + final output = outputs.first;
195 + final address = output.isParsedAddress
196 + ? output.extractedAddress
197 + : output.address;
198 + final amount = output.sendAll
199 + ? null
200 + : output.cryptoAmount.replaceAll(',', '.');
201 + final formattedAmount = output.sendAll
202 + ? null
203 + : output.formattedCryptoAmount;
204 +
205 + if ((formattedAmount != null && unlockedBalance < formattedAmount) ||
206 + (formattedAmount == null && unlockedBalance <= 0)) {
207 + final formattedBalance = moneroAmountToString(amount: unlockedBalance);
208 +
209 + throw MoneroTransactionCreationException(
210 + 'Incorrect unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
211 + }
212 +
213 + pendingTransactionDescription =
214 + await transaction_history.createTransaction(
215 + address: address,
216 + amount: amount,
217 + priorityRaw: _credentials.priority.serialize(),
218 + accountIndex: walletAddresses.account.id);
219 + }
220 +
221 + return PendingMoneroTransaction(pendingTransactionDescription);
222 + }
223 +
224 + @override
225 + int calculateEstimatedFee(TransactionPriority priority, int amount) {
226 + // FIXME: hardcoded value;
227 +
228 + if (priority is MoneroTransactionPriority) {
229 + switch (priority) {
230 + case MoneroTransactionPriority.slow:
231 + return 24590000;
232 + case MoneroTransactionPriority.regular:
233 + return 123050000;
234 + case MoneroTransactionPriority.medium:
235 + return 245029999;
236 + case MoneroTransactionPriority.fast:
237 + return 614530000;
238 + case MoneroTransactionPriority.fastest:
239 + return 26021600000;
240 + }
241 + }
242 +
243 + return 0;
244 + }
245 +
246 + @override
247 + Future<void> save() async {
248 + await walletAddresses.updateAddressesInBox();
249 + await backupWalletFiles(name);
250 + await monero_wallet.store();
251 + }
252 +
253 + Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
254 +
255 + Future<bool> isConnected() async => monero_wallet.isConnected();
256 +
257 + Future<void> setAsRecovered() async {
258 + walletInfo.isRecovery = false;
259 + await walletInfo.save();
260 + }
261 +
262 + @override
263 + Future<void> rescan({int height}) async {
264 + walletInfo.restoreHeight = height;
265 + walletInfo.isRecovery = true;
266 + monero_wallet.setRefreshFromBlockHeight(height: height);
267 + monero_wallet.rescanBlockchainAsync();
268 + await startSync();
269 + _askForUpdateBalance();
270 + walletAddresses.accountList.update();
271 + await _askForUpdateTransactionHistory();
272 + await save();
273 + await walletInfo.save();
274 + }
275 +
276 + String getTransactionAddress(int accountIndex, int addressIndex) =>
277 + monero_wallet.getAddress(
278 + accountIndex: accountIndex,
279 + addressIndex: addressIndex);
280 +
281 + @override
282 + Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
283 + monero_transaction_history.refreshTransactions();
284 + return _getAllTransactions(null).fold<Map<String, MoneroTransactionInfo>>(
285 + <String, MoneroTransactionInfo>{},
286 + (Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
287 + acc[tx.id] = tx;
288 + return acc;
289 + });
290 + }
291 +
292 + Future<void> updateTransactions() async {
293 + try {
294 + if (_isTransactionUpdating) {
295 + return;
296 + }
297 +
298 + _isTransactionUpdating = true;
299 + final transactions = await fetchTransactions();
300 + transactionHistory.addMany(transactions);
301 + await transactionHistory.save();
302 + _isTransactionUpdating = false;
303 + } catch (e) {
304 + print(e);
305 + _isTransactionUpdating = false;
306 + }
307 + }
308 +
309 + List<MoneroTransactionInfo> _getAllTransactions(dynamic _) =>
310 + monero_transaction_history
311 + .getAllTransations()
312 + .map((row) => MoneroTransactionInfo.fromRow(row))
313 + .toList();
314 +
315 + void _setListeners() {
316 + _listener?.stop();
317 + _listener = monero_wallet.setListeners(_onNewBlock, _onNewTransaction);
318 + }
319 +
320 + void _setInitialHeight() {
321 + if (walletInfo.isRecovery) {
322 + return;
323 + }
324 +
325 + final currentHeight = getCurrentHeight();
326 +
327 + if (currentHeight <= 1) {
328 + final height = _getHeightByDate(walletInfo.date);
329 + monero_wallet.setRecoveringFromSeed(isRecovery: true);
330 + monero_wallet.setRefreshFromBlockHeight(height: height);
331 + }
332 + }
333 +
334 + int _getHeightDistance(DateTime date) {
335 + final distance =
336 + DateTime.now().millisecondsSinceEpoch - date.millisecondsSinceEpoch;
337 + final daysTmp = (distance / 86400).round();
338 + final days = daysTmp < 1 ? 1 : daysTmp;
339 +
340 + return days * 1000;
341 + }
342 +
343 + int _getHeightByDate(DateTime date) {
344 + final nodeHeight = monero_wallet.getNodeHeightSync();
345 + final heightDistance = _getHeightDistance(date);
346 +
347 + if (nodeHeight <= 0) {
348 + return 0;
349 + }
350 +
351 + return nodeHeight - heightDistance;
352 + }
353 +
354 + void _askForUpdateBalance() {
355 + final unlockedBalance = _getUnlockedBalance();
356 + final fullBalance = _getFullBalance();
357 +
358 + if (balance.fullBalance != fullBalance ||
359 + balance.unlockedBalance != unlockedBalance) {
360 + balance = MoneroBalance(
361 + fullBalance: fullBalance, unlockedBalance: unlockedBalance);
362 + }
363 + }
364 +
365 + Future<void> _askForUpdateTransactionHistory() async =>
366 + await updateTransactions();
367 +
368 + int _getFullBalance() =>
369 + monero_wallet.getFullBalance(accountIndex: walletAddresses.account.id);
370 +
371 + int _getUnlockedBalance() =>
372 + monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account.id);
373 +
374 + void _onNewBlock(int height, int blocksLeft, double ptc) async {
375 + try {
376 + if (walletInfo.isRecovery) {
377 + await _askForUpdateTransactionHistory();
378 + _askForUpdateBalance();
379 + walletAddresses.accountList.update();
380 + }
381 +
382 + if (blocksLeft < 100) {
383 + await _askForUpdateTransactionHistory();
384 + _askForUpdateBalance();
385 + walletAddresses.accountList.update();
386 + syncStatus = SyncedSyncStatus();
387 +
388 + if (!_hasSyncAfterStartup) {
389 + _hasSyncAfterStartup = true;
390 + await save();
391 + }
392 +
393 + if (walletInfo.isRecovery) {
394 + await setAsRecovered();
395 + }
396 + } else {
397 + syncStatus = SyncingSyncStatus(blocksLeft, ptc);
398 + }
399 + } catch (e) {
400 + print(e.toString());
401 + }
402 + }
403 +
404 + void _onNewTransaction() async {
405 + try {
406 + await _askForUpdateTransactionHistory();
407 + _askForUpdateBalance();
408 + await Future<void>.delayed(Duration(seconds: 1));
409 + } catch (e) {
410 + print(e.toString());
411 + }
412 + }
413 +}
cw_monero/lib/monero_wallet_addresses.dart new
+85
@@ -0,0 +1,85 @@
1 +import 'package:cw_core/wallet_addresses.dart';
2 +import 'package:cw_core/wallet_info.dart';
3 +import 'package:cw_monero/account.dart';
4 +import 'package:cw_monero/monero_account_list.dart';
5 +import 'package:cw_monero/monero_subaddress_list.dart';
6 +import 'package:cw_monero/subaddress.dart';
7 +import 'package:mobx/mobx.dart';
8 +
9 +part 'monero_wallet_addresses.g.dart';
10 +
11 +class MoneroWalletAddresses = MoneroWalletAddressesBase
12 + with _$MoneroWalletAddresses;
13 +
14 +abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
15 + MoneroWalletAddressesBase(WalletInfo walletInfo) : super(walletInfo) {
16 + accountList = MoneroAccountList();
17 + subaddressList = MoneroSubaddressList();
18 + }
19 +
20 + @override
21 + @observable
22 + String address;
23 +
24 + @observable
25 + Account account;
26 +
27 + @observable
28 + Subaddress subaddress;
29 +
30 + MoneroSubaddressList subaddressList;
31 +
32 + MoneroAccountList accountList;
33 +
34 + @override
35 + Future<void> init() async {
36 + accountList.update();
37 + account = accountList.accounts.first;
38 + updateSubaddressList(accountIndex: account.id ?? 0);
39 + await updateAddressesInBox();
40 + }
41 +
42 + @override
43 + Future<void> updateAddressesInBox() async {
44 + try {
45 + final _subaddressList = MoneroSubaddressList();
46 +
47 + addressesMap.clear();
48 +
49 + accountList.accounts.forEach((account) {
50 + _subaddressList.update(accountIndex: account.id);
51 + _subaddressList.subaddresses.forEach((subaddress) {
52 + addressesMap[subaddress.address] = subaddress.label;
53 + });
54 + });
55 +
56 + await saveAddressesInBox();
57 + } catch (e) {
58 + print(e.toString());
59 + }
60 + }
61 +
62 + bool validate() {
63 + accountList.update();
64 + final accountListLength = accountList.accounts?.length ?? 0;
65 +
66 + if (accountListLength <= 0) {
67 + return false;
68 + }
69 +
70 + subaddressList.update(accountIndex: accountList.accounts.first.id);
71 + final subaddressListLength = subaddressList.subaddresses?.length ?? 0;
72 +
73 + if (subaddressListLength <= 0) {
74 + return false;
75 + }
76 +
77 + return true;
78 + }
79 +
80 + void updateSubaddressList({int accountIndex}) {
81 + subaddressList.update(accountIndex: accountIndex);
82 + subaddress = subaddressList.subaddresses.first;
83 + address = subaddress.address;
84 + }
85 +}
\ No newline at end of file
cw_monero/lib/monero_wallet_keys.dart new
+12
@@ -0,0 +1,12 @@
1 +class MoneroWalletKeys {
2 + const MoneroWalletKeys(
3 + {this.privateSpendKey,
4 + this.privateViewKey,
5 + this.publicSpendKey,
6 + this.publicViewKey});
7 +
8 + final String publicViewKey;
9 + final String privateViewKey;
10 + final String publicSpendKey;
11 + final String privateSpendKey;
12 +}
\ No newline at end of file
cw_monero/lib/monero_wallet_service.dart new
+229
@@ -0,0 +1,229 @@
1 +import 'dart:io';
2 +import 'package:cw_core/wallet_base.dart';
3 +import 'package:cw_monero/monero_wallet_utils.dart';
4 +import 'package:hive/hive.dart';
5 +import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
6 +import 'package:cw_monero/api/wallet.dart' as monero_wallet;
7 +import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
8 +import 'package:cw_monero/monero_wallet.dart';
9 +import 'package:cw_core/wallet_credentials.dart';
10 +import 'package:cw_core/wallet_service.dart';
11 +import 'package:cw_core/pathForWallet.dart';
12 +import 'package:cw_core/wallet_info.dart';
13 +import 'package:cw_core/wallet_type.dart';
14 +
15 +class MoneroNewWalletCredentials extends WalletCredentials {
16 + MoneroNewWalletCredentials({String name, String password, this.language})
17 + : super(name: name, password: password);
18 +
19 + final String language;
20 +}
21 +
22 +class MoneroRestoreWalletFromSeedCredentials extends WalletCredentials {
23 + MoneroRestoreWalletFromSeedCredentials(
24 + {String name, String password, int height, this.mnemonic})
25 + : super(name: name, password: password, height: height);
26 +
27 + final String mnemonic;
28 +}
29 +
30 +class MoneroWalletLoadingException implements Exception {
31 + @override
32 + String toString() => 'Failure to load the wallet.';
33 +}
34 +
35 +class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
36 + MoneroRestoreWalletFromKeysCredentials(
37 + {String name,
38 + String password,
39 + this.language,
40 + this.address,
41 + this.viewKey,
42 + this.spendKey,
43 + int height})
44 + : super(name: name, password: password, height: height);
45 +
46 + final String language;
47 + final String address;
48 + final String viewKey;
49 + final String spendKey;
50 +}
51 +
52 +class MoneroWalletService extends WalletService<
53 + MoneroNewWalletCredentials,
54 + MoneroRestoreWalletFromSeedCredentials,
55 + MoneroRestoreWalletFromKeysCredentials> {
56 + MoneroWalletService(this.walletInfoSource);
57 +
58 + final Box<WalletInfo> walletInfoSource;
59 +
60 + static bool walletFilesExist(String path) =>
61 + !File(path).existsSync() && !File('$path.keys').existsSync();
62 +
63 + @override
64 + WalletType getType() => WalletType.monero;
65 +
66 + @override
67 + Future<MoneroWallet> create(MoneroNewWalletCredentials credentials) async {
68 + try {
69 + final path = await pathForWallet(name: credentials.name, type: getType());
70 + await monero_wallet_manager.createWallet(
71 + path: path,
72 + password: credentials.password,
73 + language: credentials.language);
74 + final wallet = MoneroWallet(walletInfo: credentials.walletInfo);
75 + await wallet.init();
76 +
77 + return wallet;
78 + } catch (e) {
79 + // TODO: Implement Exception for wallet list service.
80 + print('MoneroWalletsManager Error: ${e.toString()}');
81 + rethrow;
82 + }
83 + }
84 +
85 + @override
86 + Future<bool> isWalletExit(String name) async {
87 + try {
88 + final path = await pathForWallet(name: name, type: getType());
89 + return monero_wallet_manager.isWalletExist(path: path);
90 + } catch (e) {
91 + // TODO: Implement Exception for wallet list service.
92 + print('MoneroWalletsManager Error: $e');
93 + rethrow;
94 + }
95 + }
96 +
97 + @override
98 + Future<MoneroWallet> openWallet(String name, String password) async {
99 + try {
100 + final path = await pathForWallet(name: name, type: getType());
101 +
102 + if (walletFilesExist(path)) {
103 + await repairOldAndroidWallet(name);
104 + }
105 +
106 + await monero_wallet_manager
107 + .openWalletAsync({'path': path, 'password': password});
108 + final walletInfo = walletInfoSource.values.firstWhere(
109 + (info) => info.id == WalletBase.idFor(name, getType()),
110 + orElse: () => null);
111 + final wallet = MoneroWallet(walletInfo: walletInfo);
112 + final isValid = wallet.walletAddresses.validate();
113 +
114 + if (!isValid) {
115 + await restoreOrResetWalletFiles(name);
116 + wallet.close();
117 + return openWallet(name, password);
118 + }
119 +
120 + await wallet.init();
121 +
122 + return wallet;
123 + } catch (e) {
124 + // TODO: Implement Exception for wallet list service.
125 +
126 + if ((e.toString().contains('bad_alloc') ||
127 + (e is WalletOpeningException &&
128 + (e.message == 'std::bad_alloc' ||
129 + e.message.contains('bad_alloc')))) ||
130 + (e.toString().contains('does not correspond') ||
131 + (e is WalletOpeningException &&
132 + e.message.contains('does not correspond')))) {
133 + await restoreOrResetWalletFiles(name);
134 + return openWallet(name, password);
135 + }
136 +
137 + rethrow;
138 + }
139 + }
140 +
141 + @override
142 + Future<void> remove(String wallet) async {
143 + final path = await pathForWalletDir(name: wallet, type: getType());
144 + final file = Directory(path);
145 + final isExist = file.existsSync();
146 +
147 + if (isExist) {
148 + await file.delete(recursive: true);
149 + }
150 + }
151 +
152 + @override
153 + Future<MoneroWallet> restoreFromKeys(
154 + MoneroRestoreWalletFromKeysCredentials credentials) async {
155 + try {
156 + final path = await pathForWallet(name: credentials.name, type: getType());
157 + await monero_wallet_manager.restoreFromKeys(
158 + path: path,
159 + password: credentials.password,
160 + language: credentials.language,
161 + restoreHeight: credentials.height,
162 + address: credentials.address,
163 + viewKey: credentials.viewKey,
164 + spendKey: credentials.spendKey);
165 + final wallet = MoneroWallet(walletInfo: credentials.walletInfo);
166 + await wallet.init();
167 +
168 + return wallet;
169 + } catch (e) {
170 + // TODO: Implement Exception for wallet list service.
171 + print('MoneroWalletsManager Error: $e');
172 + rethrow;
173 + }
174 + }
175 +
176 + @override
177 + Future<MoneroWallet> restoreFromSeed(
178 + MoneroRestoreWalletFromSeedCredentials credentials) async {
179 + try {
180 + final path = await pathForWallet(name: credentials.name, type: getType());
181 + await monero_wallet_manager.restoreFromSeed(
182 + path: path,
183 + password: credentials.password,
184 + seed: credentials.mnemonic,
185 + restoreHeight: credentials.height);
186 + final wallet = MoneroWallet(walletInfo: credentials.walletInfo);
187 + await wallet.init();
188 +
189 + return wallet;
190 + } catch (e) {
191 + // TODO: Implement Exception for wallet list service.
192 + print('MoneroWalletsManager Error: $e');
193 + rethrow;
194 + }
195 + }
196 +
197 + Future<void> repairOldAndroidWallet(String name) async {
198 + try {
199 + if (!Platform.isAndroid) {
200 + return;
201 + }
202 +
203 + final oldAndroidWalletDirPath =
204 + await outdatedAndroidPathForWalletDir(name: name);
205 + final dir = Directory(oldAndroidWalletDirPath);
206 +
207 + if (!dir.existsSync()) {
208 + return;
209 + }
210 +
211 + final newWalletDirPath =
212 + await pathForWalletDir(name: name, type: getType());
213 +
214 + dir.listSync().forEach((f) {
215 + final file = File(f.path);
216 + final name = f.path.split('/').last;
217 + final newPath = newWalletDirPath + '/$name';
218 + final newFile = File(newPath);
219 +
220 + if (!newFile.existsSync()) {
221 + newFile.createSync();
222 + }
223 + newFile.writeAsBytesSync(file.readAsBytesSync());
224 + });
225 + } catch (e) {
226 + print(e.toString());
227 + }
228 + }
229 +}
cw_monero/lib/monero_wallet_utils.dart new
+88
@@ -0,0 +1,88 @@
1 +import 'dart:io';
2 +import 'package:cw_core/pathForWallet.dart';
3 +import 'package:cw_core/wallet_type.dart';
4 +
5 +String backupFileName(String originalPath) {
6 + final pathParts = originalPath.split('/');
7 + final newName = '#_${pathParts.last}';
8 + pathParts.removeLast();
9 + pathParts.add(newName);
10 + return pathParts.join('/');
11 +}
12 +
13 +Future<void> backupWalletFiles(String name) async {
14 + final path = await pathForWallet(name: name, type: WalletType.monero);
15 + final cacheFile = File(path);
16 + final keysFile = File('$path.keys');
17 + final addressListFile = File('$path.address.txt');
18 + final newCacheFilePath = backupFileName(cacheFile.path);
19 + final newKeysFilePath = backupFileName(keysFile.path);
20 + final newAddressListFilePath = backupFileName(addressListFile.path);
21 +
22 + if (cacheFile.existsSync()) {
23 + await cacheFile.copy(newCacheFilePath);
24 + }
25 +
26 + if (keysFile.existsSync()) {
27 + await keysFile.copy(newKeysFilePath);
28 + }
29 +
30 + if (addressListFile.existsSync()) {
31 + await addressListFile.copy(newAddressListFilePath);
32 + }
33 +}
34 +
35 +Future<void> restoreWalletFiles(String name) async {
36 + final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
37 + final cacheFilePath = '$walletDirPath/$name';
38 + final keysFilePath = '$walletDirPath/$name.keys';
39 + final addressListFilePath = '$walletDirPath/$name.address.txt';
40 + final backupCacheFile = File(backupFileName(cacheFilePath));
41 + final backupKeysFile = File(backupFileName(keysFilePath));
42 + final backupAddressListFile = File(backupFileName(addressListFilePath));
43 +
44 + if (backupCacheFile.existsSync()) {
45 + await backupCacheFile.copy(cacheFilePath);
46 + }
47 +
48 + if (backupKeysFile.existsSync()) {
49 + await backupKeysFile.copy(keysFilePath);
50 + }
51 +
52 + if (backupAddressListFile.existsSync()) {
53 + await backupAddressListFile.copy(addressListFilePath);
54 + }
55 +}
56 +
57 +Future<bool> backupWalletFilesExists(String name) async {
58 + final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
59 + final cacheFilePath = '$walletDirPath/$name';
60 + final keysFilePath = '$walletDirPath/$name.keys';
61 + final addressListFilePath = '$walletDirPath/$name.address.txt';
62 + final backupCacheFile = File(backupFileName(cacheFilePath));
63 + final backupKeysFile = File(backupFileName(keysFilePath));
64 + final backupAddressListFile = File(backupFileName(addressListFilePath));
65 +
66 + return backupCacheFile.existsSync()
67 + && backupKeysFile.existsSync()
68 + && backupAddressListFile.existsSync();
69 +}
70 +
71 +Future<void> removeCache(String name) async {
72 + final path = await pathForWallet(name: name, type: WalletType.monero);
73 + final cacheFile = File(path);
74 +
75 + if (cacheFile.existsSync()) {
76 + cacheFile.deleteSync();
77 + }
78 +}
79 +
80 +Future<void> restoreOrResetWalletFiles(String name) async {
81 + final backupsExists = await backupWalletFilesExists(name);
82 +
83 + if (backupsExists) {
84 + await restoreWalletFiles(name);
85 + }
86 +
87 + removeCache(name);
88 +}
\ No newline at end of file
cw_monero/lib/mymonero.dart new
+1689
@@ -0,0 +1,1689 @@
1 +const prefixLength = 3;
2 +
3 +String swapEndianBytes(String original) {
4 + if (original.length != 8) {
5 + return '';
6 + }
7 +
8 + return original[6] +
9 + original[7] +
10 + original[4] +
11 + original[5] +
12 + original[2] +
13 + original[3] +
14 + original[0] +
15 + original[1];
16 +}
17 +
18 +List<String> tructWords(List<String> wordSet) {
19 + final start = 0;
20 + final end = prefixLength;
21 +
22 + return wordSet.map((word) => word.substring(start, end)).toList();
23 +}
24 +
25 +String mnemonicDecode(String seed) {
26 + final n = englistWordSet.length;
27 + var out = '';
28 + var wlist = seed.split(' ');
29 + wlist.removeLast();
30 +
31 + for (var i = 0; i < wlist.length; i += 3) {
32 + final w1 =
33 + tructWords(englistWordSet).indexOf(wlist[i].substring(0, prefixLength));
34 + final w2 = tructWords(englistWordSet)
35 + .indexOf(wlist[i + 1].substring(0, prefixLength));
36 + final w3 = tructWords(englistWordSet)
37 + .indexOf(wlist[i + 2].substring(0, prefixLength));
38 +
39 + if (w1 == -1 || w2 == -1 || w3 == -1) {
40 + print("invalid word in mnemonic");
41 + return '';
42 + }
43 +
44 + final x = w1 + n * (((n - w1) + w2) % n) + n * n * (((n - w2) + w3) % n);
45 +
46 + if (x % n != w1) {
47 + print("Something went wrong when decoding your private key, please try again");
48 + return '';
49 + }
50 +
51 + final _res = '0000000' + x.toRadixString(16);
52 + final start = _res.length - 8;
53 + final end = _res.length;
54 + final res = _res.substring(start, end);
55 +
56 + out += swapEndianBytes(res);
57 + }
58 +
59 + return out;
60 +}
61 +
62 +final englistWordSet = [
63 + "abbey",
64 + "abducts",
65 + "ability",
66 + "ablaze",
67 + "abnormal",
68 + "abort",
69 + "abrasive",
70 + "absorb",
71 + "abyss",
72 + "academy",
73 + "aces",
74 + "aching",
75 + "acidic",
76 + "acoustic",
77 + "acquire",
78 + "across",
79 + "actress",
80 + "acumen",
81 + "adapt",
82 + "addicted",
83 + "adept",
84 + "adhesive",
85 + "adjust",
86 + "adopt",
87 + "adrenalin",
88 + "adult",
89 + "adventure",
90 + "aerial",
91 + "afar",
92 + "affair",
93 + "afield",
94 + "afloat",
95 + "afoot",
96 + "afraid",
97 + "after",
98 + "against",
99 + "agenda",
100 + "aggravate",
101 + "agile",
102 + "aglow",
103 + "agnostic",
104 + "agony",
105 + "agreed",
106 + "ahead",
107 + "aided",
108 + "ailments",
109 + "aimless",
110 + "airport",
111 + "aisle",
112 + "ajar",
113 + "akin",
114 + "alarms",
115 + "album",
116 + "alchemy",
117 + "alerts",
118 + "algebra",
119 + "alkaline",
120 + "alley",
121 + "almost",
122 + "aloof",
123 + "alpine",
124 + "already",
125 + "also",
126 + "altitude",
127 + "alumni",
128 + "always",
129 + "amaze",
130 + "ambush",
131 + "amended",
132 + "amidst",
133 + "ammo",
134 + "amnesty",
135 + "among",
136 + "amply",
137 + "amused",
138 + "anchor",
139 + "android",
140 + "anecdote",
141 + "angled",
142 + "ankle",
143 + "annoyed",
144 + "answers",
145 + "antics",
146 + "anvil",
147 + "anxiety",
148 + "anybody",
149 + "apart",
150 + "apex",
151 + "aphid",
152 + "aplomb",
153 + "apology",
154 + "apply",
155 + "apricot",
156 + "aptitude",
157 + "aquarium",
158 + "arbitrary",
159 + "archer",
160 + "ardent",
161 + "arena",
162 + "argue",
163 + "arises",
164 + "army",
165 + "around",
166 + "arrow",
167 + "arsenic",
168 + "artistic",
169 + "ascend",
170 + "ashtray",
171 + "aside",
172 + "asked",
173 + "asleep",
174 + "aspire",
175 + "assorted",
176 + "asylum",
177 + "athlete",
178 + "atlas",
179 + "atom",
180 + "atrium",
181 + "attire",
182 + "auburn",
183 + "auctions",
184 + "audio",
185 + "august",
186 + "aunt",
187 + "austere",
188 + "autumn",
189 + "avatar",
190 + "avidly",
191 + "avoid",
192 + "awakened",
193 + "awesome",
194 + "awful",
195 + "awkward",
196 + "awning",
197 + "awoken",
198 + "axes",
199 + "axis",
200 + "axle",
201 + "aztec",
202 + "azure",
203 + "baby",
204 + "bacon",
205 + "badge",
206 + "baffles",
207 + "bagpipe",
208 + "bailed",
209 + "bakery",
210 + "balding",
211 + "bamboo",
212 + "banjo",
213 + "baptism",
214 + "basin",
215 + "batch",
216 + "bawled",
217 + "bays",
218 + "because",
219 + "beer",
220 + "befit",
221 + "begun",
222 + "behind",
223 + "being",
224 + "below",
225 + "bemused",
226 + "benches",
227 + "berries",
228 + "bested",
229 + "betting",
230 + "bevel",
231 + "beware",
232 + "beyond",
233 + "bias",
234 + "bicycle",
235 + "bids",
236 + "bifocals",
237 + "biggest",
238 + "bikini",
239 + "bimonthly",
240 + "binocular",
241 + "biology",
242 + "biplane",
243 + "birth",
244 + "biscuit",
245 + "bite",
246 + "biweekly",
247 + "blender",
248 + "blip",
249 + "bluntly",
250 + "boat",
251 + "bobsled",
252 + "bodies",
253 + "bogeys",
254 + "boil",
255 + "boldly",
256 + "bomb",
257 + "border",
258 + "boss",
259 + "both",
260 + "bounced",
261 + "bovine",
262 + "bowling",
263 + "boxes",
264 + "boyfriend",
265 + "broken",
266 + "brunt",
267 + "bubble",
268 + "buckets",
269 + "budget",
270 + "buffet",
271 + "bugs",
272 + "building",
273 + "bulb",
274 + "bumper",
275 + "bunch",
276 + "business",
277 + "butter",
278 + "buying",
279 + "buzzer",
280 + "bygones",
281 + "byline",
282 + "bypass",
283 + "cabin",
284 + "cactus",
285 + "cadets",
286 + "cafe",
287 + "cage",
288 + "cajun",
289 + "cake",
290 + "calamity",
291 + "camp",
292 + "candy",
293 + "casket",
294 + "catch",
295 + "cause",
296 + "cavernous",
297 + "cease",
298 + "cedar",
299 + "ceiling",
300 + "cell",
301 + "cement",
302 + "cent",
303 + "certain",
304 + "chlorine",
305 + "chrome",
306 + "cider",
307 + "cigar",
308 + "cinema",
309 + "circle",
310 + "cistern",
311 + "citadel",
312 + "civilian",
313 + "claim",
314 + "click",
315 + "clue",
316 + "coal",
317 + "cobra",
318 + "cocoa",
319 + "code",
320 + "coexist",
321 + "coffee",
322 + "cogs",
323 + "cohesive",
324 + "coils",
325 + "colony",
326 + "comb",
327 + "cool",
328 + "copy",
329 + "corrode",
330 + "costume",
331 + "cottage",
332 + "cousin",
333 + "cowl",
334 + "criminal",
335 + "cube",
336 + "cucumber",
337 + "cuddled",
338 + "cuffs",
339 + "cuisine",
340 + "cunning",
341 + "cupcake",
342 + "custom",
343 + "cycling",
344 + "cylinder",
345 + "cynical",
346 + "dabbing",
347 + "dads",
348 + "daft",
349 + "dagger",
350 + "daily",
351 + "damp",
352 + "dangerous",
353 + "dapper",
354 + "darted",
355 + "dash",
356 + "dating",
357 + "dauntless",
358 + "dawn",
359 + "daytime",
360 + "dazed",
361 + "debut",
362 + "decay",
363 + "dedicated",
364 + "deepest",
365 + "deftly",
366 + "degrees",
367 + "dehydrate",
368 + "deity",
369 + "dejected",
370 + "delayed",
371 + "demonstrate",
372 + "dented",
373 + "deodorant",
374 + "depth",
375 + "desk",
376 + "devoid",
377 + "dewdrop",
378 + "dexterity",
379 + "dialect",
380 + "dice",
381 + "diet",
382 + "different",
383 + "digit",
384 + "dilute",
385 + "dime",
386 + "dinner",
387 + "diode",
388 + "diplomat",
389 + "directed",
390 + "distance",
391 + "ditch",
392 + "divers",
393 + "dizzy",
394 + "doctor",
395 + "dodge",
396 + "does",
397 + "dogs",
398 + "doing",
399 + "dolphin",
400 + "domestic",
401 + "donuts",
402 + "doorway",
403 + "dormant",
404 + "dosage",
405 + "dotted",
406 + "double",
407 + "dove",
408 + "down",
409 + "dozen",
410 + "dreams",
411 + "drinks",
412 + "drowning",
413 + "drunk",
414 + "drying",
415 + "dual",
416 + "dubbed",
417 + "duckling",
418 + "dude",
419 + "duets",
420 + "duke",
421 + "dullness",
422 + "dummy",
423 + "dunes",
424 + "duplex",
425 + "duration",
426 + "dusted",
427 + "duties",
428 + "dwarf",
429 + "dwelt",
430 + "dwindling",
431 + "dying",
432 + "dynamite",
433 + "dyslexic",
434 + "each",
435 + "eagle",
436 + "earth",
437 + "easy",
438 + "eating",
439 + "eavesdrop",
440 + "eccentric",
441 + "echo",
442 + "eclipse",
443 + "economics",
444 + "ecstatic",
445 + "eden",
446 + "edgy",
447 + "edited",
448 + "educated",
449 + "eels",
450 + "efficient",
451 + "eggs",
452 + "egotistic",
453 + "eight",
454 + "either",
455 + "eject",
456 + "elapse",
457 + "elbow",
458 + "eldest",
459 + "eleven",
460 + "elite",
461 + "elope",
462 + "else",
463 + "eluded",
464 + "emails",
465 + "ember",
466 + "emerge",
467 + "emit",
468 + "emotion",
469 + "empty",
470 + "emulate",
471 + "energy",
472 + "enforce",
473 + "enhanced",
474 + "enigma",
475 + "enjoy",
476 + "enlist",
477 + "enmity",
478 + "enough",
479 + "enraged",
480 + "ensign",
481 + "entrance",
482 + "envy",
483 + "epoxy",
484 + "equip",
485 + "erase",
486 + "erected",
487 + "erosion",
488 + "error",
489 + "eskimos",
490 + "espionage",
491 + "essential",
492 + "estate",
493 + "etched",
494 + "eternal",
495 + "ethics",
496 + "etiquette",
497 + "evaluate",
498 + "evenings",
499 + "evicted",
500 + "evolved",
501 + "examine",
502 + "excess",
503 + "exhale",
504 + "exit",
505 + "exotic",
506 + "exquisite",
507 + "extra",
508 + "exult",
509 + "fabrics",
510 + "factual",
511 + "fading",
512 + "fainted",
513 + "faked",
514 + "fall",
515 + "family",
516 + "fancy",
517 + "farming",
518 + "fatal",
519 + "faulty",
520 + "fawns",
521 + "faxed",
522 + "fazed",
523 + "feast",
524 + "february",
525 + "federal",
526 + "feel",
527 + "feline",
528 + "females",
529 + "fences",
530 + "ferry",
531 + "festival",
532 + "fetches",
533 + "fever",
534 + "fewest",
535 + "fiat",
536 + "fibula",
537 + "fictional",
538 + "fidget",
539 + "fierce",
540 + "fifteen",
541 + "fight",
542 + "films",
543 + "firm",
544 + "fishing",
545 + "fitting",
546 + "five",
547 + "fixate",
548 + "fizzle",
549 + "fleet",
550 + "flippant",
551 + "flying",
552 + "foamy",
553 + "focus",
554 + "foes",
555 + "foggy",
556 + "foiled",
557 + "folding",
558 + "fonts",
559 + "foolish",
560 + "fossil",
561 + "fountain",
562 + "fowls",
563 + "foxes",
564 + "foyer",
565 + "framed",
566 + "friendly",
567 + "frown",
568 + "fruit",
569 + "frying",
570 + "fudge",
571 + "fuel",
572 + "fugitive",
573 + "fully",
574 + "fuming",
575 + "fungal",
576 + "furnished",
577 + "fuselage",
578 + "future",
579 + "fuzzy",
580 + "gables",
581 + "gadget",
582 + "gags",
583 + "gained",
584 + "galaxy",
585 + "gambit",
586 + "gang",
587 + "gasp",
588 + "gather",
589 + "gauze",
590 + "gave",
591 + "gawk",
592 + "gaze",
593 + "gearbox",
594 + "gecko",
595 + "geek",
596 + "gels",
597 + "gemstone",
598 + "general",
599 + "geometry",
600 + "germs",
601 + "gesture",
602 + "getting",
603 + "geyser",
604 + "ghetto",
605 + "ghost",
606 + "giant",
607 + "giddy",
608 + "gifts",
609 + "gigantic",
610 + "gills",
611 + "gimmick",
612 + "ginger",
613 + "girth",
614 + "giving",
615 + "glass",
616 + "gleeful",
617 + "glide",
618 + "gnaw",
619 + "gnome",
620 + "goat",
621 + "goblet",
622 + "godfather",
623 + "goes",
624 + "goggles",
625 + "going",
626 + "goldfish",
627 + "gone",
628 + "goodbye",
629 + "gopher",
630 + "gorilla",
631 + "gossip",
632 + "gotten",
633 + "gourmet",
634 + "governing",
635 + "gown",
636 + "greater",
637 + "grunt",
638 + "guarded",
639 + "guest",
640 + "guide",
641 + "gulp",
642 + "gumball",
643 + "guru",
644 + "gusts",
645 + "gutter",
646 + "guys",
647 + "gymnast",
648 + "gypsy",
649 + "gyrate",
650 + "habitat",
651 + "hacksaw",
652 + "haggled",
653 + "hairy",
654 + "hamburger",
655 + "happens",
656 + "hashing",
657 + "hatchet",
658 + "haunted",
659 + "having",
660 + "hawk",
661 + "haystack",
662 + "hazard",
663 + "hectare",
664 + "hedgehog",
665 + "heels",
666 + "hefty",
667 + "height",
668 + "hemlock",
669 + "hence",
670 + "heron",
671 + "hesitate",
672 + "hexagon",
673 + "hickory",
674 + "hiding",
675 + "highway",
676 + "hijack",
677 + "hiker",
678 + "hills",
679 + "himself",
680 + "hinder",
681 + "hippo",
682 + "hire",
683 + "history",
684 + "hitched",
685 + "hive",
686 + "hoax",
687 + "hobby",
688 + "hockey",
689 + "hoisting",
690 + "hold",
691 + "honked",
692 + "hookup",
693 + "hope",
694 + "hornet",
695 + "hospital",
696 + "hotel",
697 + "hounded",
698 + "hover",
699 + "howls",
700 + "hubcaps",
701 + "huddle",
702 + "huge",
703 + "hull",
704 + "humid",
705 + "hunter",
706 + "hurried",
707 + "husband",
708 + "huts",
709 + "hybrid",
710 + "hydrogen",
711 + "hyper",
712 + "iceberg",
713 + "icing",
714 + "icon",
715 + "identity",
716 + "idiom",
717 + "idled",
718 + "idols",
719 + "igloo",
720 + "ignore",
721 + "iguana",
722 + "illness",
723 + "imagine",
724 + "imbalance",
725 + "imitate",
726 + "impel",
727 + "inactive",
728 + "inbound",
729 + "incur",
730 + "industrial",
731 + "inexact",
732 + "inflamed",
733 + "ingested",
734 + "initiate",
735 + "injury",
736 + "inkling",
737 + "inline",
738 + "inmate",
739 + "innocent",
740 + "inorganic",
741 + "input",
742 + "inquest",
743 + "inroads",
744 + "insult",
745 + "intended",
746 + "inundate",
747 + "invoke",
748 + "inwardly",
749 + "ionic",
750 + "irate",
751 + "iris",
752 + "irony",
753 + "irritate",
754 + "island",
755 + "isolated",
756 + "issued",
757 + "italics",
758 + "itches",
759 + "items",
760 + "itinerary",
761 + "itself",
762 + "ivory",
763 + "jabbed",
764 + "jackets",
765 + "jaded",
766 + "jagged",
767 + "jailed",
768 + "jamming",
769 + "january",
770 + "jargon",
771 + "jaunt",
772 + "javelin",
773 + "jaws",
774 + "jazz",
775 + "jeans",
776 + "jeers",
777 + "jellyfish",
778 + "jeopardy",
779 + "jerseys",
780 + "jester",
781 + "jetting",
782 + "jewels",
783 + "jigsaw",
784 + "jingle",
785 + "jittery",
786 + "jive",
787 + "jobs",
788 + "jockey",
789 + "jogger",
790 + "joining",
791 + "joking",
792 + "jolted",
793 + "jostle",
794 + "journal",
795 + "joyous",
796 + "jubilee",
797 + "judge",
798 + "juggled",
799 + "juicy",
800 + "jukebox",
801 + "july",
802 + "jump",
803 + "junk",
804 + "jury",
805 + "justice",
806 + "juvenile",
807 + "kangaroo",
808 + "karate",
809 + "keep",
810 + "kennel",
811 + "kept",
812 + "kernels",
813 + "kettle",
814 + "keyboard",
815 + "kickoff",
816 + "kidneys",
817 + "king",
818 + "kiosk",
819 + "kisses",
820 + "kitchens",
821 + "kiwi",
822 + "knapsack",
823 + "knee",
824 + "knife",
825 + "knowledge",
826 + "knuckle",
827 + "koala",
828 + "laboratory",
829 + "ladder",
830 + "lagoon",
831 + "lair",
832 + "lakes",
833 + "lamb",
834 + "language",
835 + "laptop",
836 + "large",
837 + "last",
838 + "later",
839 + "launching",
840 + "lava",
841 + "lawsuit",
842 + "layout",
843 + "lazy",
844 + "lectures",
845 + "ledge",
846 + "leech",
847 + "left",
848 + "legion",
849 + "leisure",
850 + "lemon",
851 + "lending",
852 + "leopard",
853 + "lesson",
854 + "lettuce",
855 + "lexicon",
856 + "liar",
857 + "library",
858 + "licks",
859 + "lids",
860 + "lied",
861 + "lifestyle",
862 + "light",
863 + "likewise",
864 + "lilac",
865 + "limits",
866 + "linen",
867 + "lion",
868 + "lipstick",
869 + "liquid",
870 + "listen",
871 + "lively",
872 + "loaded",
873 + "lobster",
874 + "locker",
875 + "lodge",
876 + "lofty",
877 + "logic",
878 + "loincloth",
879 + "long",
880 + "looking",
881 + "lopped",
882 + "lordship",
883 + "losing",
884 + "lottery",
885 + "loudly",
886 + "love",
887 + "lower",
888 + "loyal",
889 + "lucky",
890 + "luggage",
891 + "lukewarm",
892 + "lullaby",
893 + "lumber",
894 + "lunar",
895 + "lurk",
896 + "lush",
897 + "luxury",
898 + "lymph",
899 + "lynx",
900 + "lyrics",
901 + "macro",
902 + "madness",
903 + "magically",
904 + "mailed",
905 + "major",
906 + "makeup",
907 + "malady",
908 + "mammal",
909 + "maps",
910 + "masterful",
911 + "match",
912 + "maul",
913 + "maverick",
914 + "maximum",
915 + "mayor",
916 + "maze",
917 + "meant",
918 + "mechanic",
919 + "medicate",
920 + "meeting",
921 + "megabyte",
922 + "melting",
923 + "memoir",
924 + "menu",
925 + "merger",
926 + "mesh",
927 + "metro",
928 + "mews",
929 + "mice",
930 + "midst",
931 + "mighty",
932 + "mime",
933 + "mirror",
934 + "misery",
935 + "mittens",
936 + "mixture",
937 + "moat",
938 + "mobile",
939 + "mocked",
940 + "mohawk",
941 + "moisture",
942 + "molten",
943 + "moment",
944 + "money",
945 + "moon",
946 + "mops",
947 + "morsel",
948 + "mostly",
949 + "motherly",
950 + "mouth",
951 + "movement",
952 + "mowing",
953 + "much",
954 + "muddy",
955 + "muffin",
956 + "mugged",
957 + "mullet",
958 + "mumble",
959 + "mundane",
960 + "muppet",
961 + "mural",
962 + "musical",
963 + "muzzle",
964 + "myriad",
965 + "mystery",
966 + "myth",
967 + "nabbing",
968 + "nagged",
969 + "nail",
970 + "names",
971 + "nanny",
972 + "napkin",
973 + "narrate",
974 + "nasty",
975 + "natural",
976 + "nautical",
977 + "navy",
978 + "nearby",
979 + "necklace",
980 + "needed",
981 + "negative",
982 + "neither",
983 + "neon",
984 + "nephew",
985 + "nerves",
986 + "nestle",
987 + "network",
988 + "neutral",
989 + "never",
990 + "newt",
991 + "nexus",
992 + "nibs",
993 + "niche",
994 + "niece",
995 + "nifty",
996 + "nightly",
997 + "nimbly",
998 + "nineteen",
999 + "nirvana",
1000 + "nitrogen",
1001 + "nobody",
1002 + "nocturnal",
1003 + "nodes",
1004 + "noises",
1005 + "nomad",
1006 + "noodles",
1007 + "northern",
1008 + "nostril",
1009 + "noted",
1010 + "nouns",
1011 + "novelty",
1012 + "nowhere",
1013 + "nozzle",
1014 + "nuance",
1015 + "nucleus",
1016 + "nudged",
1017 + "nugget",
1018 + "nuisance",
1019 + "null",
1020 + "number",
1021 + "nuns",
1022 + "nurse",
1023 + "nutshell",
1024 + "nylon",
1025 + "oaks",
1026 + "oars",
1027 + "oasis",
1028 + "oatmeal",
1029 + "obedient",
1030 + "object",
1031 + "obliged",
1032 + "obnoxious",
1033 + "observant",
1034 + "obtains",
1035 + "obvious",
1036 + "occur",
1037 + "ocean",
1038 + "october",
1039 + "odds",
1040 + "odometer",
1041 + "offend",
1042 + "often",
1043 + "oilfield",
1044 + "ointment",
1045 + "okay",
1046 + "older",
1047 + "olive",
1048 + "olympics",
1049 + "omega",
1050 + "omission",
1051 + "omnibus",
1052 + "onboard",
1053 + "oncoming",
1054 + "oneself",
1055 + "ongoing",
1056 + "onion",
1057 + "online",
1058 + "onslaught",
1059 + "onto",
1060 + "onward",
1061 + "oozed",
1062 + "opacity",
1063 + "opened",
1064 + "opposite",
1065 + "optical",
1066 + "opus",
1067 + "orange",
1068 + "orbit",
1069 + "orchid",
1070 + "orders",
1071 + "organs",
1072 + "origin",
1073 + "ornament",
1074 + "orphans",
1075 + "oscar",
1076 + "ostrich",
1077 + "otherwise",
1078 + "otter",
1079 + "ouch",
1080 + "ought",
1081 + "ounce",
1082 + "ourselves",
1083 + "oust",
1084 + "outbreak",
1085 + "oval",
1086 + "oven",
1087 + "owed",
1088 + "owls",
1089 + "owner",
1090 + "oxidant",
1091 + "oxygen",
1092 + "oyster",
1093 + "ozone",
1094 + "pact",
1095 + "paddles",
1096 + "pager",
1097 + "pairing",
1098 + "palace",
1099 + "pamphlet",
1100 + "pancakes",
1101 + "paper",
1102 + "paradise",
1103 + "pastry",
1104 + "patio",
1105 + "pause",
1106 + "pavements",
1107 + "pawnshop",
1108 + "payment",
1109 + "peaches",
1110 + "pebbles",
1111 + "peculiar",
1112 + "pedantic",
1113 + "peeled",
1114 + "pegs",
1115 + "pelican",
1116 + "pencil",
1117 + "people",
1118 + "pepper",
1119 + "perfect",
1120 + "pests",
1121 + "petals",
1122 + "phase",
1123 + "pheasants",
1124 + "phone",
1125 + "phrases",
1126 + "physics",
1127 + "piano",
1128 + "picked",
1129 + "pierce",
1130 + "pigment",
1131 + "piloted",
1132 + "pimple",
1133 + "pinched",
1134 + "pioneer",
1135 + "pipeline",
1136 + "pirate",
1137 + "pistons",
1138 + "pitched",
1139 + "pivot",
1140 + "pixels",
1141 + "pizza",
1142 + "playful",
1143 + "pledge",
1144 + "pliers",
1145 + "plotting",
1146 + "plus",
1147 + "plywood",
1148 + "poaching",
1149 + "pockets",
1150 + "podcast",
1151 + "poetry",
1152 + "point",
1153 + "poker",
1154 + "polar",
1155 + "ponies",
1156 + "pool",
1157 + "popular",
1158 + "portents",
1159 + "possible",
1160 + "potato",
1161 + "pouch",
1162 + "poverty",
1163 + "powder",
1164 + "pram",
1165 + "present",
1166 + "pride",
1167 + "problems",
1168 + "pruned",
1169 + "prying",
1170 + "psychic",
1171 + "public",
1172 + "puck",
1173 + "puddle",
1174 + "puffin",
1175 + "pulp",
1176 + "pumpkins",
1177 + "punch",
1178 + "puppy",
1179 + "purged",
1180 + "push",
1181 + "putty",
1182 + "puzzled",
1183 + "pylons",
1184 + "pyramid",
1185 + "python",
1186 + "queen",
1187 + "quick",
1188 + "quote",
1189 + "rabbits",
1190 + "racetrack",
1191 + "radar",
1192 + "rafts",
1193 + "rage",
1194 + "railway",
1195 + "raking",
1196 + "rally",
1197 + "ramped",
1198 + "randomly",
1199 + "rapid",
1200 + "rarest",
1201 + "rash",
1202 + "rated",
1203 + "ravine",
1204 + "rays",
1205 + "razor",
1206 + "react",
1207 + "rebel",
1208 + "recipe",
1209 + "reduce",
1210 + "reef",
1211 + "refer",
1212 + "regular",
1213 + "reheat",
1214 + "reinvest",
1215 + "rejoices",
1216 + "rekindle",
1217 + "relic",
1218 + "remedy",
1219 + "renting",
1220 + "reorder",
1221 + "repent",
1222 + "request",
1223 + "reruns",
1224 + "rest",
1225 + "return",
1226 + "reunion",
1227 + "revamp",
1228 + "rewind",
1229 + "rhino",
1230 + "rhythm",
1231 + "ribbon",
1232 + "richly",
1233 + "ridges",
1234 + "rift",
1235 + "rigid",
1236 + "rims",
1237 + "ringing",
1238 + "riots",
1239 + "ripped",
1240 + "rising",
1241 + "ritual",
1242 + "river",
1243 + "roared",
1244 + "robot",
1245 + "rockets",
1246 + "rodent",
1247 + "rogue",
1248 + "roles",
1249 + "romance",
1250 + "roomy",
1251 + "roped",
1252 + "roster",
1253 + "rotate",
1254 + "rounded",
1255 + "rover",
1256 + "rowboat",
1257 + "royal",
1258 + "ruby",
1259 + "rudely",
1260 + "ruffled",
1261 + "rugged",
1262 + "ruined",
1263 + "ruling",
1264 + "rumble",
1265 + "runway",
1266 + "rural",
1267 + "rustled",
1268 + "ruthless",
1269 + "sabotage",
1270 + "sack",
1271 + "sadness",
1272 + "safety",
1273 + "saga",
1274 + "sailor",
1275 + "sake",
1276 + "salads",
1277 + "sample",
1278 + "sanity",
1279 + "sapling",
1280 + "sarcasm",
1281 + "sash",
1282 + "satin",
1283 + "saucepan",
1284 + "saved",
1285 + "sawmill",
1286 + "saxophone",
1287 + "sayings",
1288 + "scamper",
1289 + "scenic",
1290 + "school",
1291 + "science",
1292 + "scoop",
1293 + "scrub",
1294 + "scuba",
1295 + "seasons",
1296 + "second",
1297 + "sedan",
1298 + "seeded",
1299 + "segments",
1300 + "seismic",
1301 + "selfish",
1302 + "semifinal",
1303 + "sensible",
1304 + "september",
1305 + "sequence",
1306 + "serving",
1307 + "session",
1308 + "setup",
1309 + "seventh",
1310 + "sewage",
1311 + "shackles",
1312 + "shelter",
1313 + "shipped",
1314 + "shocking",
1315 + "shrugged",
1316 + "shuffled",
1317 + "shyness",
1318 + "siblings",
1319 + "sickness",
1320 + "sidekick",
1321 + "sieve",
1322 + "sifting",
1323 + "sighting",
1324 + "silk",
1325 + "simplest",
1326 + "sincerely",
1327 + "sipped",
1328 + "siren",
1329 + "situated",
1330 + "sixteen",
1331 + "sizes",
1332 + "skater",
1333 + "skew",
1334 + "skirting",
1335 + "skulls",
1336 + "skydive",
1337 + "slackens",
1338 + "sleepless",
1339 + "slid",
1340 + "slower",
1341 + "slug",
1342 + "smash",
1343 + "smelting",
1344 + "smidgen",
1345 + "smog",
1346 + "smuggled",
1347 + "snake",
1348 + "sneeze",
1349 + "sniff",
1350 + "snout",
1351 + "snug",
1352 + "soapy",
1353 + "sober",
1354 + "soccer",
1355 + "soda",
1356 + "software",
1357 + "soggy",
1358 + "soil",
1359 + "solved",
1360 + "somewhere",
1361 + "sonic",
1362 + "soothe",
1363 + "soprano",
1364 + "sorry",
1365 + "southern",
1366 + "sovereign",
1367 + "sowed",
1368 + "soya",
1369 + "space",
1370 + "speedy",
1371 + "sphere",
1372 + "spiders",
1373 + "splendid",
1374 + "spout",
1375 + "sprig",
1376 + "spud",
1377 + "spying",
1378 + "square",
1379 + "stacking",
1380 + "stellar",
1381 + "stick",
1382 + "stockpile",
1383 + "strained",
1384 + "stunning",
1385 + "stylishly",
1386 + "subtly",
1387 + "succeed",
1388 + "suddenly",
1389 + "suede",
1390 + "suffice",
1391 + "sugar",
1392 + "suitcase",
1393 + "sulking",
1394 + "summon",
1395 + "sunken",
1396 + "superior",
1397 + "surfer",
1398 + "sushi",
1399 + "suture",
1400 + "swagger",
1401 + "swept",
1402 + "swiftly",
1403 + "sword",
1404 + "swung",
1405 + "syllabus",
1406 + "symptoms",
1407 + "syndrome",
1408 + "syringe",
1409 + "system",
1410 + "taboo",
1411 + "tacit",
1412 + "tadpoles",
1413 + "tagged",
1414 + "tail",
1415 + "taken",
1416 + "talent",
1417 + "tamper",
1418 + "tanks",
1419 + "tapestry",
1420 + "tarnished",
1421 + "tasked",
1422 + "tattoo",
1423 + "taunts",
1424 + "tavern",
1425 + "tawny",
1426 + "taxi",
1427 + "teardrop",
1428 + "technical",
1429 + "tedious",
1430 + "teeming",
1431 + "tell",
1432 + "template",
1433 + "tender",
1434 + "tepid",
1435 + "tequila",
1436 + "terminal",
1437 + "testing",
1438 + "tether",
1439 + "textbook",
1440 + "thaw",
1441 + "theatrics",
1442 + "thirsty",
1443 + "thorn",
1444 + "threaten",
1445 + "thumbs",
1446 + "thwart",
1447 + "ticket",
1448 + "tidy",
1449 + "tiers",
1450 + "tiger",
1451 + "tilt",
1452 + "timber",
1453 + "tinted",
1454 + "tipsy",
1455 + "tirade",
1456 + "tissue",
1457 + "titans",
1458 + "toaster",
1459 + "tobacco",
1460 + "today",
1461 + "toenail",
1462 + "toffee",
1463 + "together",
1464 + "toilet",
1465 + "token",
1466 + "tolerant",
1467 + "tomorrow",
1468 + "tonic",
1469 + "toolbox",
1470 + "topic",
1471 + "torch",
1472 + "tossed",
1473 + "total",
1474 + "touchy",
1475 + "towel",
1476 + "toxic",
1477 + "toyed",
1478 + "trash",
1479 + "trendy",
1480 + "tribal",
1481 + "trolling",
1482 + "truth",
1483 + "trying",
1484 + "tsunami",
1485 + "tubes",
1486 + "tucks",
1487 + "tudor",
1488 + "tuesday",
1489 + "tufts",
1490 + "tugs",
1491 + "tuition",
1492 + "tulips",
1493 + "tumbling",
1494 + "tunnel",
1495 + "turnip",
1496 + "tusks",
1497 + "tutor",
1498 + "tuxedo",
1499 + "twang",
1500 + "tweezers",
1501 + "twice",
1502 + "twofold",
1503 + "tycoon",
1504 + "typist",
1505 + "tyrant",
1506 + "ugly",
1507 + "ulcers",
1508 + "ultimate",
1509 + "umbrella",
1510 + "umpire",
1511 + "unafraid",
1512 + "unbending",
1513 + "uncle",
1514 + "under",
1515 + "uneven",
1516 + "unfit",
1517 + "ungainly",
1518 + "unhappy",
1519 + "union",
1520 + "unjustly",
1521 + "unknown",
1522 + "unlikely",
1523 + "unmask",
1524 + "unnoticed",
1525 + "unopened",
1526 + "unplugs",
1527 + "unquoted",
1528 + "unrest",
1529 + "unsafe",
1530 + "until",
1531 + "unusual",
1532 + "unveil",
1533 + "unwind",
1534 + "unzip",
1535 + "upbeat",
1536 + "upcoming",
1537 + "update",
1538 + "upgrade",
1539 + "uphill",
1540 + "upkeep",
1541 + "upload",
1542 + "upon",
1543 + "upper",
1544 + "upright",
1545 + "upstairs",
1546 + "uptight",
1547 + "upwards",
1548 + "urban",
1549 + "urchins",
1550 + "urgent",
1551 + "usage",
1552 + "useful",
1553 + "usher",
1554 + "using",
1555 + "usual",
1556 + "utensils",
1557 + "utility",
1558 + "utmost",
1559 + "utopia",
1560 + "uttered",
1561 + "vacation",
1562 + "vague",
1563 + "vain",
1564 + "value",
1565 + "vampire",
1566 + "vane",
1567 + "vapidly",
1568 + "vary",
1569 + "vastness",
1570 + "vats",
1571 + "vaults",
1572 + "vector",
1573 + "veered",
1574 + "vegan",
1575 + "vehicle",
1576 + "vein",
1577 + "velvet",
1578 + "venomous",
1579 + "verification",
1580 + "vessel",
1581 + "veteran",
1582 + "vexed",
1583 + "vials",
1584 + "vibrate",
1585 + "victim",
1586 + "video",
1587 + "viewpoint",
1588 + "vigilant",
1589 + "viking",
1590 + "village",
1591 + "vinegar",
1592 + "violin",
1593 + "vipers",
1594 + "virtual",
1595 + "visited",
1596 + "vitals",
1597 + "vivid",
1598 + "vixen",
1599 + "vocal",
1600 + "vogue",
1601 + "voice",
1602 + "volcano",
1603 + "vortex",
1604 + "voted",
1605 + "voucher",
1606 + "vowels",
1607 + "voyage",
1608 + "vulture",
1609 + "wade",
1610 + "waffle",
1611 + "wagtail",
1612 + "waist",
1613 + "waking",
1614 + "wallets",
1615 + "wanted",
1616 + "warped",
1617 + "washing",
1618 + "water",
1619 + "waveform",
1620 + "waxing",
1621 + "wayside",
1622 + "weavers",
1623 + "website",
1624 + "wedge",
1625 + "weekday",
1626 + "weird",
1627 + "welders",
1628 + "went",
1629 + "wept",
1630 + "were",
1631 + "western",
1632 + "wetsuit",
1633 + "whale",
1634 + "when",
1635 + "whipped",
1636 + "whole",
1637 + "wickets",
1638 + "width",
1639 + "wield",
1640 + "wife",
1641 + "wiggle",
1642 + "wildly",
1643 + "winter",
1644 + "wipeout",
1645 + "wiring",
1646 + "wise",
1647 + "withdrawn",
1648 + "wives",
1649 + "wizard",
1650 + "wobbly",
1651 + "woes",
1652 + "woken",
1653 + "wolf",
1654 + "womanly",
1655 + "wonders",
1656 + "woozy",
1657 + "worry",
1658 + "wounded",
1659 + "woven",
1660 + "wrap",
1661 + "wrist",
1662 + "wrong",
1663 + "yacht",
1664 + "yahoo",
1665 + "yanks",
1666 + "yard",
1667 + "yawning",
1668 + "yearbook",
1669 + "yellow",
1670 + "yesterday",
1671 + "yeti",
1672 + "yields",
1673 + "yodel",
1674 + "yoga",
1675 + "younger",
1676 + "yoyo",
1677 + "zapped",
1678 + "zeal",
1679 + "zebra",
1680 + "zero",
1681 + "zesty",
1682 + "zigzags",
1683 + "zinger",
1684 + "zippers",
1685 + "zodiac",
1686 + "zombie",
1687 + "zones",
1688 + "zoom"
1689 +];
cw_monero/lib/pending_monero_transaction.dart new
+47
@@ -0,0 +1,47 @@
1 +import 'package:cw_monero/api/structs/pending_transaction.dart';
2 +import 'package:cw_monero/api/transaction_history.dart'
3 + as monero_transaction_history;
4 +import 'package:cw_core/crypto_currency.dart';
5 +import 'package:cake_wallet/core/amount_converter.dart';
6 +import 'package:cw_core/pending_transaction.dart';
7 +
8 +class DoubleSpendException implements Exception {
9 + DoubleSpendException();
10 +
11 + @override
12 + String toString() =>
13 + 'This transaction cannot be committed. This can be due to many reasons including the wallet not being synced, there is not enough XMR in your available balance, or previous transactions are not yet fully processed.';
14 +}
15 +
16 +class PendingMoneroTransaction with PendingTransaction {
17 + PendingMoneroTransaction(this.pendingTransactionDescription);
18 +
19 + final PendingTransactionDescription pendingTransactionDescription;
20 +
21 + @override
22 + String get id => pendingTransactionDescription.hash;
23 +
24 + @override
25 + String get amountFormatted => AmountConverter.amountIntToString(
26 + CryptoCurrency.xmr, pendingTransactionDescription.amount);
27 +
28 + @override
29 + String get feeFormatted => AmountConverter.amountIntToString(
30 + CryptoCurrency.xmr, pendingTransactionDescription.fee);
31 +
32 + @override
33 + Future<void> commit() async {
34 + try {
35 + monero_transaction_history.commitTransactionFromPointerAddress(
36 + address: pendingTransactionDescription.pointerAddress);
37 + } catch (e) {
38 + final message = e.toString();
39 +
40 + if (message.contains('Reason: double spend')) {
41 + throw DoubleSpendException();
42 + }
43 +
44 + rethrow;
45 + }
46 + }
47 +}
cw_monero/lib/subaddress.dart new
+22
@@ -0,0 +1,22 @@
1 +import 'package:cw_monero/api/structs/subaddress_row.dart';
2 +
3 +class Subaddress {
4 + Subaddress({this.id, this.address, this.label});
5 +
6 + Subaddress.fromMap(Map map)
7 + : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
8 + this.address = (map['address'] ?? '') as String,
9 + this.label = (map['label'] ?? '') as String;
10 +
11 + Subaddress.fromRow(SubaddressRow row)
12 + : this.id = row.getId(),
13 + this.address = row.getAddress(),
14 + this.label = row.getId() == 0 &&
15 + row.getLabel().toLowerCase() == 'Primary account'.toLowerCase()
16 + ? 'Primary address'
17 + : row.getLabel();
18 +
19 + final int id;
20 + final String address;
21 + final String label;
22 +}
lib/bitcoin/cw_bitcoin.dart new
+125
@@ -0,0 +1,125 @@
1 +part of 'bitcoin.dart';
2 +
3 +class CWBitcoin extends Bitcoin {
4 + @override
5 + TransactionPriority getMediumTransactionPriority() => BitcoinTransactionPriority.medium;
6 +
7 + @override
8 + WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({String name, String mnemonic, String password})
9 + => BitcoinRestoreWalletFromSeedCredentials(name: name, mnemonic: mnemonic, password: password);
10 +
11 + @override
12 + WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({String name, String password, String wif, WalletInfo walletInfo})
13 + => BitcoinRestoreWalletFromWIFCredentials(name: name, password: password, wif: wif, walletInfo: walletInfo);
14 +
15 + @override
16 + WalletCredentials createBitcoinNewWalletCredentials({String name, WalletInfo walletInfo})
17 + => BitcoinNewWalletCredentials(name: name, walletInfo: walletInfo);
18 +
19 + @override
20 + List<String> getWordList() => wordlist;
21 +
22 + @override
23 + Map<String, String> getWalletKeys(Object wallet) {
24 + final bitcoinWallet = wallet as BitcoinWallet;
25 + final keys = bitcoinWallet.keys;
26 +
27 + return <String, String>{
28 + 'wif': keys.wif,
29 + 'privateKey': keys.privateKey,
30 + 'publicKey': keys.publicKey
31 + };
32 + }
33 +
34 + @override
35 + List<TransactionPriority> getTransactionPriorities()
36 + => BitcoinTransactionPriority.all;
37 +
38 + @override
39 + TransactionPriority deserializeBitcoinTransactionPriority(int raw)
40 + => BitcoinTransactionPriority.deserialize(raw: raw);
41 +
42 + @override
43 + int getFeeRate(Object wallet, TransactionPriority priority) {
44 + final bitcoinWallet = wallet as BitcoinWallet;
45 + return bitcoinWallet.feeRate(priority);
46 + }
47 +
48 + @override
49 + Future<void> generateNewAddress(Object wallet) async {
50 + final bitcoinWallet = wallet as BitcoinWallet;
51 + await bitcoinWallet.walletAddresses.generateNewAddress();
52 + }
53 +
54 + @override
55 + Future<void> nextAddress(Object wallet) {
56 + final bitcoinWallet = wallet as BitcoinWallet;
57 + bitcoinWallet.walletAddresses.nextAddress();
58 + }
59 +
60 + @override
61 + Object createBitcoinTransactionCredentials(List<Output> outputs, TransactionPriority priority)
62 + => BitcoinTransactionCredentials(
63 + outputs.map((out) => OutputInfo(
64 + fiatAmount: out.fiatAmount,
65 + cryptoAmount: out.cryptoAmount,
66 + address: out.address,
67 + note: out.note,
68 + sendAll: out.sendAll,
69 + extractedAddress: out.extractedAddress,
70 + isParsedAddress: out.isParsedAddress,
71 + formattedCryptoAmount: out.formattedCryptoAmount))
72 + .toList(),
73 + priority as BitcoinTransactionPriority);
74 +
75 + @override
76 + List<String> getAddresses(Object wallet) {
77 + final bitcoinWallet = wallet as BitcoinWallet;
78 + return bitcoinWallet.walletAddresses.addresses
79 + .map((BitcoinAddressRecord addr) => addr.address)
80 + .toList();
81 + }
82 +
83 + @override
84 + String getAddress(Object wallet) {
85 + final bitcoinWallet = wallet as BitcoinWallet;
86 + return bitcoinWallet.walletAddresses.address;
87 + }
88 +
89 + @override
90 + String formatterBitcoinAmountToString({int amount})
91 + => bitcoinAmountToString(amount: amount);
92 +
93 + @override
94 + double formatterBitcoinAmountToDouble({int amount})
95 + => bitcoinAmountToDouble(amount: amount);
96 +
97 + @override
98 + int formatterStringDoubleToBitcoinAmount(String amount)
99 + => stringDoubleToBitcoinAmount(amount);
100 +
101 + @override
102 + List<Unspent> getUnspents(Object wallet) {
103 + final bitcoinWallet = wallet as BitcoinWallet;
104 + return bitcoinWallet.unspentCoins
105 + .map((BitcoinUnspent bitcoinUnspent) => Unspent(
106 + bitcoinUnspent.address.address,
107 + bitcoinUnspent.hash,
108 + bitcoinUnspent.value,
109 + bitcoinUnspent.vout))
110 + .toList();
111 + }
112 +
113 + void updateUnspents(Object wallet) async {
114 + final bitcoinWallet = wallet as BitcoinWallet;
115 + await bitcoinWallet.updateUnspent();
116 + }
117 +
118 + WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
119 + return BitcoinWalletService(walletInfoSource, unspentCoinSource);
120 + }
121 +
122 + WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
123 + return LitecoinWalletService(walletInfoSource, unspentCoinSource);
124 + }
125 +}
\ No newline at end of file
lib/core/sync_status_title.dart new
+36
@@ -0,0 +1,36 @@
1 +import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cw_core/sync_status.dart';
3 +
4 +String syncStatusTitle(SyncStatus syncStatus) {
5 + if (syncStatus is SyncingSyncStatus) {
6 + return S.current.Blocks_remaining('${syncStatus.blocksLeft}');
7 + }
8 +
9 + if (syncStatus is SyncedSyncStatus) {
10 + return S.current.sync_status_syncronized;
11 + }
12 +
13 + if (syncStatus is NotConnectedSyncStatus) {
14 + return S.current.sync_status_not_connected;
15 + }
16 +
17 + if (syncStatus is StartingSyncStatus) {
18 + return S.current.sync_status_starting_sync;
19 + }
20 +
21 + if (syncStatus is FailedSyncStatus) {
22 + return S.current.sync_status_failed_connect;
23 + }
24 +
25 + if (syncStatus is ConnectingSyncStatus) {
26 + return S.current.sync_status_connecting;
27 + }
28 +
29 + if (syncStatus is ConnectedSyncStatus) {
30 + return S.current.sync_status_connected;
31 + }
32 +
33 + if (syncStatus is LostConnectionSyncStatus) {
34 + return S.current.sync_status_failed_connect;
35 + }
36 +}
\ No newline at end of file
lib/monero/cw_monero.dart new
+286
@@ -0,0 +1,286 @@
1 +part of 'monero.dart';
2 +
3 +class CWMoneroAccountList extends MoneroAccountList {
4 + CWMoneroAccountList(this._wallet);
5 + Object _wallet;
6 +
7 + @override
8 + @computed
9 + ObservableList<Account> get accounts {
10 + final moneroWallet = _wallet as MoneroWallet;
11 + final accounts = moneroWallet.walletAddresses.accountList
12 + .accounts
13 + .map((acc) => Account(id: acc.id, label: acc.label))
14 + .toList();
15 + return ObservableList<Account>.of(accounts);
16 + }
17 +
18 + @override
19 + void update(Object wallet) {
20 + final moneroWallet = wallet as MoneroWallet;
21 + moneroWallet.walletAddresses.accountList.update();
22 + }
23 +
24 + @override
25 + void refresh(Object wallet) {
26 + final moneroWallet = wallet as MoneroWallet;
27 + moneroWallet.walletAddresses.accountList.refresh();
28 + }
29 +
30 + @override
31 + List<Account> getAll(Object wallet) {
32 + final moneroWallet = wallet as MoneroWallet;
33 + return moneroWallet.walletAddresses.accountList
34 + .getAll()
35 + .map((acc) => Account(id: acc.id, label: acc.label))
36 + .toList();
37 + }
38 +
39 + @override
40 + Future<void> addAccount(Object wallet, {String label}) async {
41 + final moneroWallet = wallet as MoneroWallet;
42 + moneroWallet.walletAddresses.accountList.addAccount(label: label);
43 + }
44 +
45 + @override
46 + Future<void> setLabelAccount(Object wallet, {int accountIndex, String label}) async {
47 + final moneroWallet = wallet as MoneroWallet;
48 + moneroWallet.walletAddresses.accountList
49 + .setLabelAccount(
50 + accountIndex: accountIndex,
51 + label: label);
52 + }
53 +}
54 +
55 +class CWMoneroSubaddressList extends MoneroSubaddressList {
56 + CWMoneroSubaddressList(this._wallet);
57 + Object _wallet;
58 +
59 + @override
60 + @computed
61 + ObservableList<Subaddress> get subaddresses {
62 + final moneroWallet = _wallet as MoneroWallet;
63 + final subAddresses = moneroWallet.walletAddresses.subaddressList
64 + .subaddresses
65 + .map((sub) => Subaddress(
66 + id: sub.id,
67 + address: sub.address,
68 + label: sub.label))
69 + .toList();
70 + return ObservableList<Subaddress>.of(subAddresses);
71 + }
72 +
73 + @override
74 + void update(Object wallet, {int accountIndex}) {
75 + final moneroWallet = wallet as MoneroWallet;
76 + moneroWallet.walletAddresses.subaddressList.update(accountIndex: accountIndex);
77 + }
78 +
79 + @override
80 + void refresh(Object wallet, {int accountIndex}) {
81 + final moneroWallet = wallet as MoneroWallet;
82 + moneroWallet.walletAddresses.subaddressList.refresh(accountIndex: accountIndex);
83 + }
84 +
85 + @override
86 + List<Subaddress> getAll(Object wallet) {
87 + final moneroWallet = wallet as MoneroWallet;
88 + return moneroWallet.walletAddresses
89 + .subaddressList
90 + .getAll()
91 + .map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
92 + .toList();
93 + }
94 +
95 + @override
96 + Future<void> addSubaddress(Object wallet, {int accountIndex, String label}) async {
97 + final moneroWallet = wallet as MoneroWallet;
98 + moneroWallet.walletAddresses.subaddressList
99 + .addSubaddress(
100 + accountIndex: accountIndex,
101 + label: label);
102 + }
103 +
104 + @override
105 + Future<void> setLabelSubaddress(Object wallet,
106 + {int accountIndex, int addressIndex, String label}) async {
107 + final moneroWallet = wallet as MoneroWallet;
108 + moneroWallet.walletAddresses.subaddressList
109 + .setLabelSubaddress(
110 + accountIndex: accountIndex,
111 + addressIndex: addressIndex,
112 + label: label);
113 + }
114 +}
115 +
116 +class CWMoneroWalletDetails extends MoneroWalletDetails {
117 + CWMoneroWalletDetails(this._wallet);
118 + Object _wallet;
119 +
120 + @computed
121 + Account get account {
122 + final moneroWallet = _wallet as MoneroWallet;
123 + final acc = moneroWallet.walletAddresses.account;
124 + return Account(id: acc.id, label: acc.label);
125 + }
126 +
127 + @computed
128 + MoneroBalance get balance {
129 + final moneroWallet = _wallet as MoneroWallet;
130 + final balance = moneroWallet.balance;
131 + return MoneroBalance(
132 + fullBalance: balance.fullBalance,
133 + unlockedBalance: balance.unlockedBalance);
134 + }
135 +}
136 +
137 +class CWMonero extends Monero {
138 + MoneroAccountList getAccountList(Object wallet) {
139 + return CWMoneroAccountList(wallet);
140 + }
141 +
142 + MoneroSubaddressList getSubaddressList(Object wallet) {
143 + return CWMoneroSubaddressList(wallet);
144 + }
145 +
146 + TransactionHistoryBase getTransactionHistory(Object wallet) {
147 + return MoneroTransactionHistory();
148 + }
149 +
150 + MoneroWalletDetails getMoneroWalletDetails(Object wallet) {
151 + return CWMoneroWalletDetails(wallet);
152 + }
153 +
154 + int getHeigthByDate({DateTime date}) {
155 + return getHeigthByDate(date: date);
156 + }
157 +
158 + TransactionPriority getDefaultTransactionPriority() {
159 + return MoneroTransactionPriority.slow;
160 + }
161 +
162 + TransactionPriority deserializeMoneroTransactionPriority({int raw}) {
163 + return MoneroTransactionPriority.deserialize(raw: raw);
164 + }
165 +
166 + List<TransactionPriority> getTransactionPriorities() {
167 + return MoneroTransactionPriority.all;
168 + }
169 +
170 + List<String> getMoneroWordList(String language) {
171 + switch (language.toLowerCase()) {
172 + case 'english':
173 + return EnglishMnemonics.words;
174 + case 'chinese (simplified)':
175 + return ChineseSimplifiedMnemonics.words;
176 + case 'dutch':
177 + return DutchMnemonics.words;
178 + case 'german':
179 + return GermanMnemonics.words;
180 + case 'japanese':
181 + return JapaneseMnemonics.words;
182 + case 'portuguese':
183 + return PortugueseMnemonics.words;
184 + case 'russian':
185 + return RussianMnemonics.words;
186 + case 'spanish':
187 + return SpanishMnemonics.words;
188 + default:
189 + return EnglishMnemonics.words;
190 + }
191 + }
192 +
193 + WalletCredentials createMoneroRestoreWalletFromKeysCredentials({
194 + String name,
195 + String spendKey,
196 + String viewKey,
197 + String address,
198 + String password,
199 + String language,
200 + int height}) {
201 + return MoneroRestoreWalletFromKeysCredentials(
202 + name: name,
203 + spendKey: spendKey,
204 + viewKey: viewKey,
205 + address: address,
206 + password: password,
207 + language: language,
208 + height: height);
209 + }
210 +
211 + WalletCredentials createMoneroRestoreWalletFromSeedCredentials({String name, String password, int height, String mnemonic}) {
212 + return MoneroRestoreWalletFromSeedCredentials(
213 + name: name,
214 + password: password,
215 + height: height,
216 + mnemonic: mnemonic);
217 + }
218 +
219 + WalletCredentials createMoneroNewWalletCredentials({String name, String password, String language}) {
220 + return MoneroNewWalletCredentials(
221 + name: name,
222 + password: password,
223 + language: language);
224 + }
225 +
226 + Map<String, String> getKeys(Object wallet) {
227 + final moneroWallet = wallet as MoneroWallet;
228 + final keys = moneroWallet.keys;
229 + return <String, String>{
230 + 'privateSpendKey': keys.privateSpendKey,
231 + 'privateViewKey': keys.privateViewKey,
232 + 'publicSpendKey': keys.publicSpendKey,
233 + 'publicViewKey': keys.publicViewKey};
234 + }
235 +
236 + Object createMoneroTransactionCreationCredentials({List<Output> outputs, TransactionPriority priority}) {
237 + return MoneroTransactionCreationCredentials(
238 + outputs: outputs.map((out) => OutputInfo(
239 + fiatAmount: out.fiatAmount,
240 + cryptoAmount: out.cryptoAmount,
241 + address: out.address,
242 + note: out.note,
243 + sendAll: out.sendAll,
244 + extractedAddress: out.extractedAddress,
245 + isParsedAddress: out.isParsedAddress,
246 + formattedCryptoAmount: out.formattedCryptoAmount))
247 + .toList(),
248 + priority: priority as MoneroTransactionPriority);
249 + }
250 +
251 + String formatterMoneroAmountToString({int amount}) {
252 + return moneroAmountToString(amount: amount);
253 + }
254 +
255 + double formatterMoneroAmountToDouble({int amount}) {
256 + return moneroAmountToDouble(amount: amount);
257 + }
258 +
259 + int formatterMoneroParseAmount({String amount}) {
260 + return moneroParseAmount(amount: amount);
261 + }
262 +
263 + Account getCurrentAccount(Object wallet) {
264 + final moneroWallet = wallet as MoneroWallet;
265 + final acc = moneroWallet.walletAddresses.account;
266 + return Account(id: acc.id, label: acc.label);
267 + }
268 +
269 + void setCurrentAccount(Object wallet, Account account) {
270 + final moneroWallet = wallet as MoneroWallet;
271 + moneroWallet.walletAddresses.account = monero_account.Account(id: account.id, label: account.label);
272 + }
273 +
274 + void onStartup() {
275 + monero_wallet_api.onStartup();
276 + }
277 +
278 + int getTransactionInfoAccountId(TransactionInfo tx) {
279 + final moneroTransactionInfo = tx as MoneroTransactionInfo;
280 + return moneroTransactionInfo.accountIndex;
281 + }
282 +
283 + WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource) {
284 + return MoneroWalletService(walletInfoSource);
285 + }
286 +}
pubspec_default.yaml new
+102
@@ -0,0 +1,102 @@
1 +name: cake_wallet
2 +description: Cake Wallet.
3 +version: 4.2.7+62
4 +
5 +environment:
6 + sdk: ">=2.7.0 <3.0.0"
7 +
8 +dependencies:
9 + flutter:
10 + sdk: flutter
11 + flutter_localizations:
12 + sdk: flutter
13 + flutter_cupertino_localizations: ^1.0.1
14 + intl: ^0.17.0
15 + url_launcher: ^6.0.3
16 + qr: ^2.0.0
17 + uuid: ^2.2.2
18 + shared_preferences: ^0.5.3+4
19 + flutter_secure_storage:
20 + git:
21 + url: https://github.com/cake-tech/flutter_secure_storage.git
22 + ref: cake
23 + version: 3.3.57
24 + provider: ^5.0.0
25 + rxdart: ^0.26.0
26 + yaml: ^2.1.16
27 + barcode_scan: any
28 + http: ^0.12.0+2
29 + path_provider: ^1.3.0
30 + mobx: ^1.2.1+2
31 + flutter_mobx: ^1.1.0+2
32 + flutter_slidable: ^0.5.3
33 + share: ^2.0.1
34 + esys_flutter_share: ^1.0.2
35 + date_range_picker: ^1.0.6
36 + dio: ^3.0.10
37 + hive: ^1.4.4+1
38 + hive_flutter: ^0.3.1
39 + local_auth: ^1.1.6
40 + package_info: ^2.0.0
41 + devicelocale: ^0.4.1
42 + auto_size_text: ^2.1.0
43 + dotted_border: ^1.0.5
44 + smooth_page_indicator: ^0.2.0
45 + webview_flutter: ^2.0.2
46 + flutter_spinkit: ^5.0.0
47 + uni_links: ^0.4.0
48 + lottie: ^0.7.0
49 + animate_do: ^2.0.0
50 + cupertino_icons: ^1.0.2
51 + encrypt: ^4.0.0
52 + crypto: ^2.1.5
53 + password: ^1.0.0
54 + basic_utils: ^2.0.3
55 + bitcoin_flutter:
56 + git:
57 + url: https://github.com/cake-tech/bitcoin_flutter.git
58 + ref: cake
59 + get_it: ^6.0.0
60 + connectivity: ^3.0.3
61 + keyboard_actions: ^3.3.0
62 + flushbar: ^1.10.4
63 + archive: ^2.0.13
64 + cryptography: ^1.4.0
65 + file_picker: ^3.0.0-nullsafety.2
66 + unorm_dart: ^0.2.0
67 + permission_handler: ^5.0.1+1
68 +
69 +dev_dependencies:
70 + flutter_test:
71 + sdk: flutter
72 + build_runner: ^1.10.3
73 + build_resolvers: ^1.3.10
74 + mobx_codegen: ^1.1.0+1
75 + hive_generator: ^0.8.1
76 + flutter_launcher_icons: ^0.8.1
77 + pedantic: ^1.8.0
78 +
79 +flutter_icons:
80 + image_path: "assets/images/app_logo.png"
81 + android: true
82 + ios: true
83 +
84 +flutter:
85 + uses-material-design: true
86 +
87 + assets:
88 + - assets/images/
89 + - assets/node_list.yml
90 + - assets/bitcoin_electrum_server_list.yml
91 + - assets/litecoin_electrum_server_list.yml
92 + - assets/text/
93 + - assets/faq/
94 + - assets/animation/
95 +
96 + fonts:
97 + - family: Lato
98 + fonts:
99 + - asset: assets/fonts/Lato-Regular.ttf
100 + - asset: assets/fonts/Lato-Medium.ttf
101 + - asset: assets/fonts/Lato-Semibold.ttf
102 + - asset: assets/fonts/Lato-Bold.ttf
tool/configure.dart new
+329
@@ -0,0 +1,329 @@
1 +import 'dart:convert';
2 +import 'dart:io';
3 +
4 +const bitcoinOutputPath = 'lib/bitcoin/bitcoin.dart';
5 +const moneroOutputPath = 'lib/monero/monero.dart';
6 +const walletTypesPath = 'lib/wallet_types.g.dart';
7 +const pubspecDefaultPath = 'pubspec_default.yaml';
8 +const pubspecOutputPath = 'pubspec.yaml';
9 +
10 +Future<void> main(List<String> args) async {
11 + const prefix = '--';
12 + final hasBitcoin = args.contains('${prefix}bitcoin');
13 + final hasMonero = args.contains('${prefix}monero');
14 + await generateBitcoin(hasBitcoin);
15 + await generateMonero(hasMonero);
16 + await generatePubspec(hasMonero: hasMonero, hasBitcoin: hasBitcoin);
17 + await generateWalletTypes(hasMonero: hasMonero, hasBitcoin: hasBitcoin);
18 +}
19 +
20 +Future<void> generateBitcoin(bool hasImplementation) async {
21 + final outputFile = File(bitcoinOutputPath);
22 + const bitcoinCommonHeaders = """
23 +import 'package:cw_core/wallet_credentials.dart';
24 +import 'package:cw_core/wallet_info.dart';
25 +import 'package:cw_core/transaction_priority.dart';
26 +import 'package:cw_core/output_info.dart';
27 +import 'package:cw_core/unspent_coins_info.dart';
28 +import 'package:cw_core/wallet_service.dart';
29 +import 'package:cake_wallet/view_model/send/output.dart';
30 +import 'package:hive/hive.dart';""";
31 + const bitcoinCWHeaders = """
32 +import 'package:cw_bitcoin/bitcoin_unspent.dart';
33 +import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
34 +import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
35 +import 'package:cw_bitcoin/bitcoin_wallet.dart';
36 +import 'package:cw_bitcoin/bitcoin_wallet_service.dart';
37 +import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
38 +import 'package:cw_bitcoin/bitcoin_amount_format.dart';
39 +import 'package:cw_bitcoin/bitcoin_address_record.dart';
40 +import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
41 +import 'package:cw_bitcoin/litecoin_wallet_service.dart';
42 +""";
43 + const bitcoinCwPart = "part 'cw_bitcoin.dart';";
44 + const bitcoinContent = """
45 +class Unspent {
46 + Unspent(this.address, this.hash, this.value, this.vout)
47 + : isSending = true,
48 + isFrozen = false,
49 + note = '';
50 +
51 + final String address;
52 + final String hash;
53 + final int value;
54 + final int vout;
55 +
56 + bool isSending;
57 + bool isFrozen;
58 + String note;
59 +
60 + bool get isP2wpkh => address.startsWith('bc') || address.startsWith('ltc');
61 +}
62 +
63 +abstract class Bitcoin {
64 + TransactionPriority getMediumTransactionPriority();
65 +
66 + WalletCredentials createBitcoinRestoreWalletFromSeedCredentials({String name, String mnemonic, String password});
67 + WalletCredentials createBitcoinRestoreWalletFromWIFCredentials({String name, String password, String wif, WalletInfo walletInfo});
68 + WalletCredentials createBitcoinNewWalletCredentials({String name, WalletInfo walletInfo});
69 + List<String> getWordList();
70 + Map<String, String> getWalletKeys(Object wallet);
71 + List<TransactionPriority> getTransactionPriorities();
72 + TransactionPriority deserializeBitcoinTransactionPriority(int raw);
73 + int getFeeRate(Object wallet, TransactionPriority priority);
74 + Future<void> generateNewAddress(Object wallet);
75 + Future<void> nextAddress(Object wallet);
76 + Object createBitcoinTransactionCredentials(List<Output> outputs, TransactionPriority priority);
77 +
78 + List<String> getAddresses(Object wallet);
79 + String getAddress(Object wallet);
80 +
81 + String formatterBitcoinAmountToString({int amount});
82 + double formatterBitcoinAmountToDouble({int amount});
83 + int formatterStringDoubleToBitcoinAmount(String amount);
84 +
85 + List<Unspent> getUnspents(Object wallet);
86 + void updateUnspents(Object wallet);
87 + WalletService createBitcoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
88 + WalletService createLitecoinWalletService(Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource);
89 +}
90 + """;
91 +
92 + const bitcoinEmptyDefinition = 'Bitcoin bitcoin;\n';
93 + const bitcoinCWDefinition = 'Bitcoin bitcoin = CWBitcoin();\n';
94 +
95 + final output = '$bitcoinCommonHeaders\n'
96 + + (hasImplementation ? '$bitcoinCWHeaders\n' : '\n')
97 + + (hasImplementation ? '$bitcoinCwPart\n\n' : '\n')
98 + + (hasImplementation ? bitcoinCWDefinition : bitcoinEmptyDefinition)
99 + + '\n'
100 + + bitcoinContent;
101 +
102 + if (outputFile.existsSync()) {
103 + await outputFile.delete();
104 + }
105 +
106 + await outputFile.writeAsString(output);
107 +}
108 +
109 +Future<void> generateMonero(bool hasImplementation) async {
110 + final outputFile = File(moneroOutputPath);
111 + const moneroCommonHeaders = """
112 +import 'package:mobx/mobx.dart';
113 +import 'package:flutter/foundation.dart';
114 +import 'package:cw_core/wallet_credentials.dart';
115 +import 'package:cw_core/wallet_info.dart';
116 +import 'package:cw_core/transaction_priority.dart';
117 +import 'package:cw_core/transaction_history.dart';
118 +import 'package:cw_core/transaction_info.dart';
119 +import 'package:cw_core/balance.dart';
120 +import 'package:cw_core/output_info.dart';
121 +import 'package:cake_wallet/view_model/send/output.dart';
122 +import 'package:cw_core/wallet_service.dart';
123 +import 'package:hive/hive.dart';""";
124 + const moneroCWHeaders = """
125 +import 'package:cw_monero/get_height_by_date.dart';
126 +import 'package:cw_monero/monero_amount_format.dart';
127 +import 'package:cw_monero/monero_transaction_priority.dart';
128 +import 'package:cw_monero/monero_wallet_service.dart';
129 +import 'package:cw_monero/monero_wallet.dart';
130 +import 'package:cw_monero/monero_transaction_info.dart';
131 +import 'package:cw_monero/monero_transaction_history.dart';
132 +import 'package:cw_monero/monero_transaction_creation_credentials.dart';
133 +import 'package:cw_monero/account.dart' as monero_account;
134 +import 'package:cw_monero/api/wallet.dart' as monero_wallet_api;
135 +import 'package:cw_monero/mnemonics/english.dart';
136 +import 'package:cw_monero/mnemonics/chinese_simplified.dart';
137 +import 'package:cw_monero/mnemonics/dutch.dart';
138 +import 'package:cw_monero/mnemonics/german.dart';
139 +import 'package:cw_monero/mnemonics/japanese.dart';
140 +import 'package:cw_monero/mnemonics/russian.dart';
141 +import 'package:cw_monero/mnemonics/spanish.dart';
142 +import 'package:cw_monero/mnemonics/portuguese.dart';
143 +""";
144 + const moneroCwPart = "part 'cw_monero.dart';";
145 + const moneroContent = """
146 +class Account {
147 + Account({this.id, this.label});
148 + final int id;
149 + final String label;
150 +}
151 +
152 +class Subaddress {
153 + Subaddress({this.id, this.accountId, this.label, this.address});
154 + final int id;
155 + final int accountId;
156 + final String label;
157 + final String address;
158 +}
159 +
160 +class MoneroBalance extends Balance {
161 + MoneroBalance({@required this.fullBalance, @required this.unlockedBalance})
162 + : formattedFullBalance = monero.formatterMoneroAmountToString(amount: fullBalance),
163 + formattedUnlockedBalance =
164 + monero.formatterMoneroAmountToString(amount: unlockedBalance),
165 + super(unlockedBalance, fullBalance);
166 +
167 + MoneroBalance.fromString(
168 + {@required this.formattedFullBalance,
169 + @required this.formattedUnlockedBalance})
170 + : fullBalance = monero.formatterMoneroParseAmount(amount: formattedFullBalance),
171 + unlockedBalance = monero.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
172 + super(monero.formatterMoneroParseAmount(amount: formattedUnlockedBalance),
173 + monero.formatterMoneroParseAmount(amount: formattedFullBalance));
174 +
175 + final int fullBalance;
176 + final int unlockedBalance;
177 + final String formattedFullBalance;
178 + final String formattedUnlockedBalance;
179 +
180 + @override
181 + String get formattedAvailableBalance => formattedUnlockedBalance;
182 +
183 + @override
184 + String get formattedAdditionalBalance => formattedFullBalance;
185 +}
186 +
187 +abstract class MoneroWalletDetails {
188 + @observable
189 + Account account;
190 +
191 + @observable
192 + MoneroBalance balance;
193 +}
194 +
195 +abstract class Monero {
196 + MoneroAccountList getAccountList(Object wallet);
197 +
198 + MoneroSubaddressList getSubaddressList(Object wallet);
199 +
200 + TransactionHistoryBase getTransactionHistory(Object wallet);
201 +
202 + MoneroWalletDetails getMoneroWalletDetails(Object wallet);
203 +
204 + int getHeigthByDate({DateTime date});
205 + TransactionPriority getDefaultTransactionPriority();
206 + TransactionPriority deserializeMoneroTransactionPriority({int raw});
207 + List<TransactionPriority> getTransactionPriorities();
208 + List<String> getMoneroWordList(String language);
209 +
210 + WalletCredentials createMoneroRestoreWalletFromKeysCredentials({
211 + String name,
212 + String spendKey,
213 + String viewKey,
214 + String address,
215 + String password,
216 + String language,
217 + int height});
218 + WalletCredentials createMoneroRestoreWalletFromSeedCredentials({String name, String password, int height, String mnemonic});
219 + WalletCredentials createMoneroNewWalletCredentials({String name, String password, String language});
220 + Map<String, String> getKeys(Object wallet);
221 + Object createMoneroTransactionCreationCredentials({List<Output> outputs, TransactionPriority priority});
222 + String formatterMoneroAmountToString({int amount});
223 + double formatterMoneroAmountToDouble({int amount});
224 + int formatterMoneroParseAmount({String amount});
225 + Account getCurrentAccount(Object wallet);
226 + void setCurrentAccount(Object wallet, Account account);
227 + void onStartup();
228 + int getTransactionInfoAccountId(TransactionInfo tx);
229 + WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource);
230 +}
231 +
232 +abstract class MoneroSubaddressList {
233 + ObservableList<Subaddress> get subaddresses;
234 + void update(Object wallet, {int accountIndex});
235 + void refresh(Object wallet, {int accountIndex});
236 + List<Subaddress> getAll(Object wallet);
237 + Future<void> addSubaddress(Object wallet, {int accountIndex, String label});
238 + Future<void> setLabelSubaddress(Object wallet,
239 + {int accountIndex, int addressIndex, String label});
240 +}
241 +
242 +abstract class MoneroAccountList {
243 + ObservableList<Account> get accounts;
244 + void update(Object wallet);
245 + void refresh(Object wallet);
246 + List<Account> getAll(Object wallet);
247 + Future<void> addAccount(Object wallet, {String label});
248 + Future<void> setLabelAccount(Object wallet, {int accountIndex, String label});
249 +}
250 + """;
251 +
252 + const moneroEmptyDefinition = 'Monero monero;\n';
253 + const moneroCWDefinition = 'Monero monero = CWMonero();\n';
254 +
255 + final output = '$moneroCommonHeaders\n'
256 + + (hasImplementation ? '$moneroCWHeaders\n' : '\n')
257 + + (hasImplementation ? '$moneroCwPart\n\n' : '\n')
258 + + (hasImplementation ? moneroCWDefinition : moneroEmptyDefinition)
259 + + '\n'
260 + + moneroContent;
261 +
262 + if (outputFile.existsSync()) {
263 + await outputFile.delete();
264 + }
265 +
266 + await outputFile.writeAsString(output);
267 +}
268 +
269 +Future<void> generatePubspec({bool hasMonero, bool hasBitcoin}) async {
270 + const cwCore = """
271 + cw_core:
272 + path: ./cw_core
273 + """;
274 + const cwMonero = """
275 + cw_monero:
276 + path: ./cw_monero
277 + """;
278 + const cwBitcoin = """
279 + cw_bitcoin:
280 + path: ./cw_bitcoin
281 + """;
282 + final inputFile = File(pubspecDefaultPath);
283 + final inputText = await inputFile.readAsString();
284 + final inputLines = inputText.split('\n');
285 + final dependenciesIndex = inputLines.indexWhere((line) => line.toLowerCase() == 'dependencies:');
286 + var output = cwCore;
287 +
288 + if (hasMonero) {
289 + output += '\n$cwMonero';
290 + }
291 +
292 + if (hasBitcoin) {
293 + output += '\n$cwBitcoin';
294 + }
295 +
296 + final outputLines = output.split('\n');
297 + inputLines.insertAll(dependenciesIndex + 1, outputLines);
298 + final outputContent = inputLines.join('\n');
299 + final outputFile = File(pubspecOutputPath);
300 +
301 + if (outputFile.existsSync()) {
302 + await outputFile.delete();
303 + }
304 +
305 + await outputFile.writeAsString(outputContent);
306 +}
307 +
308 +Future<void> generateWalletTypes({bool hasMonero, bool hasBitcoin}) async {
309 + final walletTypesFile = File(walletTypesPath);
310 +
311 + if (walletTypesFile.existsSync()) {
312 + await walletTypesFile.delete();
313 + }
314 +
315 + const outputHeader = "import 'package:cw_core/wallet_type.dart';";
316 + const outputDefinition = 'final availableWalletTypes = <WalletType>[';
317 + var outputContent = outputHeader + '\n\n' + outputDefinition + '\n';
318 +
319 + if (hasMonero) {
320 + outputContent += '\tWalletType.monero,\n';
321 + }
322 +
323 + if (hasBitcoin) {
324 + outputContent += '\tWalletType.bitcoin,\n\tWalletType.litecoin,\n';
325 + }
326 +
327 + outputContent += '];\n';
328 + await walletTypesFile.writeAsString(outputContent);
329 +}
\ No newline at end of file