dev
dart 418 lines 14.4 KB
Raw
1 import 'package:bitcoin_base/bitcoin_base.dart';
2 import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/core/validator.dart';
4 import 'package:cake_wallet/solana/solana.dart';
5 import 'package:cake_wallet/zano/zano.dart';
6 import 'package:cake_wallet/zcash/zcash_network_type.dart';
7 import 'package:cw_core/crypto_currency.dart';
8 import 'package:cw_core/erc20_token.dart';
9
10 const BEFORE_REGEX = '(^|\\s)';
11 const AFTER_REGEX = '(\$|\\s)';
12
13 class AddressValidator extends TextValidator {
14 AddressValidator({
15 required CryptoCurrency type,
16 bool isTestnet = false,
17 String? network,
18 }) : super(
19 errorMessage: S.current.error_text_address,
20 useAdditionalValidation: [CryptoCurrency.btc, CryptoCurrency.ltc].contains(type)
21 ? (String txt) {
22 final RegExp lightningInvoiceRegex = RegExp(
23 r'^(lightning:)?(lnbc|lntb|lnbs|lnbcrt|lnurl)[a-z0-9]+$',
24 caseSensitive: false);
25 if (lightningInvoiceRegex.hasMatch(txt)) return true;
26
27 return BitcoinAddressUtils.validateAddress(
28 address: txt,
29 network: type == CryptoCurrency.btc
30 ? isTestnet
31 ? BitcoinNetwork.testnet
32 : BitcoinNetwork.mainnet
33 : LitecoinNetwork.mainnet,
34 );
35 }
36 : type == CryptoCurrency.zano
37 ? zano?.validateAddress
38 : null,
39 pattern: getPattern(type, isTestnet: isTestnet, network: network),
40 length: getLength(type),
41 );
42
43 static const List<CryptoCurrency> reliableValidateCurrencies = [
44 CryptoCurrency.xmr,
45 CryptoCurrency.btc,
46 CryptoCurrency.ltc,
47 CryptoCurrency.bch,
48 CryptoCurrency.trx,
49 CryptoCurrency.nano,
50 CryptoCurrency.sol,
51 CryptoCurrency.zano,
52 CryptoCurrency.ada,
53 CryptoCurrency.xrp,
54 CryptoCurrency.xhv,
55 CryptoCurrency.zaddr,
56 CryptoCurrency.zec,
57 CryptoCurrency.dcr,
58 CryptoCurrency.rvn,
59 CryptoCurrency.near,
60 CryptoCurrency.rune,
61 CryptoCurrency.scrt,
62 CryptoCurrency.stx,
63 CryptoCurrency.kmd,
64 CryptoCurrency.doge,
65 CryptoCurrency.btcln,
66 ];
67
68 static String? getPattern(CryptoCurrency type, {bool isTestnet = false, String? network}) {
69 var pattern = "";
70 if (type is Erc20Token) {
71 pattern = '0x[0-9a-zA-Z]+';
72 }
73 switch (type) {
74 case CryptoCurrency.xmr:
75 pattern = '4[0-9a-zA-Z]{94}|8[0-9a-zA-Z]{94}|[0-9a-zA-Z]{106}';
76 case CryptoCurrency.ada:
77 pattern = '[0-9a-zA-Z]{59}|[0-9a-zA-Z]{92}|[0-9a-zA-Z]{104}'
78 '|[0-9a-zA-Z]{105}|addr1[0-9a-zA-Z]{98}';
79 case CryptoCurrency.btc:
80 if (isTestnet) {
81 pattern = '(^|\s)([mnL][a-km-zA-HJ-NP-Z1-9]{25,34})'
82 '|([23M][a-km-zA-HJ-NP-Z1-9]{25,34})'
83 '|(tb1q[ac-hj-np-z02-9]{25,39})'
84 '|(tb1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))'
85 '|(tb1q[ac-hj-np-z02-9]{40,80})'
86 '|(${silentPaymentAddressPatternTestnet})(\$|\s)';
87 } else {
88 pattern = '(^|\s)(1[a-km-zA-HJ-NP-Z1-9]{25,34})'
89 '|(3[a-km-zA-HJ-NP-Z1-9]{25,34})'
90 '|(bc1q[ac-hj-np-z02-9]{25,39})'
91 '|(bc1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))'
92 '|(bc1q[ac-hj-np-z02-9]{40,80})'
93 '|(lightning:)?(lnbc|lntb|lnbs|lnbcrt|lnurl)[a-z0-9]+'
94 '|(${silentPaymentAddressPatternMainnet})(\$|\s)';
95 }
96 case CryptoCurrency.ltc:
97 pattern = '(^|\s)(L[a-km-zA-HJ-NP-Z1-9]{25,34})'
98 '|([3M][a-km-zA-HJ-NP-Z1-9]{25,34})'
99 '|(ltc1q[ac-hj-np-z02-9]{25,39})'
100 '|(ltc1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))'
101 '|(ltc1q[ac-hj-np-z02-9]{40,80})'
102 '|(${MwebAddress.regex.pattern})(\$|\s)';
103 case CryptoCurrency.nano:
104 pattern = '[0-9a-zA-Z_]+';
105 case CryptoCurrency.banano:
106 pattern = '[0-9a-zA-Z_]+';
107 case CryptoCurrency.usdc:
108 case CryptoCurrency.usdcpoly:
109 case CryptoCurrency.usdtPoly:
110 case CryptoCurrency.usdcEPoly:
111 case CryptoCurrency.ape:
112 case CryptoCurrency.avaxc:
113 case CryptoCurrency.eth:
114 case CryptoCurrency.baseEth:
115 case CryptoCurrency.arbEth:
116 case CryptoCurrency.mana:
117 case CryptoCurrency.matic:
118 case CryptoCurrency.maticpoly:
119 case CryptoCurrency.mkr:
120 case CryptoCurrency.oxt:
121 case CryptoCurrency.paxg:
122 case CryptoCurrency.uni:
123 case CryptoCurrency.aave:
124 case CryptoCurrency.bat:
125 case CryptoCurrency.comp:
126 case CryptoCurrency.cro:
127 case CryptoCurrency.ens:
128 case CryptoCurrency.ftm:
129 case CryptoCurrency.frax:
130 case CryptoCurrency.gusd:
131 case CryptoCurrency.gtc:
132 case CryptoCurrency.grt:
133 case CryptoCurrency.ldo:
134 case CryptoCurrency.nexo:
135 case CryptoCurrency.pepe:
136 case CryptoCurrency.storj:
137 case CryptoCurrency.tusd:
138 case CryptoCurrency.wbtc:
139 case CryptoCurrency.weth:
140 case CryptoCurrency.zrx:
141 case CryptoCurrency.dydx:
142 case CryptoCurrency.steth:
143 case CryptoCurrency.shib:
144 pattern = '0x[0-9a-zA-Z]+';
145 case CryptoCurrency.xrp:
146 pattern = '[0-9a-zA-Z]{34}|[0-9a-zA-Z]{33}|X[0-9a-zA-Z]{46}';
147 case CryptoCurrency.xhv:
148 pattern = 'hvx|hvi|hvs[0-9a-zA-Z]+';
149 case CryptoCurrency.xag:
150 case CryptoCurrency.xau:
151 case CryptoCurrency.xaud:
152 case CryptoCurrency.xbtc:
153 case CryptoCurrency.xcad:
154 case CryptoCurrency.xchf:
155 case CryptoCurrency.xcny:
156 case CryptoCurrency.xeur:
157 case CryptoCurrency.xgbp:
158 case CryptoCurrency.xjpy:
159 case CryptoCurrency.xnok:
160 case CryptoCurrency.xnzd:
161 case CryptoCurrency.xusd:
162 case CryptoCurrency.usdt:
163 case CryptoCurrency.usdterc20:
164 case CryptoCurrency.xlm:
165 case CryptoCurrency.trx:
166 case CryptoCurrency.dai:
167 case CryptoCurrency.dash:
168 case CryptoCurrency.eos:
169 case CryptoCurrency.wow:
170 pattern = '[0-9a-zA-Z]+';
171 case CryptoCurrency.bch:
172 pattern = '(?:bitcoincash:)?(q|p)[0-9a-zA-Z]{41}'
173 '|[13][a-km-zA-HJ-NP-Z1-9]{25,34}';
174 case CryptoCurrency.hbar:
175 pattern = '[0-9a-zA-Z.]+';
176 case CryptoCurrency.zec:
177 if (ZcashNetworkType.isDevNetwork(network)) {
178 return null;
179 }
180 pattern = "(?:$zcashAddressPattern|zxviews[a-z0-9]{278})";
181 case CryptoCurrency.dcr:
182 pattern = '(D|T|S)[ksecS]([0-9a-zA-Z])+';
183 case CryptoCurrency.rvn:
184 pattern = '[Rr]([1-9a-km-zA-HJ-NP-Z]){33}';
185 case CryptoCurrency.near:
186 pattern = '[0-9a-f]{64}';
187 case CryptoCurrency.rune:
188 pattern = 'thor1[0-9a-z]{38}';
189 case CryptoCurrency.scrt:
190 pattern = 'secret1[0-9a-z]{38}';
191 case CryptoCurrency.stx:
192 pattern = 'S[MP][0-9a-zA-Z]+';
193 case CryptoCurrency.kmd:
194 pattern = 'R[0-9a-zA-Z]{33}';
195 case CryptoCurrency.pivx:
196 pattern = 'D([1-9a-km-zA-HJ-NP-Z]){33}';
197 case CryptoCurrency.btcln:
198 pattern =
199 r'(lightning:)?(lnbc|lntb|lnbs|lnbcrt|lnurl|LNBC|LNTB|LNBS|LNBCRT|LNURL)[a-zA-Z0-9]+';
200 case CryptoCurrency.zano:
201 pattern = r'([1-9A-HJ-NP-Za-km-z]{90,200})|(@[\w\d.-]+)';
202 case CryptoCurrency.doge:
203 pattern = r'^D[a-km-zA-HJ-NP-Z1-9]{25,34}';
204 default:
205 return '';
206 }
207
208 return '$BEFORE_REGEX($pattern)$AFTER_REGEX';
209 }
210
211 static List<int>? getLength(CryptoCurrency type) {
212 if (type is Erc20Token) {
213 return [42];
214 }
215
216 if (solana != null) {
217 final length = solana!.getValidationLength(type);
218 if (length != null) return length;
219 }
220
221 switch (type) {
222 case CryptoCurrency.xmr:
223 case CryptoCurrency.wow:
224 return null;
225 case CryptoCurrency.ada:
226 return null;
227 case CryptoCurrency.btc:
228 return null;
229 case CryptoCurrency.ltc:
230 return null;
231 case CryptoCurrency.dash:
232 return [34];
233 case CryptoCurrency.eos:
234 return [42];
235 case CryptoCurrency.eth:
236 case CryptoCurrency.usdcpoly:
237 case CryptoCurrency.usdtPoly:
238 case CryptoCurrency.usdcEPoly:
239 case CryptoCurrency.mana:
240 case CryptoCurrency.matic:
241 case CryptoCurrency.maticpoly:
242 case CryptoCurrency.mkr:
243 case CryptoCurrency.oxt:
244 case CryptoCurrency.paxg:
245 case CryptoCurrency.uni:
246 case CryptoCurrency.dai:
247 case CryptoCurrency.ape:
248 case CryptoCurrency.usdc:
249 case CryptoCurrency.usdterc20:
250 case CryptoCurrency.aave:
251 case CryptoCurrency.bat:
252 case CryptoCurrency.comp:
253 case CryptoCurrency.cro:
254 case CryptoCurrency.ens:
255 case CryptoCurrency.ftm:
256 case CryptoCurrency.frax:
257 case CryptoCurrency.gusd:
258 case CryptoCurrency.gtc:
259 case CryptoCurrency.grt:
260 case CryptoCurrency.ldo:
261 case CryptoCurrency.nexo:
262 case CryptoCurrency.pepe:
263 case CryptoCurrency.storj:
264 case CryptoCurrency.tusd:
265 case CryptoCurrency.wbtc:
266 case CryptoCurrency.weth:
267 case CryptoCurrency.zrx:
268 case CryptoCurrency.dydx:
269 case CryptoCurrency.steth:
270 case CryptoCurrency.shib:
271 case CryptoCurrency.avaxc:
272 case CryptoCurrency.baseEth:
273 case CryptoCurrency.arbEth:
274 return [42];
275 case CryptoCurrency.bch:
276 return [42, 54, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35];
277 case CryptoCurrency.bnb:
278 return [42];
279 case CryptoCurrency.nano:
280 return [64, 65];
281 case CryptoCurrency.banano:
282 return [64, 65];
283 case CryptoCurrency.sc:
284 return [76];
285 case CryptoCurrency.sol:
286 case CryptoCurrency.usdtSol:
287 case CryptoCurrency.usdcsol:
288 return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44];
289 case CryptoCurrency.trx:
290 return [34];
291 case CryptoCurrency.usdt:
292 return [34];
293 case CryptoCurrency.usdttrc20:
294 return [34];
295 case CryptoCurrency.xlm:
296 return [56];
297 case CryptoCurrency.xrp:
298 return null;
299 case CryptoCurrency.xhv:
300 case CryptoCurrency.xag:
301 case CryptoCurrency.xau:
302 case CryptoCurrency.xaud:
303 case CryptoCurrency.xbtc:
304 case CryptoCurrency.xcad:
305 case CryptoCurrency.xchf:
306 case CryptoCurrency.xcny:
307 case CryptoCurrency.xeur:
308 case CryptoCurrency.xgbp:
309 case CryptoCurrency.xjpy:
310 case CryptoCurrency.xnok:
311 case CryptoCurrency.xnzd:
312 case CryptoCurrency.xusd:
313 return [98, 99, 106];
314 case CryptoCurrency.btt:
315 case CryptoCurrency.bttc:
316 case CryptoCurrency.doge:
317 case CryptoCurrency.firo:
318 return [34];
319 case CryptoCurrency.hbar:
320 return [4, 5, 6, 7, 8, 9, 10, 11];
321 case CryptoCurrency.xvg:
322 return [34];
323 case CryptoCurrency.zen:
324 return [35];
325 case CryptoCurrency.zec:
326 return null;
327 case CryptoCurrency.kmd:
328 case CryptoCurrency.pivx:
329 case CryptoCurrency.rvn:
330 return [34];
331 case CryptoCurrency.dcr:
332 return [35];
333 case CryptoCurrency.stx:
334 return [40, 41, 42];
335 case CryptoCurrency.rune:
336 return [43];
337 case CryptoCurrency.scrt:
338 return [45];
339 case CryptoCurrency.near:
340 return [64];
341 case CryptoCurrency.btcln:
342 case CryptoCurrency.kaspa:
343 case CryptoCurrency.zano:
344 default:
345 return null;
346 }
347 }
348
349 static String get silentPaymentAddressPatternMainnet => 'sp1[0-9a-zA-Z]{113}';
350 static String get silentPaymentAddressPatternTestnet => '(tsp|sprt)1[0-9a-zA-Z]{113}';
351 static String get mWebAddressPattern => MwebAddress.regex.pattern;
352 static String get zcashAddressPattern =>
353 "t1[0-9A-Za-z]{33}|t3[0-9A-Za-z]{33}|zs[a-z0-9]{76}|u1[a-z0-9]{1,300}";
354
355 static const String bolt11InvoiceMatcher = r'^(lightning:)?(lnbc|lntb|lnbs|lnbcrt)[a-z0-9]+$';
356 static const String bolt12OfferMatcher = r'^(lightning:)?(lno1)[a-z0-9]+$';
357 static const String lnurlMatcher = r'^(lightning:)?(lnurl)[a-z0-9]+$';
358
359 // NOTE: not needed to check for network here as it's a general address catcher, validation is separate
360 static String? getAddressFromStringPattern(CryptoCurrency type) {
361 String? pattern = null;
362
363 switch (type) {
364 case CryptoCurrency.xmr:
365 pattern = '(4[0-9a-zA-Z]{94})'
366 '|(8[0-9a-zA-Z]{94})'
367 '|([0-9a-zA-Z]{106})';
368 case CryptoCurrency.wow:
369 pattern = '(W[0-9a-zA-Z]{94})'
370 '|(W[0-9a-zA-Z]{94})'
371 '|(W[0-9a-zA-Z]{96})'
372 '|([0-9a-zA-Z]{106})';
373 case CryptoCurrency.btc:
374 pattern =
375 '${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${P2wpkhAddress.regex.pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}';
376 case CryptoCurrency.ltc:
377 pattern = '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
378 '|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
379 '|([^0-9a-zA-Z]|^)ltc[a-zA-Z0-9]{26,45}([^0-9a-zA-Z]|\$)'
380 '|([^0-9a-zA-Z]|^)((ltc|t)mweb1q[ac-hj-np-z02-9]{90,120})([^0-9a-zA-Z]|\$)';
381 case CryptoCurrency.eth:
382 case CryptoCurrency.maticpoly:
383 case CryptoCurrency.baseEth:
384 case CryptoCurrency.arbEth:
385 case CryptoCurrency.arb:
386 pattern = '0x[0-9a-zA-Z]+';
387 case CryptoCurrency.nano:
388 pattern = 'nano_[0-9a-zA-Z]{60}';
389 case CryptoCurrency.banano:
390 pattern = 'ban_[0-9a-zA-Z]{60}';
391 case CryptoCurrency.bch:
392 pattern = '(bitcoincash:)?q[0-9a-zA-Z]{41,42}';
393 case CryptoCurrency.sol:
394 pattern = '[1-9A-HJ-NP-Za-km-z]+';
395 case CryptoCurrency.trx:
396 pattern = '(T|t)[1-9A-HJ-NP-Za-km-z]{33}';
397 case CryptoCurrency.zano:
398 pattern = '([1-9A-HJ-NP-Za-km-z]{90,200})|(@[\w\d.-]+)';
399 case CryptoCurrency.zec:
400 pattern = "(?:$zcashAddressPattern|zxviews[a-z0-9]{278})";
401 default:
402 if (type.tag == CryptoCurrency.eth.title) {
403 pattern = '0x[0-9a-zA-Z]+';
404 }
405 if (type.tag == CryptoCurrency.maticpoly.tag) {
406 pattern = '0x[0-9a-zA-Z]+';
407 }
408 if (type.tag == CryptoCurrency.sol.title) {
409 pattern = '[1-9A-HJ-NP-Za-km-z]{43,44}';
410 }
411 if (type.tag == CryptoCurrency.trx.title) {
412 pattern = '(T|t)[1-9A-HJ-NP-Za-km-z]{33}';
413 }
414 }
415
416 return pattern != null ? "($pattern)" : null;
417 }
418 }