mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
Cw 1161 add user added tokens to swap currencies (#2455)
* Add user ETH and SOL tokens to exchange currency lists * Update default_spl_tokens.dart * fix solana token icon issue * add user currency to Trade and update usage * add support for user Tron and Polygon tokens in exchange * removing the providersForCurrentPair method and related logic * Improve currency search * prevent crash in EVM wallets for unknown token symbols * Improve asset lookup in XOSwap provider * revert token enabled state for tron solana * Move SPL and Tron token classes to cw_core * fix updating trades for user tokens * Improve token matching by including tag comparison * safer currency parsing across all exchange providers * Update edit_token_page.dart
This commit is contained in:
@@ -300,6 +300,46 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||
return CryptoCurrency._fullNameCurrencyMap[name.split("(").first.trim().toLowerCase()]!;
|
||||
}
|
||||
|
||||
static CryptoCurrency? safeParseCurrencyFromString(String? raw, {CryptoCurrency? walletCurrency}) {
|
||||
if (raw == null || raw.isEmpty) return null;
|
||||
|
||||
try {
|
||||
return CryptoCurrency.fromString(raw, walletCurrency: walletCurrency);
|
||||
} catch (_) {}
|
||||
|
||||
// try cleaned (keep only A–Z/0–9)
|
||||
final cleaned = raw.trim().toUpperCase().replaceAll(RegExp(r'[^A-Z0-9]'), '');
|
||||
try {
|
||||
return CryptoCurrency.fromString(cleaned, walletCurrency: walletCurrency);
|
||||
} catch (_) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
CryptoCurrency copyWith({
|
||||
String? title,
|
||||
int? raw,
|
||||
String? name,
|
||||
String? fullName,
|
||||
String? iconPath,
|
||||
String? tag,
|
||||
int? decimals,
|
||||
bool? enabled,
|
||||
bool? isPotentialScam,
|
||||
}) {
|
||||
return CryptoCurrency(
|
||||
title: title ?? this.title,
|
||||
raw: raw ?? this.raw,
|
||||
name: name ?? this.name,
|
||||
fullName: fullName ?? this.fullName,
|
||||
iconPath: iconPath ?? this.iconPath,
|
||||
tag: tag ?? this.tag,
|
||||
decimals: decimals ?? this.decimals,
|
||||
enabled: enabled ?? this.enabled,
|
||||
isPotentialScam: isPotentialScam ?? this.isPotentialScam,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
}
|
||||
|
||||
@@ -248,10 +248,17 @@ abstract class EVMChainWalletBase
|
||||
// For fixing wrongly classified tokens
|
||||
if (!isPotentialScam && token.isPotentialScam) {
|
||||
token.isPotentialScam = false;
|
||||
final iconPath = CryptoCurrency.all
|
||||
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
|
||||
.iconPath;
|
||||
token.iconPath = iconPath;
|
||||
|
||||
if (token.iconPath == null || token.iconPath!.isEmpty) {
|
||||
try {
|
||||
token.iconPath = CryptoCurrency.all
|
||||
.firstWhere((e) => e.title.toUpperCase() == token.symbol.toUpperCase())
|
||||
.iconPath;
|
||||
} catch (_) {
|
||||
printV("Token ${token.symbol} does not have an icon path");
|
||||
}
|
||||
}
|
||||
|
||||
await token.save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_solana/spl_token.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
|
||||
class DefaultSPLTokens {
|
||||
final List<SPLToken> _defaultTokens = [
|
||||
@@ -99,6 +99,448 @@ class DefaultSPLTokens {
|
||||
iconPath: 'assets/images/avdo_icon.png',
|
||||
enabled: false,
|
||||
),
|
||||
SPLToken(
|
||||
name: 'Abbott xStock',
|
||||
symbol: 'ABTx',
|
||||
mintAddress: 'XsHtf5RpxsQ7jeJ9ivNewouZKJHbPxhPoEy6yYvULr7',
|
||||
decimal: 8,
|
||||
mint: 'abtx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'AbbVie xStock',
|
||||
symbol: 'ABBVx',
|
||||
mintAddress: 'XswbinNKyPmzTa5CskMbCPvMW6G5CMnZXZEeQSSQoie',
|
||||
decimal: 8,
|
||||
mint: 'abbvx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Accenture xStock',
|
||||
symbol: 'ACNx',
|
||||
mintAddress: 'Xs5UJzmCRQ8DWZjskExdSQDnbE6iLkRu2jjrRAB1JSU',
|
||||
decimal: 8,
|
||||
mint: 'acnx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Alphabet xStock',
|
||||
symbol: 'GOOGLx',
|
||||
mintAddress: 'XsCPL9dNWBMvFtTmwcCA5v3xWPSMEBCszbQdiLLq6aN',
|
||||
decimal: 8,
|
||||
mint: 'googlx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Amazon xStock',
|
||||
symbol: 'AMZNx',
|
||||
mintAddress: 'Xs3eBt7uRfJX8QUs4suhyU8p2M6DoUDrJyWBa8LLZsg',
|
||||
decimal: 8,
|
||||
mint: 'amznx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Amber xStock',
|
||||
symbol: 'AMBRx',
|
||||
mintAddress: 'XsaQTCgebC2KPbf27KUhdv5JFvHhQ4GDAPURwrEhAzb',
|
||||
decimal: 8,
|
||||
mint: 'ambrx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Apple xStock',
|
||||
symbol: 'AAPLx',
|
||||
mintAddress: 'XsbEhLAtcf6HdfpFZ5xEMdqW8nfAvcsP5bdudRLJzJp',
|
||||
decimal: 8,
|
||||
mint: 'aaplx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'AppLovin xStock',
|
||||
symbol: 'APPx',
|
||||
mintAddress: 'XsPdAVBi8Zc1xvv53k4JcMrQaEDTgkGqKYeh7AYgPHV',
|
||||
decimal: 8,
|
||||
mint: 'appx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'AstraZeneca xStock',
|
||||
symbol: 'AZNx',
|
||||
mintAddress: 'Xs3ZFkPYT2BN7qBMqf1j1bfTeTm1rFzEFSsQ1z3wAKU',
|
||||
decimal: 8,
|
||||
mint: 'aznx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Bank of America xStock',
|
||||
symbol: 'BACx',
|
||||
mintAddress: 'XswsQk4duEQmCbGzfqUUWYmi7pV7xpJ9eEmLHXCaEQP',
|
||||
decimal: 8,
|
||||
mint: 'bacx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Berkshire Hathaway xStock',
|
||||
symbol: 'BRK.Bx',
|
||||
mintAddress: 'Xs6B6zawENwAbWVi7w92rjazLuAr5Az59qgWKcNb45x',
|
||||
decimal: 8,
|
||||
mint: 'brkbx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Broadcom xStock',
|
||||
symbol: 'AVGOx',
|
||||
mintAddress: 'XsgSaSvNSqLTtFuyWPBhK9196Xb9Bbdyjj4fH3cPJGo',
|
||||
decimal: 8,
|
||||
mint: 'avgox',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Chevron xStock',
|
||||
symbol: 'CVXx',
|
||||
mintAddress: 'XsNNMt7WTNA2sV3jrb1NNfNgapxRF5i4i6GcnTRRHts',
|
||||
decimal: 8,
|
||||
mint: 'cvxx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Circle xStock',
|
||||
symbol: 'CRCLx',
|
||||
mintAddress: 'XsueG8BtpquVJX9LVLLEGuViXUungE6WmK5YZ3p3bd1',
|
||||
decimal: 8,
|
||||
mint: 'crclx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Cisco xStock',
|
||||
symbol: 'CSCOx',
|
||||
mintAddress: 'Xsr3pdLQyXvDJBFgpR5nexCEZwXvigb8wbPYp4YoNFf',
|
||||
decimal: 8,
|
||||
mint: 'cscx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Coca-Cola xStock',
|
||||
symbol: 'KOx',
|
||||
mintAddress: 'XsaBXg8dU5cPM6ehmVctMkVqoiRG2ZjMo1cyBJ3AykQ',
|
||||
decimal: 8,
|
||||
mint: 'kox',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Coinbase xStock',
|
||||
symbol: 'COINx',
|
||||
mintAddress: 'Xs7ZdzSHLU9ftNJsii5fCeJhoRWSC32SQGzGQtePxNu',
|
||||
decimal: 8,
|
||||
mint: 'coinx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Comcast xStock',
|
||||
symbol: 'CMCSAx',
|
||||
mintAddress: 'XsvKCaNsxg2GN8jjUmq71qukMJr7Q1c5R2Mk9P8kcS8',
|
||||
decimal: 8,
|
||||
mint: 'cmcsax',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'CrowdStrike xStock',
|
||||
symbol: 'CRWDx',
|
||||
mintAddress: 'Xs7xXqkcK7K8urEqGg52SECi79dRp2cEKKuYjUePYDw',
|
||||
decimal: 8,
|
||||
mint: 'crwdx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Danaher xStock',
|
||||
symbol: 'DHRx',
|
||||
mintAddress: 'Xseo8tgCZfkHxWS9xbFYeKFyMSbWEvZGFV1Gh53GtCV',
|
||||
decimal: 8,
|
||||
mint: 'dhrx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'DFDV xStock',
|
||||
symbol: 'DFDVx',
|
||||
mintAddress: 'Xs2yquAgsHByNzx68WJC55WHjHBvG9JsMB7CWjTLyPy',
|
||||
decimal: 8,
|
||||
mint: 'dfdvx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Eli Lilly xStock',
|
||||
symbol: 'LLYx',
|
||||
mintAddress: 'Xsnuv4omNoHozR6EEW5mXkw8Nrny5rB3jVfLqi6gKMH',
|
||||
decimal: 8,
|
||||
mint: 'llyx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Exxon Mobil xStock',
|
||||
symbol: 'XOMx',
|
||||
mintAddress: 'XsaHND8sHyfMfsWPj6kSdd5VwvCayZvjYgKmmcNL5qh',
|
||||
decimal: 8,
|
||||
mint: 'xomx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Gamestop xStock',
|
||||
symbol: 'GMEx',
|
||||
mintAddress: 'Xsf9mBktVB9BSU5kf4nHxPq5hCBJ2j2ui3ecFGxPRGc',
|
||||
decimal: 8,
|
||||
mint: 'gmex',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Gold xStock',
|
||||
symbol: 'GLDx',
|
||||
mintAddress: 'Xsv9hRk1z5ystj9MhnA7Lq4vjSsLwzL2nxrwmwtD3re',
|
||||
decimal: 8,
|
||||
mint: 'gldx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Goldman Sachs xStock',
|
||||
symbol: 'GSx',
|
||||
mintAddress: 'XsgaUyp4jd1fNBCxgtTKkW64xnnhQcvgaxzsbAq5ZD1',
|
||||
decimal: 8,
|
||||
mint: 'gsx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Home Depot xStock',
|
||||
symbol: 'HDx',
|
||||
mintAddress: 'XszjVtyhowGjSC5odCqBpW1CtXXwXjYokymrk7fGKD3',
|
||||
decimal: 8,
|
||||
mint: 'hdx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Honeywell xStock',
|
||||
symbol: 'HONx',
|
||||
mintAddress: 'XsRbLZthfABAPAfumWNEJhPyiKDW6TvDVeAeW7oKqA2',
|
||||
decimal: 8,
|
||||
mint: 'honx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Intel xStock',
|
||||
symbol: 'INTCx',
|
||||
mintAddress: 'XshPgPdXFRWB8tP1j82rebb2Q9rPgGX37RuqzohmArM',
|
||||
decimal: 8,
|
||||
mint: 'intcx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'International Business Machines xStock',
|
||||
symbol: 'IBMx',
|
||||
mintAddress: 'XspwhyYPdWVM8XBHZnpS9hgyag9MKjLRyE3tVfmCbSr',
|
||||
decimal: 8,
|
||||
mint: 'ibmx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Johnson & Johnson xStock',
|
||||
symbol: 'JNJx',
|
||||
mintAddress: 'XsGVi5eo1Dh2zUpic4qACcjuWGjNv8GCt3dm5XcX6Dn',
|
||||
decimal: 8,
|
||||
mint: 'jnjx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'JPMorgan Chase xStock',
|
||||
symbol: 'JPMx',
|
||||
mintAddress: 'XsMAqkcKsUewDrzVkait4e5u4y8REgtyS7jWgCpLV2C',
|
||||
decimal: 8,
|
||||
mint: 'jpmx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Linde xStock',
|
||||
symbol: 'LINx',
|
||||
mintAddress: 'XsSr8anD1hkvNMu8XQiVcmiaTP7XGvYu7Q58LdmtE8Z',
|
||||
decimal: 8,
|
||||
mint: 'linx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Marvell xStock',
|
||||
symbol: 'MRVLx',
|
||||
mintAddress: 'XsuxRGDzbLjnJ72v74b7p9VY6N66uYgTCyfwwRjVCJA',
|
||||
decimal: 8,
|
||||
mint: 'mrvlx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Mastercard xStock',
|
||||
symbol: 'MAx',
|
||||
mintAddress: 'XsApJFV9MAktqnAc6jqzsHVujxkGm9xcSUffaBoYLKC',
|
||||
decimal: 8,
|
||||
mint: 'max',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'McDonald\'s xStock',
|
||||
symbol: 'MCDx',
|
||||
mintAddress: 'XsqE9cRRpzxcGKDXj1BJ7Xmg4GRhZoyY1KpmGSxAWT2',
|
||||
decimal: 8,
|
||||
mint: 'mcdx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Medtronic xStock',
|
||||
symbol: 'MDTx',
|
||||
mintAddress: 'XsDgw22qRLTv5Uwuzn6T63cW69exG41T6gwQhEK22u2',
|
||||
decimal: 8,
|
||||
mint: 'mdtx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Merck xStock',
|
||||
symbol: 'MRKx',
|
||||
mintAddress: 'XsnQnU7AdbRZYe2akqqpibDdXjkieGFfSkbkjX1Sd1X',
|
||||
decimal: 8,
|
||||
mint: 'mrkx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Meta xStock',
|
||||
symbol: 'METAx',
|
||||
mintAddress: 'Xsa62P5mvPszXL1krVUnU5ar38bBSVcWAB6fmPCo5Zu',
|
||||
decimal: 8,
|
||||
mint: 'metax',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Microsoft xStock',
|
||||
symbol: 'MSFTx',
|
||||
mintAddress: 'XspzcW1PRtgf6Wj92HCiZdjzKCyFekVD8P5Ueh3dRMX',
|
||||
decimal: 8,
|
||||
mint: 'msftx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'MicroStrategy xStock',
|
||||
symbol: 'MSTRx',
|
||||
mintAddress: 'XsP7xzNPvEHS1m6qfanPUGjNmdnmsLKEoNAnHjdxxyZ',
|
||||
decimal: 8,
|
||||
mint: 'mstrx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Nasdaq xStock',
|
||||
symbol: 'QQQx',
|
||||
mintAddress: 'Xs8S1uUs1zvS2p7iwtsG3b6fkhpvmwz4GYU3gWAmWHZ',
|
||||
decimal: 8,
|
||||
mint: 'qqqx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Netflix xStock',
|
||||
symbol: 'NFLXx',
|
||||
mintAddress: 'XsEH7wWfJJu2ZT3UCFeVfALnVA6CP5ur7Ee11KmzVpL',
|
||||
decimal: 8,
|
||||
mint: 'nflxx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Novo Nordisk xStock',
|
||||
symbol: 'NVOx',
|
||||
mintAddress: 'XsfAzPzYrYjd4Dpa9BU3cusBsvWfVB9gBcyGC87S57n',
|
||||
decimal: 8,
|
||||
mint: 'nvox',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'NVIDIA xStock',
|
||||
symbol: 'NVDAx',
|
||||
mintAddress: 'Xsc9qvGR1efVDFGLrVsmkzv3qi45LTBjeUKSPmx9qEh',
|
||||
decimal: 8,
|
||||
mint: 'nvdax',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'OPEN xStock',
|
||||
symbol: 'OPENx',
|
||||
mintAddress: 'XsGtpmjhmC8kyjVSWL4VicGu36ceq9u55PTgF8bhGv6',
|
||||
decimal: 8,
|
||||
mint: 'openx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Oracle xStock',
|
||||
symbol: 'ORCLx',
|
||||
mintAddress: 'XsjFwUPiLofddX5cWFHW35GCbXcSu1BCUGfxoQAQjeL',
|
||||
decimal: 8,
|
||||
mint: 'orclx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Palantir xStock',
|
||||
symbol: 'PLTRx',
|
||||
mintAddress: 'XsoBhf2ufR8fTyNSjqfU71DYGaE6Z3SUGAidpzriAA4',
|
||||
decimal: 8,
|
||||
mint: 'pltrx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'PepsiCo xStock',
|
||||
symbol: 'PEPx',
|
||||
mintAddress: 'Xsv99frTRUeornyvCfvhnDesQDWuvns1M852Pez91vF',
|
||||
decimal: 8,
|
||||
mint: 'pepx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Pfizer xStock',
|
||||
symbol: 'PFEx',
|
||||
mintAddress: 'XsAtbqkAP1HJxy7hFDeq7ok6yM43DQ9mQ1Rh861X8rw',
|
||||
decimal: 8,
|
||||
mint: 'pfex',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Philip Morris xStock',
|
||||
symbol: 'PMx',
|
||||
mintAddress: 'Xsba6tUnSjDae2VcopDB6FGGDaxRrewFCDa5hKn5vT3',
|
||||
decimal: 8,
|
||||
mint: 'pmx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Procter & Gamble xStock',
|
||||
symbol: 'PGx',
|
||||
mintAddress: 'XsYdjDjNUygZ7yGKfQaB6TxLh2gC6RRjzLtLAGJrhzV',
|
||||
decimal: 8,
|
||||
mint: 'pgx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Robinhood xStock',
|
||||
symbol: 'HOODx',
|
||||
mintAddress: 'XsvNBAYkrDRNhA7wPHQfX3ZUXZyZLdnCQDfHZ56bzpg',
|
||||
decimal: 8,
|
||||
mint: 'hoodx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Salesforce xStock',
|
||||
symbol: 'CRMx',
|
||||
mintAddress: 'XsczbcQ3zfcgAEt9qHQES8pxKAVG5rujPSHQEXi4kaN',
|
||||
decimal: 8,
|
||||
mint: 'crmx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'SP500 xStock',
|
||||
symbol: 'SPYx',
|
||||
mintAddress: 'XsoCS1TfEyfFhfvj8EtZ528L3CaKBDBRqRapnBbDF2W',
|
||||
decimal: 8,
|
||||
mint: 'spyx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'TBLL xStock',
|
||||
symbol: 'TBLLx',
|
||||
mintAddress: 'XsqBC5tcVQLYt8wqGCHRnAUUecbRYXoJCReD6w7QEKp',
|
||||
decimal: 8,
|
||||
mint: 'tbllx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Tesla xStock',
|
||||
symbol: 'TSLAx',
|
||||
mintAddress: 'XsDoVfqeBukxuZHWhdvWHBhgEHjGNst4MLodqsJHzoB',
|
||||
decimal: 8,
|
||||
mint: 'tslax',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Thermo Fisher xStock',
|
||||
symbol: 'TMOx',
|
||||
mintAddress: 'Xs8drBWy3Sd5QY3aifG9kt9KFs2K3PGZmx7jWrsrk57',
|
||||
decimal: 8,
|
||||
mint: 'tmox',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'TQQQ xStock',
|
||||
symbol: 'TQQQx',
|
||||
mintAddress: 'XsjQP3iMAaQ3kQScQKthQpx9ALRbjKAjQtHg6TFomoc',
|
||||
decimal: 8,
|
||||
mint: 'tqqqx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'UnitedHealth xStock',
|
||||
symbol: 'UNHx',
|
||||
mintAddress: 'XszvaiXGPwvk2nwb3o9C1CX4K6zH8sez11E6uyup6fe',
|
||||
decimal: 8,
|
||||
mint: 'unhx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Vanguard xStock',
|
||||
symbol: 'VTIx',
|
||||
mintAddress: 'XsssYEQjzxBCFgvYFFNuhJFBeHNdLWYeUSP8F45cDr9',
|
||||
decimal: 8,
|
||||
mint: 'vtix',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Visa xStock',
|
||||
symbol: 'Vx',
|
||||
mintAddress: 'XsqgsbXwWogGJsNcVZ3TyVouy2MbTkfCFhCGGGcQZ2p',
|
||||
decimal: 8,
|
||||
mint: 'vx',
|
||||
enabled: false),
|
||||
SPLToken(
|
||||
name: 'Walmart xStock',
|
||||
symbol: 'WMTx',
|
||||
mintAddress: 'Xs151QeqTCiuKtinzfRATnUESM2xTU6V9Wy8Vy538ci',
|
||||
decimal: 8,
|
||||
mint: 'wmtx',
|
||||
enabled: false),
|
||||
|
||||
];
|
||||
|
||||
List<SPLToken> get initialSPLTokens => _defaultTokens.map((token) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import 'package:cw_solana/pending_solana_transaction.dart';
|
||||
import 'package:cw_solana/solana_balance.dart';
|
||||
import 'package:cw_solana/solana_exceptions.dart';
|
||||
import 'package:cw_solana/solana_transaction_model.dart';
|
||||
import 'package:cw_solana/spl_token.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
import 'package:on_chain/solana/solana.dart';
|
||||
import 'package:on_chain/solana/src/instructions/associated_token_account/constant.dart';
|
||||
import 'package:on_chain/solana/src/models/pda/pda.dart';
|
||||
|
||||
@@ -25,7 +25,7 @@ import 'package:cw_solana/solana_transaction_history.dart';
|
||||
import 'package:cw_solana/solana_transaction_info.dart';
|
||||
import 'package:cw_solana/solana_transaction_model.dart';
|
||||
import 'package:cw_solana/solana_wallet_addresses.dart';
|
||||
import 'package:cw_solana/spl_token.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
import 'package:hex/hex.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_tron/tron_token.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
|
||||
class DefaultTronTokens {
|
||||
final List<TronToken> _defaultTokens = [
|
||||
|
||||
@@ -10,7 +10,7 @@ import 'package:cw_tron/pending_tron_transaction.dart';
|
||||
import 'package:cw_tron/tron_abi.dart';
|
||||
import 'package:cw_tron/tron_balance.dart';
|
||||
import 'package:cw_tron/tron_http_provider.dart';
|
||||
import 'package:cw_tron/tron_token.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
import 'package:cw_tron/tron_transaction_model.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
@@ -24,7 +24,7 @@ import 'package:cw_tron/tron_abi.dart';
|
||||
import 'package:cw_tron/tron_balance.dart';
|
||||
import 'package:cw_tron/tron_client.dart';
|
||||
import 'package:cw_tron/tron_exception.dart';
|
||||
import 'package:cw_tron/tron_token.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
import 'package:cw_tron/tron_transaction_credentials.dart';
|
||||
import 'package:cw_tron/tron_transaction_history.dart';
|
||||
import 'package:cw_tron/tron_transaction_info.dart';
|
||||
|
||||
@@ -184,7 +184,9 @@ class TradeMonitor {
|
||||
trade
|
||||
..stateRaw = updated.state.raw
|
||||
..receiveAmount = updated.receiveAmount ?? trade.receiveAmount
|
||||
..outputTransaction = updated.outputTransaction ?? trade.outputTransaction;
|
||||
..outputTransaction = updated.outputTransaction ?? trade.outputTransaction
|
||||
..userCurrencyToRaw = updated.userCurrencyToRaw
|
||||
..userCurrencyFromRaw = updated.userCurrencyFromRaw;
|
||||
printV('Trade ${trade.id} updated: ${trade.state}');
|
||||
await trade.save();
|
||||
|
||||
|
||||
@@ -525,6 +525,7 @@ Future<void> setup({
|
||||
getIt.get<ContactListViewModel>(),
|
||||
getIt.get<UnspentCoinsListViewModel>(),
|
||||
getIt.get<FeesViewModel>(),
|
||||
_walletInfoSource,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
@@ -167,6 +167,8 @@ class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: request.toAmount,
|
||||
state: TradeState.waiting,
|
||||
payoutAddress: request.toAddress,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
@@ -199,6 +201,9 @@ class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
final refundAmount = status['refundEgress']?['amount']?.toString() ?? '0.0';
|
||||
final isRefund = status['refundEgress'] != null;
|
||||
final amount = isRefund ? refundAmount : receiveAmount;
|
||||
|
||||
final from = status['sourceAsset'].toString();
|
||||
final to = status['destinationAsset'].toString();
|
||||
|
||||
final newTrade = Trade(
|
||||
id: id,
|
||||
@@ -210,7 +215,10 @@ class ChainflipExchangeProvider extends ExchangeProvider {
|
||||
state: currentState,
|
||||
payoutAddress: status['destinationAddress'].toString(),
|
||||
outputTransaction: status['swapEgress']?['transactionReference']?.toString(),
|
||||
isRefund: isRefund);
|
||||
isRefund: isRefund,
|
||||
userCurrencyFromRaw: '${from.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${to.toUpperCase()}' + '_',
|
||||
);
|
||||
|
||||
// Find trade and update receiveAmount with the real value received
|
||||
final storedTrade = _getStoredTrade(id);
|
||||
|
||||
@@ -215,6 +215,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: toAmount ?? request.toAmount,
|
||||
state: TradeState.created,
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
}
|
||||
@@ -240,9 +242,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromCurrency = responseJSON['fromCurrency'] as String;
|
||||
final from = CryptoCurrency.fromString(fromCurrency);
|
||||
final from = CryptoCurrency.safeParseCurrencyFromString(fromCurrency);
|
||||
final toCurrency = responseJSON['toCurrency'] as String;
|
||||
final to = CryptoCurrency.fromString(toCurrency);
|
||||
final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency);
|
||||
final inputAddress = responseJSON['payinAddress'] as String;
|
||||
final expectedSendAmount = responseJSON['expectedAmountFrom'].toString();
|
||||
final status = responseJSON['status'] as String;
|
||||
@@ -254,17 +256,20 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw ?? '')?.toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
extraId: extraId,
|
||||
expiredAt: expiredAt,
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress);
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
extraId: extraId,
|
||||
expiredAt: expiredAt,
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
String _getFlow(bool isFixedRate) => isFixedRate ? 'fixed-rate' : 'standard';
|
||||
|
||||
@@ -214,6 +214,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: receiveAmount ?? request.toAmount,
|
||||
state: TradeState.created,
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
isSendAll: isSendAll,
|
||||
);
|
||||
}
|
||||
@@ -249,15 +251,18 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.fromString(coinFrom),
|
||||
to: CryptoCurrency.fromString(coinTo),
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(coinFrom),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(coinTo),
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: amount,
|
||||
state: TradeState.deserialize(raw: _prepareStatus(status)),
|
||||
extraId: extraId,
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress);
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${coinFrom.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${coinTo.toUpperCase()}' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
String _getRateType(bool isFixedRate) => isFixedRate ? 'fixed' : 'float';
|
||||
|
||||
@@ -62,7 +62,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'amount': '1',
|
||||
'affiliate_id': _affiliateId
|
||||
'affiliate_id': _affiliateId,
|
||||
'float': isFixedRateMode ? 'false' : 'true',
|
||||
};
|
||||
|
||||
final responseJSON = await _getInfo(params, isFixedRateMode);
|
||||
@@ -91,7 +92,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'amount': amount.toString(),
|
||||
'affiliate_id': _affiliateId
|
||||
'affiliate_id': _affiliateId,
|
||||
'float': isFixedRateMode ? 'false' : 'true',
|
||||
};
|
||||
|
||||
final responseJSON = await _getInfo(params, isFixedRateMode);
|
||||
@@ -121,7 +123,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'amount': isFixedRateMode ? request.toAmount.toString() : request.fromAmount.toString(),
|
||||
'affiliate_id': _affiliateId
|
||||
'affiliate_id': _affiliateId,
|
||||
'float': isFixedRateMode ? 'false' : 'true',
|
||||
};
|
||||
|
||||
final responseInfoJSON = await _getInfo(params, isFixedRateMode);
|
||||
@@ -141,7 +144,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
'rate_id': rateId,
|
||||
if (networkFrom != null) 'network_from': networkFrom,
|
||||
if (networkTo != null) 'network_to': networkTo,
|
||||
'affiliate_id': _affiliateId
|
||||
'affiliate_id': _affiliateId,
|
||||
'float': isFixedRateMode ? 'false' : 'true',
|
||||
};
|
||||
|
||||
final headers = {
|
||||
@@ -151,10 +155,11 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
};
|
||||
|
||||
final uri = Uri.https(_baseUrl,
|
||||
isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath, tradeParams);
|
||||
isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath);
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: headers,
|
||||
body: json.encode(tradeParams),
|
||||
);
|
||||
|
||||
|
||||
@@ -206,6 +211,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
@@ -230,7 +237,9 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final from = responseJSON['coin_from'] as String;
|
||||
final fromNetwork = responseJSON['coin_from_network'] as String;
|
||||
final to = responseJSON['coin_to'] as String;
|
||||
final toNetwork = responseJSON['coin_to_network'] as String;
|
||||
final payoutAddress = responseJSON['withdrawal'] as String;
|
||||
final depositAddress = responseJSON['deposit'] as String;
|
||||
final refundAddress = responseJSON['return'] as String;
|
||||
@@ -246,8 +255,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.fromString(from),
|
||||
to: CryptoCurrency.fromString(to),
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(from),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(to),
|
||||
provider: description,
|
||||
inputAddress: depositAddress,
|
||||
payoutAddress: payoutAddress,
|
||||
@@ -259,6 +268,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
expiredAt: expiredAt,
|
||||
isRefund: status == 'refund',
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '$from' + '_' + '$fromNetwork',
|
||||
userCurrencyToRaw: '$to' + '_' + '$toNetwork',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -270,10 +281,11 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
|
||||
};
|
||||
|
||||
try {
|
||||
final uri = Uri.https(_baseUrl, isFixedRateMode ? _infoRevertPath : _infoPath, params);
|
||||
final uri = Uri.https(_baseUrl, isFixedRateMode ? _infoRevertPath : _infoPath);
|
||||
final response = await ProxyWrapper().post(
|
||||
clearnetUri: uri,
|
||||
headers: headers,
|
||||
body: json.encode(params),
|
||||
);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
|
||||
@@ -225,7 +225,9 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
payoutAddress: settleAddress,
|
||||
createdAt: DateTime.now(),
|
||||
isSendAll: isSendAll,
|
||||
extraId: depositMemo
|
||||
extraId: depositMemo,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -264,15 +266,18 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.fromString(fromCurrency),
|
||||
to: CryptoCurrency.fromString(toCurrency),
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(fromCurrency),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(toCurrency),
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount ?? '',
|
||||
state: TradeState.deserialize(raw: status ?? 'created'),
|
||||
expiredAt: expiredAt,
|
||||
payoutAddress: settleAddress,
|
||||
extraId: depositMemo);
|
||||
extraId: depositMemo,
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> _createQuote(TradeRequest request) async {
|
||||
|
||||
@@ -175,6 +175,8 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||
payoutAddress: payoutAddress,
|
||||
createdAt: DateTime.now(),
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -211,14 +213,16 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.fromString(fromCurrency),
|
||||
to: CryptoCurrency.fromString(toCurrency),
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(fromCurrency),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(toCurrency),
|
||||
extraId: extraId,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: TradeState.deserialize(raw: status),
|
||||
payoutAddress: payoutAddress,
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -198,6 +198,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
|
||||
createdAt: createdAt,
|
||||
expiredAt: expiredAt,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
@@ -235,8 +237,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
|
||||
|
||||
return Trade(
|
||||
id: respId,
|
||||
from: CryptoCurrency.fromString(from),
|
||||
to: CryptoCurrency.fromString(to),
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(from),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(to),
|
||||
provider: description,
|
||||
inputAddress: depositAddress,
|
||||
payoutAddress: payoutAddress,
|
||||
@@ -247,6 +249,8 @@ class StealthExExchangeProvider extends ExchangeProvider {
|
||||
createdAt: createdAt,
|
||||
isRefund: status == 'refunded',
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${from.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${to.toUpperCase()}' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,8 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
|
||||
state: TradeState.created,
|
||||
payoutAddress: request.toAddress,
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
} catch (e) {
|
||||
printV("error creating trade: ${e.toString()}");
|
||||
@@ -224,9 +226,9 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
|
||||
|
||||
final responseData = responseBody['data'] as Map<String, dynamic>;
|
||||
final fromCurrency = responseData['coin_send'] as String;
|
||||
final from = CryptoCurrency.fromString(fromCurrency);
|
||||
final from = CryptoCurrency.safeParseCurrencyFromString(fromCurrency);
|
||||
final toCurrency = responseData['coin_receive'] as String;
|
||||
final to = CryptoCurrency.fromString(toCurrency);
|
||||
final to = CryptoCurrency.safeParseCurrencyFromString(toCurrency);
|
||||
final inputAddress = responseData['server_address'] as String;
|
||||
final payoutAddress = responseData['recipient'] as String;
|
||||
final status = responseData['status'] as String;
|
||||
@@ -249,6 +251,8 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: expectedReceiveAmount,
|
||||
memo: memo,
|
||||
createdAt: DateTime.tryParse(createdAt ?? ''),
|
||||
userCurrencyFromRaw: '${fromCurrency.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${toCurrency.toUpperCase()}' + '_',
|
||||
);
|
||||
} catch (e) {
|
||||
printV("error getting trade: ${e.toString()}");
|
||||
|
||||
@@ -157,6 +157,8 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
||||
payoutAddress: request.toAddress,
|
||||
memo: memo,
|
||||
isSendAll: isSendAll,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -197,8 +199,8 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
||||
? parts[1].split('.')[1].split('-')[0]
|
||||
: '';
|
||||
|
||||
final formattedToChain = CryptoCurrency.fromString(toChain);
|
||||
final toAssetWithChain = CryptoCurrency.fromString(toAsset, walletCurrency: formattedToChain);
|
||||
final formattedToChain = CryptoCurrency.safeParseCurrencyFromString(toChain);
|
||||
final toAssetWithChain = CryptoCurrency.safeParseCurrencyFromString(toAsset, walletCurrency: formattedToChain);
|
||||
|
||||
final plannedOutTxs = responseJSON['planned_out_txs'] as List<dynamic>?;
|
||||
final isRefund = plannedOutTxs?.any((tx) => tx['refund'] == true) ?? false;
|
||||
@@ -214,6 +216,8 @@ class ThorChainExchangeProvider extends ExchangeProvider {
|
||||
state: currentState,
|
||||
memo: memo,
|
||||
isRefund: isRefund,
|
||||
userCurrencyFromRaw: '${tx['chain'] as String? ?? ''}' + '_',
|
||||
userCurrencyToRaw: '$toAsset' + '_',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
payoutAddress: payoutAddress,
|
||||
isSendAll: isSendAll,
|
||||
extraId: addressProviderMemo,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -274,10 +276,13 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
final providerName = responseJSON['provider'] as String;
|
||||
final addressProviderMemo = responseJSON['address_provider_memo'] as String?;
|
||||
|
||||
final from = responseJSON['ticker_from'] as String;
|
||||
final to = responseJSON['ticker_to'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: CryptoCurrency.fromString(responseJSON['ticker_from'] as String),
|
||||
to: CryptoCurrency.fromString(responseJSON['ticker_to'] as String),
|
||||
from: CryptoCurrency.safeParseCurrencyFromString(from),
|
||||
to: CryptoCurrency.safeParseCurrencyFromString(to),
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: refundAddress,
|
||||
@@ -289,6 +294,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
providerId: providerId,
|
||||
providerName: providerName,
|
||||
extraId: addressProviderMemo,
|
||||
userCurrencyFromRaw: '${from.toUpperCase()}' + '_',
|
||||
userCurrencyToRaw: '${to.toUpperCase()}' + '_',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -76,22 +76,26 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Failed to fetch assets for ${currency.title} on ${currency.tag}');
|
||||
}
|
||||
final assets = json.decode(response.body) as List<dynamic>;
|
||||
|
||||
final decoded = jsonDecode(response.body);
|
||||
if (decoded is! List) throw const FormatException('Unexpected response format');
|
||||
final assets = decoded.map((e) => Map<String, dynamic>.from(e as Map)).toList();
|
||||
|
||||
|
||||
final asset = assets.firstWhere(
|
||||
(asset) {
|
||||
final assetSymbol = (asset['symbol'] as String).toUpperCase();
|
||||
return assetSymbol == currency.title.toUpperCase();
|
||||
},
|
||||
orElse: () => null,
|
||||
(asset) => removeNonAlphanumeric((asset['symbol'] ?? '').toString()) == currency.title,
|
||||
orElse: () => const {},
|
||||
);
|
||||
return asset != null ? asset['id'] as String : null;
|
||||
|
||||
return asset.isEmpty ? null : asset['id'] as String;
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String removeNonAlphanumeric(String str) => str.toUpperCase().replaceAll(RegExp(r'[^A-Z0-9]'), '');
|
||||
|
||||
Future<List<dynamic>> getRatesForPair({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
@@ -117,19 +121,24 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode,
|
||||
}) async {
|
||||
final rates = await getRatesForPair(from: from, to: to);
|
||||
if (rates.isEmpty) return Limits(min: 0, max: 0);
|
||||
try {
|
||||
final rates = await getRatesForPair(from: from, to: to);
|
||||
if (rates.isEmpty) throw Exception('No rates found for $from to $to');
|
||||
|
||||
double minLimit = double.infinity;
|
||||
double maxLimit = 0;
|
||||
|
||||
for (var rate in rates) {
|
||||
final double currentMin = double.parse(rate['min']['value'].toString());
|
||||
final double currentMax = double.parse(rate['max']['value'].toString());
|
||||
if (currentMin < minLimit) minLimit = currentMin;
|
||||
if (currentMax > maxLimit) maxLimit = currentMax;
|
||||
for (var rate in rates) {
|
||||
final double currentMin = double.parse(rate['min']['value'].toString());
|
||||
final double currentMax = double.parse(rate['max']['value'].toString());
|
||||
if (currentMin < minLimit) minLimit = currentMin;
|
||||
if (currentMax > maxLimit) maxLimit = currentMax;
|
||||
}
|
||||
return Limits(min: minLimit, max: maxLimit);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
throw Exception('StealthEx failed to fetch limits');
|
||||
}
|
||||
return Limits(min: minLimit, max: maxLimit);
|
||||
}
|
||||
|
||||
Future<double> fetchRate({
|
||||
@@ -249,6 +258,8 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: receiveAmount.toString(),
|
||||
payoutAddress: payoutAddress,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '${request.fromCurrency.title}_${request.fromCurrency.tag ?? ''}',
|
||||
userCurrencyToRaw: '${request.toCurrency.title}_${request.toCurrency.tag ?? ''}',
|
||||
);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
@@ -275,10 +286,10 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
|
||||
final pairId = responseJSON['pairId'] as String;
|
||||
final pairParts = pairId.split('_');
|
||||
final CryptoCurrency fromCurrency =
|
||||
CryptoCurrency.fromString(pairParts.isNotEmpty ? pairParts[0] : "");
|
||||
final CryptoCurrency toCurrency =
|
||||
CryptoCurrency.fromString(pairParts.length > 1 ? pairParts[1] : "");
|
||||
final fromAsset = pairParts.isNotEmpty ? pairParts[0] : '';
|
||||
final toAsset = pairParts.length > 1 ? pairParts[1] : '';
|
||||
final fromCurrency = CryptoCurrency.safeParseCurrencyFromString(fromAsset);
|
||||
final toCurrency = CryptoCurrency.safeParseCurrencyFromString(toAsset);
|
||||
|
||||
final amount = responseJSON['amount'] as Map<String, dynamic>;
|
||||
final toAmount = responseJSON['toAmount'] as Map<String, dynamic>;
|
||||
@@ -306,6 +317,8 @@ class XOSwapExchangeProvider extends ExchangeProvider {
|
||||
receiveAmount: receiveAmount,
|
||||
payoutAddress: payoutAddress,
|
||||
extraId: extraId,
|
||||
userCurrencyFromRaw: '$fromAsset' + '_',
|
||||
userCurrencyToRaw: '$toAsset' + '_',
|
||||
);
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
|
||||
+50
-2
@@ -31,6 +31,8 @@ class Trade extends HiveObject {
|
||||
this.isRefund,
|
||||
this.isSendAll,
|
||||
this.router,
|
||||
this.userCurrencyFromRaw,
|
||||
this.userCurrencyToRaw,
|
||||
}) {
|
||||
if (provider != null) providerRaw = provider.raw;
|
||||
|
||||
@@ -126,6 +128,46 @@ class Trade extends HiveObject {
|
||||
@HiveField(23, defaultValue: '')
|
||||
String? receiveAmount;
|
||||
|
||||
@HiveField(24, defaultValue: '')
|
||||
String? userCurrencyFromRaw;
|
||||
|
||||
@HiveField(25, defaultValue: '')
|
||||
String? userCurrencyToRaw;
|
||||
|
||||
CryptoCurrency? get userCurrencyFrom {
|
||||
if (userCurrencyFromRaw == null || userCurrencyFromRaw!.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final underscoreIndex = userCurrencyFromRaw!.indexOf('_');
|
||||
final title = userCurrencyFromRaw!.substring(0, underscoreIndex);
|
||||
final tag = userCurrencyFromRaw!.substring(underscoreIndex + 1);
|
||||
|
||||
return CryptoCurrency(
|
||||
title: title,
|
||||
tag: tag.isNotEmpty ? tag : null,
|
||||
name: '',
|
||||
raw: -1,
|
||||
decimals: 1,
|
||||
);
|
||||
}
|
||||
|
||||
CryptoCurrency? get userCurrencyTo {
|
||||
if (userCurrencyToRaw == null || userCurrencyToRaw!.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
final underscoreIndex = userCurrencyToRaw!.indexOf('_');
|
||||
final title = userCurrencyToRaw!.substring(0, underscoreIndex);
|
||||
final tag = userCurrencyToRaw!.substring(underscoreIndex + 1);
|
||||
|
||||
return CryptoCurrency(
|
||||
title: title,
|
||||
tag: tag.isNotEmpty ? tag : null,
|
||||
name: '',
|
||||
raw: -1,
|
||||
decimals: 1,
|
||||
);
|
||||
}
|
||||
|
||||
static Trade fromMap(Map<String, Object?> map) {
|
||||
return Trade(
|
||||
id: map['id'] as String,
|
||||
@@ -206,6 +248,8 @@ class TradeAdapter extends TypeAdapter<Trade> {
|
||||
isRefund: fields[20] as bool?,
|
||||
isSendAll: fields[21] as bool?,
|
||||
router: fields[22] as String?,
|
||||
userCurrencyFromRaw: fields[24] as String?,
|
||||
userCurrencyToRaw: fields[25] as String?,
|
||||
)
|
||||
..providerRaw = fields[1] == null ? 0 : fields[1] as int
|
||||
..fromRaw = fields[2] == null ? 0 : fields[2] as int
|
||||
@@ -216,7 +260,7 @@ class TradeAdapter extends TypeAdapter<Trade> {
|
||||
@override
|
||||
void write(BinaryWriter writer, Trade obj) {
|
||||
writer
|
||||
..writeByte(24)
|
||||
..writeByte(26)
|
||||
..writeByte(0)
|
||||
..write(obj.id)
|
||||
..writeByte(1)
|
||||
@@ -264,7 +308,11 @@ class TradeAdapter extends TypeAdapter<Trade> {
|
||||
..writeByte(22)
|
||||
..write(obj.router)
|
||||
..writeByte(23)
|
||||
..write(obj.receiveAmount);
|
||||
..write(obj.receiveAmount)
|
||||
..writeByte(24)
|
||||
..write(obj.userCurrencyFromRaw)
|
||||
..writeByte(25)
|
||||
..write(obj.userCurrencyToRaw);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -36,10 +36,13 @@ import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/address_info.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
import 'package:cw_core/mweb_utxo.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/payjoin_session.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
|
||||
@@ -206,6 +209,18 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||
CakeHive.registerAdapter(PayjoinSessionAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
||||
CakeHive.registerAdapter(Erc20TokenAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
|
||||
CakeHive.registerAdapter(SPLTokenAdapter());
|
||||
}
|
||||
|
||||
if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
|
||||
CakeHive.registerAdapter(TronTokenAdapter());
|
||||
}
|
||||
|
||||
final secureStorage = secureStorageShared;
|
||||
final transactionDescriptionsBoxKey =
|
||||
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||
|
||||
@@ -125,13 +125,16 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||
});
|
||||
}
|
||||
|
||||
void _checkIfTokenIsVerified(String? contractAddress) async {
|
||||
if (contractAddress != null) {
|
||||
final isVerified = widget.homeSettingsViewModel.checkIfTokenIsWhitelisted(contractAddress);
|
||||
setState(() {
|
||||
_isTokenVerified = isVerified;
|
||||
});
|
||||
}
|
||||
void _checkIfTokenIsVerified(String? contractAddress) {
|
||||
if (contractAddress == null) return;
|
||||
|
||||
final isVerified =
|
||||
widget.homeSettingsViewModel.checkIfTokenIsWhitelisted(contractAddress);
|
||||
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_isTokenVerified = isVerified;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -253,7 +256,9 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||
name: _tokenNameController.text,
|
||||
title: _tokenSymbolController.text.toUpperCase(),
|
||||
decimals: int.parse(_tokenDecimalController.text),
|
||||
iconPath: _tokenIconPathController.text,
|
||||
iconPath: _tokenIconPathController.text.isNotEmpty
|
||||
? _tokenIconPathController.text
|
||||
: null,
|
||||
isPotentialScam: isPotentialScam,
|
||||
),
|
||||
contractAddress: _contractAddressController.text,
|
||||
@@ -335,6 +340,8 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
|
||||
if (_contractAddressController.text.isNotEmpty) {
|
||||
final token = await widget.homeSettingsViewModel.getToken(_contractAddressController.text);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (token != null) {
|
||||
final isZano = widget.homeSettingsViewModel.walletType == WalletType.zano;
|
||||
if (_tokenNameController.text.isEmpty || isZano) _tokenNameController.text = token.name;
|
||||
|
||||
@@ -164,22 +164,28 @@ class TransactionsPage extends StatelessWidget {
|
||||
if (item is TradeListItem) {
|
||||
final trade = item.trade;
|
||||
|
||||
return Observer(
|
||||
builder: (_) => TradeRow(
|
||||
key: item.key,
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
swapState: trade.state,
|
||||
provider: trade.provider,
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
createdAtFormattedDate: trade.createdAt != null
|
||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
||||
: null,
|
||||
formattedAmount: item.tradeFormattedAmount,
|
||||
formattedReceiveAmount: item.tradeFormattedReceiveAmount
|
||||
),
|
||||
);
|
||||
final tradeFrom =
|
||||
trade.fromRaw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
|
||||
final tradeTo = trade.toRaw >= 0 ? trade.to : trade.userCurrencyTo;
|
||||
|
||||
return tradeFrom != null && tradeTo != null
|
||||
? Observer(
|
||||
builder: (_) => TradeRow(
|
||||
key: item.key,
|
||||
onTap: () => Navigator.of(context)
|
||||
.pushNamed(Routes.tradeDetails, arguments: trade),
|
||||
swapState: trade.state,
|
||||
provider: trade.provider,
|
||||
from: tradeFrom,
|
||||
to: tradeTo,
|
||||
createdAtFormattedDate: trade.createdAt != null
|
||||
? DateFormat('HH:mm').format(trade.createdAt!)
|
||||
: null,
|
||||
formattedAmount: item.tradeFormattedAmount,
|
||||
formattedReceiveAmount: item.tradeFormattedReceiveAmount),
|
||||
)
|
||||
: Container();
|
||||
}
|
||||
if (item is OrderListItem) {
|
||||
final order = item.order;
|
||||
|
||||
@@ -39,13 +39,11 @@ class CurrencyPickerState extends State<CurrencyPicker> {
|
||||
String textFieldValue;
|
||||
|
||||
bool currencySearchBySubstring(Currency currency, String subString) {
|
||||
return currency.name.toLowerCase().contains(subString.toLowerCase()) ||
|
||||
(currency.tag != null
|
||||
? currency.tag!.toLowerCase().contains(subString.toLowerCase())
|
||||
: false) ||
|
||||
(currency.fullName != null
|
||||
? currency.fullName!.toLowerCase().contains(subString.toLowerCase())
|
||||
: false);
|
||||
final query = subString.toLowerCase();
|
||||
return currency.name.toLowerCase().contains(query) ||
|
||||
currency.toString().toLowerCase().contains(query) ||
|
||||
(currency.tag != null ? currency.tag!.toLowerCase().contains(query) : false) ||
|
||||
(currency.fullName != null ? currency.fullName!.toLowerCase().contains(query) : false);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -76,7 +76,7 @@ class PresentProviderPicker extends StatelessWidget {
|
||||
(e) => CheckBoxItem(
|
||||
e.title,
|
||||
exchangeViewModel.selectedProviders.contains(e),
|
||||
isDisabled: !exchangeViewModel.providersForCurrentPair().contains(e),
|
||||
isDisabled: !exchangeViewModel.providerList.contains(e),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
|
||||
@@ -102,15 +102,17 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||
}
|
||||
|
||||
if (_balanceViewModel.wallet.type == WalletType.solana) {
|
||||
final splToken = token.copyWith(enabled: true);
|
||||
await solana!.addSPLToken(
|
||||
_balanceViewModel.wallet,
|
||||
token,
|
||||
splToken,
|
||||
contractAddress,
|
||||
);
|
||||
}
|
||||
|
||||
if (_balanceViewModel.wallet.type == WalletType.tron) {
|
||||
await tron!.addTronToken(_balanceViewModel.wallet, token, contractAddress);
|
||||
final tronToken = token.copyWith(enabled: true);
|
||||
await tron!.addTronToken(_balanceViewModel.wallet, tronToken, contractAddress);
|
||||
}
|
||||
|
||||
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
||||
|
||||
@@ -159,9 +159,18 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
}
|
||||
|
||||
void _updateItems() {
|
||||
final tagFrom =
|
||||
tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : '';
|
||||
final tagTo = tradesStore.trade!.to.tag != null ? '${tradesStore.trade!.to.tag}' + ' ' : '';
|
||||
final trade = tradesStore.trade!;
|
||||
final tradeFrom = trade.fromRaw >= 0
|
||||
? trade.from
|
||||
: trade.userCurrencyFrom;
|
||||
|
||||
final tradeTo = trade.toRaw >= 0
|
||||
? trade.to
|
||||
: trade.userCurrencyTo;
|
||||
|
||||
final tagFrom = tradeFrom?.tag != null ? '${tradeFrom!.tag}' + ' ' : '';
|
||||
final tagTo = tradeTo?.tag != null ? '${tradeTo!.tag}' + ' ' : '';
|
||||
|
||||
items.clear();
|
||||
|
||||
if (trade.provider != ExchangeProviderDescription.thorChain)
|
||||
@@ -175,36 +184,40 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
),
|
||||
);
|
||||
|
||||
items.addAll([
|
||||
ExchangeTradeItem(
|
||||
title: S.current.amount,
|
||||
data: '${trade.amount} ${trade.from}',
|
||||
isCopied: false,
|
||||
isReceiveDetail: false,
|
||||
isExternalSendDetail: true,
|
||||
),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.you_will_receive_estimated_amount + ':',
|
||||
data: '${tradesStore.trade?.receiveAmount} ${trade.to}',
|
||||
isCopied: true,
|
||||
isReceiveDetail: true,
|
||||
isExternalSendDetail: false,
|
||||
),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.send_to_this_address('${tradesStore.trade!.from}', tagFrom) + ':',
|
||||
data: trade.inputAddress ?? '',
|
||||
isCopied: false,
|
||||
isReceiveDetail: false,
|
||||
isExternalSendDetail: true,
|
||||
),
|
||||
]);
|
||||
if (tradeFrom != null || tradeTo != null) {
|
||||
items.addAll([
|
||||
ExchangeTradeItem(
|
||||
title: S.current.amount,
|
||||
data: '${trade.amount} ${tradeFrom}',
|
||||
isCopied: false,
|
||||
isReceiveDetail: false,
|
||||
isExternalSendDetail: true,
|
||||
),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.you_will_receive_estimated_amount + ':',
|
||||
data: '${tradesStore.trade?.receiveAmount} ${tradeTo}',
|
||||
isCopied: true,
|
||||
isReceiveDetail: true,
|
||||
isExternalSendDetail: false,
|
||||
),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.send_to_this_address('${tradeFrom}', tagFrom) + ':',
|
||||
data: trade.inputAddress ?? '',
|
||||
isCopied: false,
|
||||
isReceiveDetail: false,
|
||||
isExternalSendDetail: true,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
final isExtraIdExist = trade.extraId != null && trade.extraId!.isNotEmpty;
|
||||
|
||||
if (isExtraIdExist) {
|
||||
final title = trade.from == CryptoCurrency.xrp
|
||||
|
||||
|
||||
final title = tradeFrom == CryptoCurrency.xrp
|
||||
? S.current.destination_tag
|
||||
: trade.from == CryptoCurrency.xlm || trade.from == CryptoCurrency.ton
|
||||
: tradeFrom == CryptoCurrency.xlm || tradeFrom == CryptoCurrency.ton
|
||||
? S.current.memo
|
||||
: S.current.extra_id;
|
||||
|
||||
@@ -220,7 +233,7 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
|
||||
items.add(
|
||||
ExchangeTradeItem(
|
||||
title: S.current.arrive_in_this_address('${tradesStore.trade!.to}', tagTo) + ':',
|
||||
title: S.current.arrive_in_this_address('${tradeTo}', tagTo) + ':',
|
||||
data: trade.payoutAddress ?? '',
|
||||
isCopied: true,
|
||||
isReceiveDetail: true,
|
||||
@@ -230,23 +243,29 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
}
|
||||
|
||||
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
|
||||
|
||||
final trade = tradesStore.trade!;
|
||||
final tradeFrom = trade.fromRaw >= 0
|
||||
? trade.from
|
||||
: trade.userCurrencyFrom;
|
||||
|
||||
bool _isEthToken() =>
|
||||
wallet.currency == CryptoCurrency.eth &&
|
||||
tradesStore.trade!.from.tag == CryptoCurrency.eth.title;
|
||||
|
||||
bool _isPolygonToken() =>
|
||||
wallet.currency == CryptoCurrency.maticpoly &&
|
||||
tradesStore.trade!.from.tag == CryptoCurrency.maticpoly.tag;
|
||||
tradeFrom?.tag == CryptoCurrency.maticpoly.tag;
|
||||
|
||||
bool _isTronToken() =>
|
||||
wallet.currency == CryptoCurrency.trx &&
|
||||
tradesStore.trade!.from.tag == CryptoCurrency.trx.title;
|
||||
tradeFrom?.tag == CryptoCurrency.trx.title;
|
||||
|
||||
bool _isSplToken() =>
|
||||
wallet.currency == CryptoCurrency.sol &&
|
||||
tradesStore.trade!.from.tag == CryptoCurrency.sol.title;
|
||||
tradeFrom?.tag == CryptoCurrency.sol.title;
|
||||
|
||||
return tradesStore.trade!.from == wallet.currency ||
|
||||
return tradeFrom == wallet.currency ||
|
||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
|
||||
_isEthToken() ||
|
||||
_isPolygonToken() ||
|
||||
|
||||
@@ -37,12 +37,17 @@ import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/fees_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_model.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/erc20_token.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
import 'package:cw_core/unspent_coin_type.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
@@ -70,6 +75,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
this.contactListViewModel,
|
||||
this.unspentCoinsListViewModel,
|
||||
this.feesViewModel,
|
||||
this.walletInfoSource,
|
||||
) : _cryptoNumberFormat = NumberFormat(),
|
||||
isSendAllEnabled = false,
|
||||
isFixedRateMode = false,
|
||||
@@ -81,8 +87,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
isDepositAddressEnabled = false,
|
||||
isReceiveAmountEditable = false,
|
||||
_useTorOnly = false,
|
||||
receiveCurrencies = <CryptoCurrency>[],
|
||||
depositCurrencies = <CryptoCurrency>[],
|
||||
receiveCurrencies = ObservableList<CryptoCurrency>(),
|
||||
depositCurrencies = ObservableList<CryptoCurrency>(),
|
||||
limits = Limits(min: 0, max: 0),
|
||||
tradeState = ExchangeTradeStateInitial(),
|
||||
limitsState = LimitsInitialState(),
|
||||
@@ -138,7 +144,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
receiveAddress = '';
|
||||
depositAddress =
|
||||
depositCurrency == wallet.currency ? wallet.walletAddresses.addressForExchange : '';
|
||||
provider = providersForCurrentPair().first;
|
||||
|
||||
provider = providerList.firstOrNull;
|
||||
final initialProvider = provider;
|
||||
provider!.checkIsAvailable().then((bool isAvailable) {
|
||||
if (!isAvailable && provider == initialProvider) {
|
||||
@@ -149,10 +156,16 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
});
|
||||
receiveCurrencies = CryptoCurrency.all
|
||||
.where((cryptoCurrency) => !excludeReceiveCurrencies.contains(cryptoCurrency))
|
||||
.toList();
|
||||
.toList()
|
||||
.asObservable();
|
||||
depositCurrencies = CryptoCurrency.all
|
||||
.where((cryptoCurrency) => !excludeDepositCurrencies.contains(cryptoCurrency))
|
||||
.toList();
|
||||
.toList()
|
||||
.asObservable();
|
||||
|
||||
_injectUserEthTokensIntoCurrencyLists();
|
||||
_injectUserSplTokensIntoCurrencyLists();
|
||||
_injectUserTronTokensIntoCurrencyLists();
|
||||
_defineIsReceiveAmountEditable();
|
||||
loadLimits();
|
||||
reaction((_) => isFixedRateMode, (Object _) {
|
||||
@@ -165,8 +178,12 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
}
|
||||
|
||||
bool get isElectrumWallet =>
|
||||
[WalletType.bitcoin, WalletType.litecoin, WalletType.bitcoinCash,WalletType.dogecoin ].contains(wallet.type);
|
||||
bool get isElectrumWallet => [
|
||||
WalletType.bitcoin,
|
||||
WalletType.litecoin,
|
||||
WalletType.bitcoinCash,
|
||||
WalletType.dogecoin
|
||||
].contains(wallet.type);
|
||||
|
||||
bool get hideAddressAfterExchange =>
|
||||
[WalletType.monero, WalletType.wownero].contains(wallet.type);
|
||||
@@ -320,9 +337,11 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
bool get isMoneroWallet => wallet.type == WalletType.monero;
|
||||
|
||||
List<CryptoCurrency> receiveCurrencies;
|
||||
@observable
|
||||
ObservableList<CryptoCurrency> receiveCurrencies;
|
||||
|
||||
List<CryptoCurrency> depositCurrencies;
|
||||
@observable
|
||||
ObservableList<CryptoCurrency> depositCurrencies;
|
||||
|
||||
final NumberFormat _cryptoNumberFormat;
|
||||
|
||||
@@ -334,6 +353,8 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
final FeesViewModel feesViewModel;
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
|
||||
@observable
|
||||
double bestRate = 0.0;
|
||||
|
||||
@@ -490,7 +511,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
|
||||
try {
|
||||
final futures = selectedProviders
|
||||
.where((provider) => providersForCurrentPair().contains(provider))
|
||||
.where((provider) => providerList.contains(provider))
|
||||
.map((provider) async {
|
||||
final limits = await provider
|
||||
.fetchLimits(
|
||||
@@ -717,16 +738,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
void removeTemplate({required ExchangeTemplate template}) =>
|
||||
_exchangeTemplateStore.remove(template: template);
|
||||
|
||||
List<ExchangeProvider> providersForCurrentPair() =>
|
||||
_providersForPair(from: depositCurrency, to: receiveCurrency);
|
||||
|
||||
List<ExchangeProvider> _providersForPair(
|
||||
{required CryptoCurrency from, required CryptoCurrency to}) =>
|
||||
providerList
|
||||
.where((provider) =>
|
||||
provider.pairList.where((pair) => pair.from == from && pair.to == to).isNotEmpty)
|
||||
.toList();
|
||||
|
||||
void _onPairChange() {
|
||||
depositAmount = '';
|
||||
receiveAmount = '';
|
||||
@@ -819,7 +830,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
@action
|
||||
void addExchangeProvider(ExchangeProvider provider) {
|
||||
selectedProviders.add(provider);
|
||||
if (providersForCurrentPair().contains(provider)) _tradeAvailableProviders.add(provider);
|
||||
if (providerList.contains(provider)) _tradeAvailableProviders.add(provider);
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -863,16 +874,15 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
|
||||
bool get isAvailableInSelected {
|
||||
final providersForPair = providersForCurrentPair();
|
||||
return selectedProviders
|
||||
.any((element) => element.isAvailable && providersForPair.contains(element));
|
||||
.any((element) => element.isAvailable && providerList.contains(element));
|
||||
}
|
||||
|
||||
void _setAvailableProviders() {
|
||||
_tradeAvailableProviders.clear();
|
||||
|
||||
_tradeAvailableProviders.addAll(
|
||||
selectedProviders.where((provider) => providersForCurrentPair().contains(provider)));
|
||||
selectedProviders.where((provider) => providerList.contains(provider)));
|
||||
}
|
||||
|
||||
void _setProviders() {
|
||||
@@ -989,7 +999,185 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||
}
|
||||
}
|
||||
|
||||
double initialAmountByAssets (CryptoCurrency ticker) {
|
||||
// Adding user's Erc20 tokens to the list of currencies
|
||||
|
||||
Future<Box<Erc20Token>> _openEvmTokensBoxFor(WalletInfo walletInfo) async {
|
||||
final walletKey = walletInfo.name.replaceAll(" ", "_");
|
||||
|
||||
final boxName = switch (walletInfo.type) {
|
||||
WalletType.ethereum => '${walletKey}_${Erc20Token.ethereumBoxName}',
|
||||
WalletType.polygon => '${walletKey}_${Erc20Token.polygonBoxName}',
|
||||
_ => '${walletKey}_${Erc20Token.ethereumBoxName}',
|
||||
};
|
||||
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
return CakeHive.box<Erc20Token>(boxName);
|
||||
}
|
||||
return CakeHive.openBox<Erc20Token>(boxName);
|
||||
}
|
||||
|
||||
Future<List<Erc20Token>> _loadAllUniqueEvmTokens() async {
|
||||
final evmWallets = walletInfoSource.values.where(
|
||||
(w) => w.type == WalletType.ethereum || w.type == WalletType.polygon,
|
||||
);
|
||||
|
||||
final seen = <String>{};
|
||||
final unique = <Erc20Token>[];
|
||||
|
||||
for (final wallet in evmWallets) {
|
||||
final chain = wallet.type == WalletType.ethereum ? 'ETH' : 'POL';
|
||||
final box = await _openEvmTokensBoxFor(wallet);
|
||||
|
||||
for (final t in box.values.where((t) => t.enabled)) {
|
||||
final key = '$chain|${t.contractAddress.toLowerCase()}';
|
||||
if (seen.add(key)) {
|
||||
unique.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unique;
|
||||
}
|
||||
|
||||
|
||||
@action
|
||||
Future<void> _injectUserEthTokensIntoCurrencyLists() async {
|
||||
final userTokens = await _loadAllUniqueEvmTokens();
|
||||
|
||||
final toAddReceive = <CryptoCurrency>[];
|
||||
final toAddDeposit = <CryptoCurrency>[];
|
||||
|
||||
for (final token in userTokens) {
|
||||
if (!_listContainsToken(receiveCurrencies, token)) toAddReceive.add(token);
|
||||
if (!_listContainsToken(depositCurrencies, token)) toAddDeposit.add(token);
|
||||
}
|
||||
|
||||
if (toAddReceive.isNotEmpty) receiveCurrencies.addAll(toAddReceive);
|
||||
if (toAddDeposit.isNotEmpty) depositCurrencies.addAll(toAddDeposit);
|
||||
}
|
||||
|
||||
bool _listContainsToken(List<CryptoCurrency> list, Erc20Token token) {
|
||||
return list.any((item) {
|
||||
if (item is Erc20Token) {
|
||||
return item.contractAddress.toLowerCase() == token.contractAddress.toLowerCase();
|
||||
}
|
||||
return item.title.toUpperCase() == token.symbol.toUpperCase() &&
|
||||
(item.tag?.toUpperCase() == token.tag?.toUpperCase() || item.tag == null);
|
||||
});
|
||||
}
|
||||
|
||||
// Adding user's Solana tokens to the list of currencies
|
||||
|
||||
Future<Box<SPLToken>> _openSolTokensBoxFor(WalletInfo wallet) async {
|
||||
final boxName = '${wallet.name.replaceAll(" ", "_")}_${SPLToken.boxName}';
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
return CakeHive.box<SPLToken>(boxName);
|
||||
}
|
||||
return CakeHive.openBox<SPLToken>(boxName);
|
||||
}
|
||||
|
||||
Future<List<SPLToken>> _loadAllUniqueSolTokens() async {
|
||||
final solWallets = walletInfoSource.values.where((wallet) => wallet.type == WalletType.solana);
|
||||
final tokens = <SPLToken>[];
|
||||
|
||||
for (final wallet in solWallets) {
|
||||
final box = await _openSolTokensBoxFor(wallet);
|
||||
tokens.addAll(box.values.where((t) => t.enabled));
|
||||
}
|
||||
|
||||
final seen = <String>{};
|
||||
final unique = <SPLToken>[];
|
||||
for (final token in tokens) {
|
||||
final key = token.mintAddress.toLowerCase();
|
||||
if (!seen.contains(key)) {
|
||||
seen.add(key);
|
||||
unique.add(token);
|
||||
}
|
||||
}
|
||||
return unique;
|
||||
}
|
||||
|
||||
bool _listContainsSplToken(List<CryptoCurrency> list, SPLToken token) {
|
||||
return list.any((item) {
|
||||
if (item is SPLToken) {
|
||||
return item.mintAddress.toLowerCase() == token.mintAddress.toLowerCase();
|
||||
}
|
||||
return item.title.toUpperCase() == token.symbol.toUpperCase() &&
|
||||
(item.tag?.toUpperCase() == token.tag?.toUpperCase() || item.tag == null);
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> _injectUserSplTokensIntoCurrencyLists() async {
|
||||
final userTokens = await _loadAllUniqueSolTokens();
|
||||
|
||||
final toAddReceive = <CryptoCurrency>[];
|
||||
final toAddDeposit = <CryptoCurrency>[];
|
||||
|
||||
for (final token in userTokens) {
|
||||
if (!_listContainsSplToken(receiveCurrencies, token)) toAddReceive.add(token);
|
||||
if (!_listContainsSplToken(depositCurrencies, token)) toAddDeposit.add(token);
|
||||
}
|
||||
|
||||
if (toAddReceive.isNotEmpty) receiveCurrencies.addAll(toAddReceive);
|
||||
if (toAddDeposit.isNotEmpty) depositCurrencies.addAll(toAddDeposit);
|
||||
}
|
||||
|
||||
// Adding user's Tron tokens to the list of currencies
|
||||
|
||||
Future<Box<TronToken>> _openTronTokensBoxFor(WalletInfo walletInfo) async {
|
||||
final boxName = '${walletInfo.name.replaceAll(" ", "_")}_${TronToken.boxName}';
|
||||
if (CakeHive.isBoxOpen(boxName)) {
|
||||
return CakeHive.box<TronToken>(boxName);
|
||||
}
|
||||
return CakeHive.openBox<TronToken>(boxName);
|
||||
}
|
||||
|
||||
Future<List<TronToken>> _loadAllUniqueTronTokens() async {
|
||||
final tronWallets =
|
||||
walletInfoSource.values.where((w) => w.type == WalletType.tron);
|
||||
|
||||
final seen = <String>{};
|
||||
final unique = <TronToken>[];
|
||||
|
||||
for (final wallet in tronWallets) {
|
||||
final box = await _openTronTokensBoxFor(wallet);
|
||||
for (final t in box.values.where((t) => t.enabled)) {
|
||||
final key = t.contractAddress.toLowerCase();
|
||||
if (seen.add(key)) unique.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
return unique;
|
||||
}
|
||||
|
||||
bool _listContainsTronToken(List<CryptoCurrency> list, TronToken token) {
|
||||
return list.any((item) {
|
||||
if (item is TronToken) {
|
||||
return item.contractAddress.toLowerCase() == token.contractAddress.toLowerCase();
|
||||
}
|
||||
return item.title.toUpperCase() == token.symbol.toUpperCase() &&
|
||||
(item.tag?.toUpperCase() == token.tag?.toUpperCase() || item.tag == null);
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> _injectUserTronTokensIntoCurrencyLists() async {
|
||||
final userTokens = await _loadAllUniqueTronTokens();
|
||||
|
||||
final toAddReceive = <CryptoCurrency>[];
|
||||
final toAddDeposit = <CryptoCurrency>[];
|
||||
|
||||
for (final token in userTokens) {
|
||||
if (!_listContainsTronToken(receiveCurrencies, token)) toAddReceive.add(token);
|
||||
if (!_listContainsTronToken(depositCurrencies, token)) toAddDeposit.add(token);
|
||||
}
|
||||
|
||||
if (toAddReceive.isNotEmpty) receiveCurrencies.addAll(toAddReceive);
|
||||
if (toAddDeposit.isNotEmpty) depositCurrencies.addAll(toAddDeposit);
|
||||
}
|
||||
|
||||
double initialAmountByAssets(CryptoCurrency ticker) {
|
||||
final amount = switch (ticker) {
|
||||
CryptoCurrency.trx => 1000,
|
||||
CryptoCurrency.nano => 10,
|
||||
|
||||
@@ -24,6 +24,7 @@ import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -163,17 +164,22 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
items.add(
|
||||
DetailsListStatusItem(title: S.current.trade_details_state, value: trade.state.toString()));
|
||||
|
||||
items.add(TradeDetailsListCardItem.tradeDetails(
|
||||
id: trade.id,
|
||||
extraId: trade.extraId,
|
||||
createdAt: trade.createdAt != null ? dateFormat.format(trade.createdAt!) : '',
|
||||
from: trade.from,
|
||||
to: trade.to,
|
||||
onTap: (BuildContext context) {
|
||||
Clipboard.setData(ClipboardData(text: '${trade.id}'));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
));
|
||||
final tradeFrom = _safeFrom(trade);
|
||||
final tradeTo = _safeTo(trade);
|
||||
|
||||
if (tradeFrom != null && tradeTo != null) {
|
||||
items.add(TradeDetailsListCardItem.tradeDetails(
|
||||
id: trade.id,
|
||||
extraId: trade.extraId,
|
||||
createdAt: trade.createdAt != null ? dateFormat.format(trade.createdAt!) : '',
|
||||
from: tradeFrom,
|
||||
to: tradeTo,
|
||||
onTap: (context) {
|
||||
Clipboard.setData(ClipboardData(text: trade.id));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
items.add(StandartListItem(
|
||||
title: S.current.trade_details_provider, value: trade.provider.toString()));
|
||||
@@ -207,4 +213,22 @@ abstract class TradeDetailsViewModelBase with Store {
|
||||
launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
CryptoCurrency? _safeFrom(Trade trade) {
|
||||
try {
|
||||
final raw = trade.fromRaw;
|
||||
return raw >= 0 ? trade.from : trade.userCurrencyFrom;
|
||||
} catch (_) {
|
||||
return trade.userCurrencyFrom;
|
||||
}
|
||||
}
|
||||
|
||||
CryptoCurrency? _safeTo(Trade trade) {
|
||||
try {
|
||||
final raw = trade.toRaw;
|
||||
return raw >= 0 ? trade.to : trade.userCurrencyTo;
|
||||
} catch (_) {
|
||||
return trade.userCurrencyTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1113,11 +1113,11 @@ import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/spl_token.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
""";
|
||||
const solanaCWHeaders = """
|
||||
import 'package:cw_solana/spl_token.dart';
|
||||
import 'package:cw_solana/solana_wallet.dart';
|
||||
import 'package:cw_solana/solana_mnemonics.dart';
|
||||
import 'package:cw_solana/solana_wallet_service.dart';
|
||||
@@ -1199,6 +1199,7 @@ import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/tron_token.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
""";
|
||||
@@ -1209,7 +1210,6 @@ import 'package:cw_tron/tron_transaction_info.dart';
|
||||
import 'package:cw_tron/tron_wallet_creation_credentials.dart';
|
||||
|
||||
import 'package:cw_tron/tron_client.dart';
|
||||
import 'package:cw_tron/tron_token.dart';
|
||||
import 'package:cw_tron/tron_wallet.dart';
|
||||
import 'package:cw_tron/tron_wallet_service.dart';
|
||||
import 'package:cw_tron/default_tron_tokens.dart';
|
||||
|
||||
Reference in New Issue
Block a user