mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-30 14:15:52 +00:00
Merge branch 'simpleswap' into testing-exchange
# Conflicts: # pubspec.yaml
This commit is contained in:
commit
534034dcd3
77 changed files with 5393 additions and 5149 deletions
25
assets/svg/exchange_icons/change_now_logo_1.svg
Normal file
25
assets/svg/exchange_icons/change_now_logo_1.svg
Normal file
|
@ -0,0 +1,25 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5027_35188)">
|
||||
<path d="M24 0H0V24H24V0Z" fill="url(#paint0_linear_5027_35188)"/>
|
||||
<path d="M4.20841 17.352C4.20841 16.032 4.20841 14.72 4.20841 13.384C4.23241 13.408 4.24841 13.432 4.25641 13.448C4.53641 13.872 4.82441 14.288 5.10441 14.712C5.68841 15.576 6.28041 16.448 6.86441 17.304C6.88841 17.352 6.92841 17.368 6.97641 17.368C7.20841 17.368 7.44041 17.368 7.68041 17.368C7.70441 17.368 7.72041 17.368 7.74441 17.368C7.74441 15.752 7.74441 14.152 7.74441 12.544C7.52841 12.544 7.30441 12.544 7.08841 12.544C7.08841 13.864 7.08841 15.176 7.08841 16.496C7.06441 16.48 7.04841 16.472 7.04041 16.456C6.17641 15.16 5.32041 13.872 4.45641 12.584C4.43241 12.544 4.40841 12.536 4.36841 12.536C4.12841 12.536 3.87241 12.536 3.63241 12.536C3.60841 12.536 3.59241 12.536 3.56841 12.536C3.56841 14.152 3.56841 15.752 3.56841 17.352C3.76841 17.352 3.99241 17.352 4.20841 17.352ZM5.95241 6.52002C5.95241 7.86402 5.95241 9.20002 5.95241 10.544C6.11241 10.544 6.26441 10.544 6.44041 10.544C6.44041 10.52 6.44041 10.496 6.44041 10.472C6.44041 10.072 6.44041 9.65602 6.44041 9.25602C6.44041 9.16802 6.45641 9.07202 6.46441 8.99202C6.52841 8.64002 6.77641 8.42402 7.12041 8.42402C7.40041 8.42402 7.60841 8.56802 7.68041 8.84002C7.70441 8.92802 7.70441 9.02402 7.72041 9.12002C7.72041 9.58402 7.72041 10.04 7.72041 10.504C7.72041 10.528 7.72041 10.552 7.72041 10.576C7.88841 10.576 8.03241 10.576 8.20841 10.576C8.20841 10.552 8.20841 10.536 8.20841 10.512C8.20841 10 8.20841 9.48002 8.20841 8.96802C8.20841 8.88002 8.20841 8.80002 8.18441 8.71202C8.13641 8.42402 7.99241 8.19202 7.71241 8.05602C7.52041 7.96802 7.29641 7.94402 7.08041 7.98402C6.81641 8.03202 6.59241 8.15202 6.44841 8.40002H6.43241C6.43241 7.78402 6.43241 7.15202 6.43241 6.53602C6.27241 6.52002 6.11241 6.52002 5.95241 6.52002ZM14.1044 10.544C14.1044 10.52 14.1044 10.504 14.1044 10.496C14.1044 9.97602 14.1044 9.45602 14.1044 8.92802C14.1044 8.85602 14.1044 8.78402 14.0884 8.71202C14.0484 8.47202 13.9444 8.26402 13.7364 8.12002C13.4244 7.90402 12.9124 7.91202 12.5844 8.14402C12.4884 8.21602 12.4164 8.30402 12.3444 8.40002C12.3444 8.28002 12.3444 8.16002 12.3444 8.02402C12.2564 8.02402 12.1764 8.02402 12.1044 8.02402C12.0324 8.02402 11.9444 8.02402 11.8724 8.02402C11.8724 8.87202 11.8724 9.71202 11.8724 10.544C12.0324 10.544 12.1844 10.544 12.3444 10.544C12.3444 10.52 12.3444 10.496 12.3444 10.472C12.3444 10.072 12.3444 9.68002 12.3444 9.28002C12.3444 9.19202 12.3444 9.12002 12.3604 9.04002C12.4004 8.68002 12.6164 8.44802 12.9684 8.40802C13.2484 8.36802 13.4884 8.48002 13.5764 8.74402C13.6164 8.85602 13.6244 8.96002 13.6244 9.08002C13.6244 9.54402 13.6244 9.99202 13.6244 10.448C13.6244 10.472 13.6244 10.496 13.6244 10.52C13.7844 10.544 13.9444 10.544 14.1044 10.544ZM5.08841 9.88002C5.07241 9.89602 5.06441 9.92002 5.04841 9.92802C4.72041 10.28 4.08041 10.216 3.82441 9.80802C3.65641 9.54402 3.64041 9.26402 3.72841 8.96802C3.91241 8.33602 4.57641 8.28802 4.92841 8.54402C4.99241 8.59202 5.04041 8.63202 5.09641 8.68002C5.21641 8.56802 5.33641 8.46402 5.44841 8.35202C5.05641 7.88002 4.11241 7.78402 3.56841 8.28002C3.03241 8.76802 3.02441 9.76002 3.52841 10.248C4.07241 10.768 5.05641 10.688 5.43241 10.208C5.33641 10.112 5.22441 10 5.08841 9.88002Z" fill="#FAFDFC"/>
|
||||
<path d="M4.20873 17.3521C3.97673 17.3521 3.76873 17.3521 3.55273 17.3521C3.55273 15.7521 3.55273 14.1361 3.55273 12.5361C3.57673 12.5361 3.59273 12.5361 3.61673 12.5361C3.85673 12.5361 4.11273 12.5361 4.35273 12.5361C4.40073 12.5361 4.42473 12.5521 4.44073 12.5841C5.31273 13.8721 6.17673 15.1521 7.03273 16.4401C7.04873 16.4561 7.05673 16.4641 7.08073 16.4801C7.08073 15.1681 7.08073 13.8481 7.08073 12.5281C7.29673 12.5281 7.52073 12.5281 7.73673 12.5281C7.73673 14.1281 7.73673 15.7441 7.73673 17.3521C7.71273 17.3521 7.69673 17.3521 7.67273 17.3521C7.44073 17.3521 7.20873 17.3521 6.96873 17.3521C6.92073 17.3521 6.88073 17.3361 6.85673 17.2881C6.27273 16.4241 5.68873 15.5521 5.09673 14.6961C4.81673 14.2721 4.52873 13.8561 4.24873 13.4321C4.23273 13.4161 4.22473 13.3921 4.20073 13.3681C4.20873 14.7201 4.20873 16.0241 4.20873 17.3521Z" fill="#01C16B"/>
|
||||
<path d="M5.95234 6.52002C6.11234 6.52002 6.26434 6.52002 6.42434 6.52002C6.42434 7.13602 6.42434 7.76802 6.42434 8.38402C6.44034 8.38402 6.44034 8.38402 6.44034 8.38402C6.57634 8.14402 6.79234 8.00802 7.07234 7.96802C7.28834 7.92802 7.49634 7.94402 7.70434 8.04002C7.98434 8.16002 8.12834 8.39202 8.17634 8.69602C8.19234 8.78402 8.20034 8.86402 8.20034 8.95202C8.20034 9.46402 8.20034 9.98402 8.20034 10.496C8.20034 10.52 8.20034 10.536 8.20034 10.56C8.04034 10.56 7.88834 10.56 7.71234 10.56C7.71234 10.536 7.71234 10.512 7.71234 10.488C7.71234 10.024 7.71234 9.56802 7.71234 9.10402C7.71234 9.00802 7.69634 8.91202 7.67234 8.82402C7.60034 8.56002 7.40834 8.40802 7.11234 8.40802C6.76034 8.40802 6.52034 8.62402 6.45634 8.97602C6.44034 9.06402 6.43234 9.16002 6.43234 9.24002C6.43234 9.64002 6.43234 10.056 6.43234 10.456C6.43234 10.48 6.43234 10.504 6.43234 10.528C6.27234 10.528 6.12034 10.528 5.94434 10.528C5.95234 9.20002 5.95234 7.86402 5.95234 6.52002Z" fill="#FAFDFC"/>
|
||||
<path d="M14.1049 10.544C13.9449 10.544 13.7929 10.544 13.6329 10.544C13.6329 10.52 13.6329 10.496 13.6329 10.472C13.6329 10.008 13.6329 9.56001 13.6329 9.10401C13.6329 8.99201 13.6169 8.87201 13.5849 8.76801C13.4889 8.50401 13.2569 8.39201 12.9769 8.43201C12.6249 8.47201 12.4169 8.69601 12.3689 9.06401C12.3529 9.15201 12.3529 9.22401 12.3529 9.30401C12.3529 9.70401 12.3529 10.096 12.3529 10.496C12.3529 10.52 12.3529 10.544 12.3529 10.568C12.1929 10.568 12.0409 10.568 11.8809 10.568C11.8809 9.72801 11.8809 8.89601 11.8809 8.04801C11.9529 8.04801 12.0409 8.04801 12.1129 8.04801C12.1849 8.04801 12.2729 8.04801 12.3529 8.04801C12.3529 8.16801 12.3529 8.30401 12.3529 8.42401C12.4249 8.32801 12.4969 8.23201 12.5929 8.16801C12.9209 7.93601 13.4329 7.92801 13.7449 8.14401C13.9529 8.28801 14.0569 8.49601 14.0969 8.73601C14.1129 8.80801 14.1129 8.88001 14.1129 8.95201C14.1129 9.47201 14.1129 9.99201 14.1129 10.52C14.1049 10.512 14.1049 10.52 14.1049 10.544Z" fill="#FAFDFC"/>
|
||||
<path d="M5.08837 9.88005C5.20837 10.0001 5.32837 10.1201 5.44037 10.2321C5.06437 10.6961 4.08037 10.7761 3.53637 10.2721C3.02437 9.78405 3.04037 8.79205 3.57637 8.30405C4.12037 7.80805 5.06437 7.91205 5.45637 8.37605C5.33637 8.48805 5.21637 8.59205 5.10437 8.70405C5.04037 8.65605 4.99237 8.60805 4.93637 8.56805C4.58437 8.31205 3.92037 8.36005 3.73637 8.99205C3.64837 9.28005 3.66437 9.56005 3.83237 9.83205C4.08837 10.2481 4.72837 10.3041 5.05637 9.95205C5.06437 9.91205 5.08037 9.88805 5.08837 9.88005Z" fill="#FAFDFC"/>
|
||||
<path d="M20.8323 12.544C20.7843 12.688 20.7443 12.832 20.6963 12.984C20.2723 14.424 19.8563 15.872 19.4323 17.312C19.4163 17.352 19.4083 17.36 19.3683 17.36C19.1763 17.36 18.9763 17.36 18.7843 17.36C18.7363 17.36 18.7203 17.344 18.7123 17.296C18.5043 16.592 18.2883 15.88 18.0803 15.176C17.9123 14.608 17.7443 14.032 17.5683 13.464C17.5683 13.448 17.5523 13.44 17.5443 13.416C17.5203 13.512 17.4803 13.6 17.4563 13.68C17.1043 14.896 16.7443 16.096 16.3923 17.304C16.3763 17.352 16.3523 17.368 16.3043 17.368C16.1123 17.368 15.9123 17.368 15.7363 17.368C15.6883 17.368 15.6723 17.352 15.6643 17.32C15.3603 16.288 15.0563 15.256 14.7683 14.224C14.6083 13.688 14.4563 13.16 14.3043 12.624C14.2883 12.6 14.2883 12.576 14.2803 12.552C14.2963 12.552 14.3043 12.552 14.3203 12.552C14.5283 12.552 14.7203 12.552 14.9283 12.552C14.9683 12.552 14.9763 12.576 14.9923 12.6C15.1363 13.144 15.2963 13.688 15.4403 14.224C15.6323 14.928 15.8323 15.64 16.0243 16.344C16.0243 16.36 16.0403 16.384 16.0483 16.408C16.4403 15.112 16.8163 13.824 17.1923 12.536C17.3363 12.536 17.4803 12.536 17.6323 12.536C17.7203 12.536 17.8163 12.536 17.8963 12.536C17.9363 12.536 17.9443 12.552 17.9603 12.584C18.0803 13 18.2003 13.408 18.3203 13.824C18.5603 14.664 18.8163 15.512 19.0563 16.344C19.0563 16.36 19.0723 16.368 19.0803 16.392C19.1283 16.208 19.1763 16.032 19.2243 15.848C19.5283 14.76 19.8323 13.68 20.1203 12.584C20.1363 12.544 20.1443 12.52 20.1923 12.52C20.4083 12.536 20.6243 12.536 20.8323 12.544C20.8323 12.536 20.8323 12.536 20.8323 12.544Z" fill="#01C16B"/>
|
||||
<path d="M16.9685 8.02398C16.9685 8.13598 16.9685 8.25598 16.9685 8.35998C16.7365 8.09598 16.4565 7.95998 16.1205 7.95998C15.6485 7.94398 15.2725 8.11998 15.0165 8.51998C14.8325 8.79998 14.7845 9.10398 14.8085 9.43198C14.8325 9.71198 14.9285 9.95198 15.1125 10.16C15.4165 10.488 15.7925 10.624 16.2245 10.576C16.4805 10.536 16.6965 10.456 16.8645 10.264C16.9045 10.224 16.9285 10.192 16.9605 10.144C16.9765 10.16 16.9765 10.16 16.9765 10.168C16.9765 10.328 16.9765 10.48 16.9605 10.64C16.9445 10.848 16.8725 11.032 16.7205 11.16C16.5765 11.28 16.4085 11.344 16.2085 11.368C15.8965 11.408 15.6165 11.344 15.3605 11.152C15.2885 11.088 15.2245 11.032 15.1525 10.968C15.0405 11.104 14.9365 11.232 14.8245 11.368C14.9605 11.504 15.1125 11.608 15.2885 11.68C15.5685 11.8 15.8565 11.84 16.1525 11.824C16.4645 11.808 16.7445 11.728 16.9925 11.536C17.3205 11.272 17.4565 10.92 17.4565 10.504C17.4565 9.70398 17.4565 8.88798 17.4565 8.08798C17.4565 8.06398 17.4565 8.04798 17.4565 8.02398C17.2805 8.02398 17.1205 8.02398 16.9685 8.02398ZM16.5765 10.024C16.2885 10.192 15.7125 10.192 15.4485 9.79198C15.2325 9.46398 15.2645 8.90398 15.5445 8.63998C15.8005 8.39998 16.0885 8.35198 16.4165 8.44798C16.7445 8.55998 16.9125 8.80798 16.9525 9.13598C16.9685 9.18398 16.9685 9.23198 16.9685 9.27198C16.9685 9.59998 16.8565 9.85598 16.5765 10.024Z" fill="#FAFDFC"/>
|
||||
<path d="M20.6483 9.45604C20.6483 9.36804 20.6643 9.27204 20.6323 9.17604C20.6163 8.89604 20.5603 8.63204 20.3923 8.40004C20.1603 8.08804 19.8323 7.93604 19.4483 7.93604C18.9843 7.93604 18.6083 8.10404 18.3443 8.49604C18.1283 8.82404 18.0803 9.18404 18.1523 9.57604C18.2003 9.83204 18.3123 10.064 18.4883 10.24C18.6963 10.448 18.9523 10.568 19.2403 10.592C19.6883 10.64 20.0883 10.544 20.4163 10.216C20.4643 10.176 20.5043 10.128 20.5363 10.08C20.4163 9.98404 20.2963 9.89604 20.1763 9.80004C20.1603 9.82404 20.1363 9.84004 20.1283 9.86404C19.9363 10.072 19.7043 10.2 19.4163 10.176C19.0883 10.152 18.8323 10.008 18.6883 9.70404C18.6483 9.61604 18.6403 9.53604 18.6403 9.44804C18.9763 9.44804 19.3043 9.44804 19.6483 9.44804C19.9923 9.44804 20.3123 9.45604 20.6483 9.45604ZM18.7443 8.70404C18.9603 8.36804 19.4003 8.24004 19.7603 8.41604C19.9763 8.52804 20.1363 8.76804 20.1203 9.07204C19.6243 9.07204 19.1283 9.07204 18.6323 9.07204C18.6403 8.92804 18.6883 8.80804 18.7443 8.70404Z" fill="#FAFDFC"/>
|
||||
<path d="M9.3285 8.60791C9.3125 8.62391 9.3125 8.62391 9.3125 8.62391C9.3285 8.61591 9.3285 8.61591 9.3285 8.60791Z" fill="#FAFDFC"/>
|
||||
<path d="M11.0967 9.90397C11.0807 9.51197 11.0967 9.11197 11.0807 8.72797C11.0647 8.43997 10.9207 8.20797 10.6567 8.08797C10.1607 7.85597 9.68866 7.91997 9.22466 8.17597C9.15266 8.21597 9.08866 8.27197 9.00866 8.33597C9.12866 8.43197 9.22466 8.52797 9.32066 8.61597C9.36066 8.59997 9.39266 8.57597 9.44066 8.55197C9.65666 8.38397 9.91266 8.31997 10.1927 8.36797C10.5047 8.41597 10.6807 8.69597 10.6327 8.98397C10.6087 8.98397 10.5847 8.98397 10.5607 8.98397C10.3687 8.98397 10.1847 8.98397 9.99266 8.99997C9.73666 9.02397 9.49666 9.07197 9.28066 9.20797C9.07266 9.32797 8.94466 9.51197 8.92066 9.76797C8.88066 10.12 9.05666 10.424 9.36866 10.544C9.53666 10.616 9.72066 10.632 9.90466 10.616C10.2167 10.592 10.4727 10.472 10.6567 10.2C10.6727 10.184 10.6727 10.176 10.6727 10.16L10.6887 10.176C10.6887 10.296 10.7047 10.416 10.7047 10.536C10.8487 10.536 10.9927 10.536 11.1287 10.536C11.1047 10.312 11.0967 10.112 11.0967 9.90397ZM10.6247 9.48797C10.6247 9.50397 10.6247 9.51197 10.6247 9.52797C10.6247 9.55197 10.6247 9.57597 10.6087 9.59997C10.6087 9.61597 10.6087 9.61597 10.6087 9.62397C10.6087 9.63997 10.6087 9.64797 10.5927 9.67197C10.5687 9.81597 10.5047 9.95197 10.3847 10.048C10.2407 10.184 10.0727 10.208 9.88866 10.208C9.86466 10.208 9.82466 10.208 9.80066 10.208C9.68866 10.208 9.58466 10.184 9.49666 10.12C9.28866 9.97597 9.30466 9.67197 9.49666 9.51197C9.60866 9.42397 9.73666 9.39197 9.85666 9.36797C9.99266 9.34397 10.2487 9.32797 10.4407 9.32797C10.5047 9.32797 10.5607 9.32797 10.6087 9.32797C10.6087 9.36797 10.6087 9.39997 10.6087 9.42397C10.6247 9.45597 10.6247 9.47997 10.6247 9.48797Z" fill="#FAFDFC"/>
|
||||
<path d="M13.6409 13.968C13.4089 13.336 12.9609 12.88 12.3289 12.608C11.8569 12.416 11.3689 12.368 10.8729 12.44C10.3849 12.512 9.96086 12.704 9.60086 13.032C9.27286 13.336 9.05686 13.688 8.92086 14.096C8.80086 14.488 8.76086 14.888 8.80886 15.288C8.89686 15.976 9.20086 16.552 9.74486 16.976C10.2089 17.328 10.7289 17.488 11.3129 17.488C11.4249 17.472 11.5209 17.472 11.6009 17.464C12.4169 17.376 13.0569 16.992 13.4649 16.272C13.8969 15.528 13.9369 14.752 13.6409 13.968ZM13.1369 15.12C13.1369 15.144 13.1369 15.16 13.1209 15.184C13.1049 15.328 13.0809 15.472 13.0329 15.608C12.9449 15.872 12.8249 16.104 12.6169 16.32C12.2649 16.696 11.8169 16.88 11.2969 16.88C10.7849 16.864 10.3609 16.696 10.0089 16.336C9.77686 16.096 9.63286 15.8 9.56086 15.488C9.52086 15.304 9.49686 15.136 9.47286 14.952V14.936C9.47286 14.952 9.47286 14.952 9.48886 14.952C9.48886 14.512 9.60086 14.104 9.86486 13.752C10.1529 13.352 10.5529 13.112 11.0569 13.048C11.3449 13.008 11.6409 13.032 11.9289 13.136C12.2649 13.256 12.5449 13.472 12.7689 13.768C13.0249 14.12 13.1289 14.52 13.1289 14.944C13.1449 14.992 13.1369 15.056 13.1369 15.12Z" fill="#01C16B"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_5027_35188" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="4.52862e-07" stop-color="#3A3A51"/>
|
||||
<stop offset="1" stop-color="#191927"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_5027_35188">
|
||||
<rect width="24" height="24" rx="4" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 14 KiB |
5
assets/svg/exchange_icons/simpleswap-icon.svg
Normal file
5
assets/svg/exchange_icons/simpleswap-icon.svg
Normal file
|
@ -0,0 +1,5 @@
|
|||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.55104 16.4654C5.53144 16.5046 5.51184 16.5439 5.49224 16.5831C5.29624 17.0541 5.19824 17.5643 5.19824 18.0745C5.19824 18.5847 5.29624 19.095 5.49224 19.5659C5.68824 20.0369 5.98224 20.4686 6.35464 20.8219C6.72704 21.1751 7.15824 21.4695 7.62864 21.6657C8.09904 21.8619 8.62824 21.96 9.13784 21.96C9.64744 21.96 10.1766 21.8619 10.647 21.6657C11.1174 21.4695 11.5682 21.1751 11.921 20.8219L19.1926 13.6395C19.957 12.8938 20.3686 11.8734 20.3686 10.8137C20.3686 9.87174 20.0746 8.94942 19.4278 8.22334C19.1142 8.08597 18.7614 8.04672 18.4086 8.10559C18.095 8.16447 17.8206 8.34108 17.5854 8.55694L10.7058 15.5823C10.5686 15.7197 10.4314 15.8178 10.2746 15.8963C10.353 15.8374 10.451 15.7982 10.5294 15.7393H10.5098C10.5098 15.7393 10.5294 15.7393 10.5294 15.7197C10.5294 15.7197 10.549 15.7197 10.549 15.7C10.5294 15.7 10.5294 15.7197 10.5098 15.7197C9.47104 16.4065 8.21664 16.7597 6.96224 16.6812C6.47224 16.6812 6.00184 16.6027 5.55104 16.4654Z" fill="#104ADE"/>
|
||||
<path d="M10.5122 15.739C10.5318 15.739 10.5318 15.7194 10.5514 15.7194C10.277 15.8175 10.0026 15.8567 9.7086 15.8371C9.4146 15.7979 9.1598 15.6997 8.9246 15.5428C8.709 15.4054 8.5522 15.2091 8.415 14.9933C8.2974 14.7774 8.219 14.5419 8.1798 14.2868C8.1602 14.0317 8.1994 13.7766 8.2778 13.5411C8.3562 13.3056 8.4934 13.0898 8.6698 12.9132L10.963 10.6172L14.3146 7.30072C14.3146 7.30072 14.3146 7.30072 14.3342 7.2811L14.3538 7.26147L14.8634 6.77088C15.1182 6.71201 15.373 6.69238 15.6474 6.69238C16.2354 6.69238 16.745 6.75125 17.235 6.88862C17.9602 7.04561 18.6266 7.39884 19.1558 7.92869C19.2538 8.02681 19.3518 8.12493 19.4302 8.24267C19.1166 8.1053 18.7442 8.06605 18.411 8.12493C18.0974 8.1838 17.823 8.36041 17.5878 8.57627L10.7082 15.582C10.571 15.7194 10.4338 15.8175 10.277 15.896C10.3554 15.8371 10.4534 15.7979 10.5318 15.739C10.5122 15.739 10.5122 15.739 10.5122 15.739Z" fill="#0038C7"/>
|
||||
<path d="M16.0775 2.43415C15.9011 2.00243 15.6267 1.59033 15.2739 1.25672C14.8819 0.864242 14.4115 0.55026 13.9019 0.354021C13.3923 0.138158 12.8435 0.0400391 12.2751 0.0400391C11.7263 0.0400391 11.1579 0.157782 10.6483 0.354021C10.1387 0.569884 9.66834 0.864242 9.27634 1.25672L3.29834 7.16351C2.23994 8.20357 1.65194 9.59687 1.63234 11.0687C1.61274 12.5404 2.16154 13.9534 3.18074 15.0327L3.23954 15.0916L3.29834 15.1504C3.35714 15.2093 3.41594 15.2682 3.47474 15.3074C4.43514 16.1316 5.65034 16.6222 6.92434 16.7007C8.19834 16.7792 9.47234 16.426 10.5111 15.7195C10.2367 15.8176 9.96234 15.8569 9.66834 15.8373C9.37434 15.798 9.11954 15.6999 8.88434 15.5429C8.66874 15.4055 8.51194 15.2093 8.37474 14.9934C8.25714 14.7776 8.17874 14.5421 8.13954 14.287C8.11994 14.0319 8.15914 13.7768 8.23754 13.5413C8.31594 13.3058 8.45314 13.0899 8.62954 12.9133L10.9227 10.6173L14.2743 7.30087C14.2939 7.28125 14.2939 7.28125 14.3135 7.26163L15.2151 6.35893C15.7247 5.84871 16.0775 5.20112 16.2147 4.51428C16.4303 3.82745 16.3519 3.10136 16.0775 2.43415Z" fill="#0F75FC"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3 KiB |
|
@ -4,6 +4,7 @@ import 'package:cw_core/wallet_info.dart' as xmr;
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/models/notification_model.dart';
|
||||
import 'package:stackwallet/models/trade_wallet_lookup.dart';
|
||||
|
@ -22,6 +23,7 @@ class DB {
|
|||
"watchedTxNotificationModels";
|
||||
static const String boxNameWatchedTrades = "watchedTradesNotificationModels";
|
||||
static const String boxNameTrades = "exchangeTransactionsBox";
|
||||
static const String boxNameTradesV2 = "exchangeTradesBox";
|
||||
static const String boxNameTradeNotes = "tradeNotesBox";
|
||||
static const String boxNameTradeLookup = "tradeToTxidLookUpBox";
|
||||
static const String boxNameFavoriteWallets = "favoriteWallets";
|
||||
|
@ -48,6 +50,7 @@ class DB {
|
|||
late final Box<NotificationModel> _boxWatchedTransactions;
|
||||
late final Box<NotificationModel> _boxWatchedTrades;
|
||||
late final Box<ExchangeTransaction> _boxTrades;
|
||||
late final Box<Trade> _boxTradesV2;
|
||||
late final Box<String> _boxTradeNotes;
|
||||
late final Box<String> _boxFavoriteWallets;
|
||||
late final Box<xmr.WalletInfo> _walletInfoSource;
|
||||
|
@ -125,6 +128,7 @@ class DB {
|
|||
_boxWatchedTrades =
|
||||
await Hive.openBox<NotificationModel>(boxNameWatchedTrades);
|
||||
_boxTrades = await Hive.openBox<ExchangeTransaction>(boxNameTrades);
|
||||
_boxTradesV2 = await Hive.openBox<Trade>(boxNameTradesV2);
|
||||
_boxTradeNotes = await Hive.openBox<String>(boxNameTradeNotes);
|
||||
_boxTradeLookup =
|
||||
await Hive.openBox<TradeWalletLookup>(boxNameTradeLookup);
|
||||
|
|
129
lib/main.dart
129
lib/main.dart
|
@ -18,12 +18,12 @@ import 'package:path_provider/path_provider.dart';
|
|||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/isar/models/log.dart';
|
||||
import 'package:stackwallet/models/models.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/models/notification_model.dart';
|
||||
import 'package:stackwallet/models/trade_wallet_lookup.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_view.dart';
|
||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
import 'package:stackwallet/pages/intro_view.dart';
|
||||
import 'package:stackwallet/pages/loading_view.dart';
|
||||
|
@ -31,13 +31,6 @@ import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart';
|
|||
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
|
||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
||||
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
||||
import 'package:stackwallet/providers/global/base_currencies_provider.dart';
|
||||
// import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart';
|
||||
|
@ -46,6 +39,8 @@ import 'package:stackwallet/providers/providers.dart';
|
|||
import 'package:stackwallet/providers/ui/color_theme_provider.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/debug_service.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||
import 'package:stackwallet/services/locale_service.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/notifications_api.dart';
|
||||
|
@ -124,6 +119,8 @@ void main() async {
|
|||
Hive.registerAdapter(ExchangeTransactionAdapter());
|
||||
Hive.registerAdapter(ExchangeTransactionStatusAdapter());
|
||||
|
||||
Hive.registerAdapter(TradeAdapter());
|
||||
|
||||
// reference lookup data adapter
|
||||
Hive.registerAdapter(TradeWalletLookupAdapter());
|
||||
|
||||
|
@ -225,7 +222,6 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
nodeService: _nodeService,
|
||||
tradesService: _tradesService,
|
||||
prefs: _prefs,
|
||||
changeNow: ref.read(changeNowProvider),
|
||||
);
|
||||
await _prefs.init();
|
||||
ref.read(priceAnd24hChangeNotifierProvider).start(true);
|
||||
|
@ -234,6 +230,11 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
// TODO: this should probably run unawaited. Keep commented out for now as proper community nodes ui hasn't been implemented yet
|
||||
// unawaited(_nodeService.updateCommunityNodes());
|
||||
|
||||
// run without awaiting
|
||||
if (Constants.enableExchange) {
|
||||
unawaited(ExchangeDataLoadingService().loadAll(ref));
|
||||
}
|
||||
|
||||
if (_prefs.isAutoBackupEnabled) {
|
||||
switch (_prefs.backupFrequencyType) {
|
||||
case BackupFrequencyType.everyTenMinutes:
|
||||
|
@ -251,112 +252,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _loadChangeNowStandardCurrencies() async {
|
||||
if (ref
|
||||
.read(availableChangeNowCurrenciesStateProvider.state)
|
||||
.state
|
||||
.isNotEmpty &&
|
||||
ref
|
||||
.read(availableFloatingRatePairsStateProvider.state)
|
||||
.state
|
||||
.isNotEmpty) {
|
||||
return;
|
||||
}
|
||||
final response = await ref.read(changeNowProvider).getAvailableCurrencies();
|
||||
final response2 =
|
||||
await ref.read(changeNowProvider).getAvailableFloatingRatePairs();
|
||||
if (response.value != null) {
|
||||
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
||||
response.value!;
|
||||
if (response2.value != null) {
|
||||
ref.read(availableFloatingRatePairsStateProvider.state).state =
|
||||
response2.value!;
|
||||
|
||||
if (response.value!.length > 1) {
|
||||
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
||||
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
||||
await ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
||||
response.value!.firstWhere((e) => e.ticker == "btc"), false);
|
||||
}
|
||||
}
|
||||
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
||||
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
||||
await ref.read(estimatedRateExchangeFormProvider).updateTo(
|
||||
response.value!.firstWhere((e) => e.ticker == "doge"), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Failed to load changeNOW available floating rate pairs: ${response2.exception?.errorMessage}",
|
||||
level: LogLevel.Error);
|
||||
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
|
||||
ChangeNowLoadStatus.failed;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Failed to load changeNOW currencies: ${response.exception?.errorMessage}",
|
||||
level: LogLevel.Error);
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
|
||||
ChangeNowLoadStatus.failed;
|
||||
return;
|
||||
}
|
||||
|
||||
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
|
||||
ChangeNowLoadStatus.success;
|
||||
}
|
||||
|
||||
Future<void> _loadFixedRateMarkets() async {
|
||||
Logging.instance.log("Starting initial fixed rate market data loading...",
|
||||
level: LogLevel.Info);
|
||||
if (ref.read(fixedRateMarketPairsStateProvider.state).state.isNotEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final response3 =
|
||||
await ref.read(changeNowProvider).getAvailableFixedRateMarkets();
|
||||
if (response3.value != null) {
|
||||
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
||||
response3.value!;
|
||||
|
||||
if (ref.read(fixedRateExchangeFormProvider).market == null) {
|
||||
final matchingMarkets =
|
||||
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
||||
if (matchingMarkets.isNotEmpty) {
|
||||
await ref
|
||||
.read(fixedRateExchangeFormProvider)
|
||||
.updateMarket(matchingMarkets.first, true);
|
||||
}
|
||||
}
|
||||
|
||||
Logging.instance.log("Initial fixed rate market data loading complete.",
|
||||
level: LogLevel.Info);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Failed to load changeNOW fixed rate markets: ${response3.exception?.errorMessage}",
|
||||
level: LogLevel.Error);
|
||||
|
||||
ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state =
|
||||
ChangeNowLoadStatus.failed;
|
||||
return;
|
||||
}
|
||||
|
||||
ref.read(changeNowFixedInitialLoadStatusStateProvider.state).state =
|
||||
ChangeNowLoadStatus.success;
|
||||
}
|
||||
|
||||
Future<void> _loadChangeNowData() async {
|
||||
List<Future<dynamic>> concurrentFutures = [];
|
||||
concurrentFutures.add(_loadChangeNowStandardCurrencies());
|
||||
if (kFixedRateEnabled) {
|
||||
concurrentFutures.add(_loadFixedRateMarkets());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
ref.read(exchangeFormStateProvider).exchange = ChangeNowExchange();
|
||||
final colorScheme = DB.instance
|
||||
.get<dynamic>(boxName: DB.boxNameTheme, key: "colorScheme") as String?;
|
||||
|
||||
|
@ -637,11 +535,6 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
if (_wallets.hasWallets || _prefs.hasPin) {
|
||||
// return HomeView();
|
||||
|
||||
// run without awaiting
|
||||
if (Constants.enableExchange) {
|
||||
_loadChangeNowData();
|
||||
}
|
||||
|
||||
String? startupWalletId;
|
||||
if (ref.read(prefsChangeNotifierProvider).gotoWalletOnStartup) {
|
||||
startupWalletId =
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class AvailableFloatingRatePair {
|
||||
final String fromTicker;
|
||||
final String toTicker;
|
||||
|
||||
AvailableFloatingRatePair({
|
||||
required this.fromTicker,
|
||||
required this.toTicker,
|
||||
});
|
||||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
return other is AvailableFloatingRatePair &&
|
||||
fromTicker == other.fromTicker &&
|
||||
toTicker == other.toTicker;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(fromTicker, toTicker);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "${fromTicker}_$toTicker";
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
enum ChangeNowExceptionType { generic, serializeResponseError }
|
||||
|
||||
class ChangeNowException implements Exception {
|
||||
String errorMessage;
|
||||
ChangeNowExceptionType type;
|
||||
ChangeNowException(this.errorMessage, this.type);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
class ChangeNowResponse<T> {
|
||||
late final T? value;
|
||||
late final ChangeNowException? exception;
|
||||
|
||||
ChangeNowResponse({this.value, this.exception});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "{ error: $exception, value: $value }";
|
||||
}
|
||||
}
|
24
lib/models/exchange/change_now/cn_available_currencies.dart
Normal file
24
lib/models/exchange/change_now/cn_available_currencies.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
|
||||
class CNAvailableCurrencies {
|
||||
final List<Currency> currencies = [];
|
||||
final List<Pair> pairs = [];
|
||||
final List<FixedRateMarket> markets = [];
|
||||
|
||||
void updateCurrencies(List<Currency> newCurrencies) {
|
||||
currencies.clear();
|
||||
currencies.addAll(newCurrencies);
|
||||
}
|
||||
|
||||
void updateFloatingPairs(List<Pair> newPairs) {
|
||||
pairs.clear();
|
||||
pairs.addAll(newPairs);
|
||||
}
|
||||
|
||||
void updateMarkets(List<FixedRateMarket> newMarkets) {
|
||||
markets.clear();
|
||||
markets.addAll(newMarkets);
|
||||
}
|
||||
}
|
|
@ -35,8 +35,10 @@ class EstimatedExchangeAmount {
|
|||
factory EstimatedExchangeAmount.fromJson(Map<String, dynamic> json) {
|
||||
try {
|
||||
return EstimatedExchangeAmount(
|
||||
estimatedAmount: Decimal.parse(json["estimatedAmount"].toString()),
|
||||
transactionSpeedForecast: json["transactionSpeedForecast"] as String,
|
||||
estimatedAmount: Decimal.parse(json["estimatedAmount"]?.toString() ??
|
||||
json["estimatedDeposit"].toString()),
|
||||
transactionSpeedForecast:
|
||||
json["transactionSpeedForecast"] as String? ?? "",
|
||||
warningMessage: json["warningMessage"] as String?,
|
||||
rateId: json["rateId"] as String?,
|
||||
networkFee: Decimal.tryParse(json["networkFee"].toString()),
|
||||
|
|
|
@ -5,6 +5,8 @@ import 'package:uuid/uuid.dart';
|
|||
|
||||
part '../../type_adaptors/exchange_transaction.g.dart';
|
||||
|
||||
@Deprecated(
|
||||
"Do not use. Migrated to Trade in db_version_migration to hive_data_version 2")
|
||||
// @HiveType(typeId: 13)
|
||||
class ExchangeTransaction {
|
||||
/// You can use it to get transaction status at the Transaction status API endpoint
|
||||
|
|
|
@ -1,282 +0,0 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class EstimatedRateExchangeFormState extends ChangeNotifier {
|
||||
/// used in testing to inject mock
|
||||
ChangeNow? cnTesting;
|
||||
|
||||
Decimal? _fromAmount;
|
||||
Decimal? _toAmount;
|
||||
|
||||
Decimal? _minFromAmount;
|
||||
Decimal? _minToAmount;
|
||||
|
||||
Decimal? rate;
|
||||
|
||||
Currency? _from;
|
||||
Currency? _to;
|
||||
|
||||
void Function(String)? _onError;
|
||||
|
||||
Currency? get from => _from;
|
||||
Currency? get to => _to;
|
||||
|
||||
String get fromAmountString =>
|
||||
_fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
|
||||
String get toAmountString =>
|
||||
_toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
|
||||
|
||||
String get rateDisplayString {
|
||||
if (rate == null || from == null || to == null) {
|
||||
return "N/A";
|
||||
} else {
|
||||
return "1 ${from!.ticker.toUpperCase()} ~${rate!.toStringAsFixed(8)} ${to!.ticker.toUpperCase()}";
|
||||
}
|
||||
}
|
||||
|
||||
bool get canExchange {
|
||||
return _fromAmount != null &&
|
||||
_fromAmount != Decimal.zero &&
|
||||
_toAmount != null &&
|
||||
rate != null &&
|
||||
minimumSendWarning.isEmpty;
|
||||
}
|
||||
|
||||
String get minimumSendWarning {
|
||||
if (_from != null &&
|
||||
_fromAmount != null &&
|
||||
_minFromAmount != null &&
|
||||
_fromAmount! < _minFromAmount!) {
|
||||
return "Minimum amount ${_minFromAmount!.toString()} ${from!.ticker.toUpperCase()}";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
Future<void> init(Currency? from, Currency? to) async {
|
||||
_from = from;
|
||||
_to = to;
|
||||
}
|
||||
|
||||
void clearAmounts(bool shouldNotifyListeners) {
|
||||
_fromAmount = null;
|
||||
_toAmount = null;
|
||||
_minFromAmount = null;
|
||||
_minToAmount = null;
|
||||
rate = null;
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> swap() async {
|
||||
final Decimal? newToAmount = _fromAmount;
|
||||
final Decimal? newFromAmount = _toAmount;
|
||||
|
||||
final Decimal? newMinFromAmount = _minToAmount;
|
||||
final Decimal? newMinToAmount = _minFromAmount;
|
||||
|
||||
final Currency? newTo = from;
|
||||
final Currency? newFrom = to;
|
||||
|
||||
_fromAmount = newFromAmount;
|
||||
_toAmount = newToAmount;
|
||||
|
||||
_minToAmount = newMinToAmount;
|
||||
_minFromAmount = newMinFromAmount;
|
||||
|
||||
// rate = newRate;
|
||||
|
||||
_to = newTo;
|
||||
_from = newFrom;
|
||||
|
||||
await _updateMinFromAmount(shouldNotifyListeners: false);
|
||||
|
||||
await updateRate();
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> updateTo(Currency to, bool shouldNotifyListeners) async {
|
||||
try {
|
||||
_to = to;
|
||||
if (_from == null) {
|
||||
rate = null;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
|
||||
|
||||
await updateRate(shouldNotifyListeners: shouldNotifyListeners);
|
||||
|
||||
debugPrint(
|
||||
"_updated TO: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateFrom(Currency from, bool shouldNotifyListeners) async {
|
||||
try {
|
||||
_from = from;
|
||||
|
||||
if (_to == null) {
|
||||
rate = null;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
await _updateMinFromAmount(shouldNotifyListeners: shouldNotifyListeners);
|
||||
|
||||
await updateRate(shouldNotifyListeners: shouldNotifyListeners);
|
||||
|
||||
debugPrint(
|
||||
"_updated FROM: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$_fromAmount _toAmount=$_toAmount rate:$rate");
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _updateMinFromAmount(
|
||||
{required bool shouldNotifyListeners}) async {
|
||||
_minFromAmount = await getStandardMinExchangeAmount(from: from!, to: to!);
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Future<void> setToAmountAndCalculateFromAmount(
|
||||
// Decimal newToAmount,
|
||||
// bool shouldNotifyListeners,
|
||||
// ) async {
|
||||
// if (newToAmount == Decimal.zero) {
|
||||
// _fromAmount = Decimal.zero;
|
||||
// }
|
||||
//
|
||||
// _toAmount = newToAmount;
|
||||
// await updateRate();
|
||||
// if (shouldNotifyListeners) {
|
||||
// notifyListeners();
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<void> setFromAmountAndCalculateToAmount(
|
||||
Decimal newFromAmount,
|
||||
bool shouldNotifyListeners,
|
||||
) async {
|
||||
if (newFromAmount == Decimal.zero) {
|
||||
_toAmount = Decimal.zero;
|
||||
}
|
||||
|
||||
_fromAmount = newFromAmount;
|
||||
await updateRate(shouldNotifyListeners: shouldNotifyListeners);
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<Decimal?> getStandardEstimatedToAmount({
|
||||
required Decimal fromAmount,
|
||||
required Currency from,
|
||||
required Currency to,
|
||||
}) async {
|
||||
final response =
|
||||
await (cnTesting ?? ChangeNow.instance).getEstimatedExchangeAmount(
|
||||
fromTicker: from.ticker,
|
||||
toTicker: to.ticker,
|
||||
fromAmount: fromAmount,
|
||||
);
|
||||
|
||||
if (response.value != null) {
|
||||
return response.value!.estimatedAmount;
|
||||
} else {
|
||||
_onError?.call(
|
||||
"Failed to fetch estimated amount: ${response.exception?.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Future<Decimal?> getStandardEstimatedFromAmount({
|
||||
// required Decimal toAmount,
|
||||
// required Currency from,
|
||||
// required Currency to,
|
||||
// }) async {
|
||||
// final response = await (cnTesting ?? ChangeNow.instance)
|
||||
// .getEstimatedExchangeAmount(
|
||||
// fromTicker: from.ticker,
|
||||
// toTicker: to.ticker,
|
||||
// fromAmount: toAmount, );
|
||||
//
|
||||
// if (response.value != null) {
|
||||
// return response.value!.fromAmount;
|
||||
// } else {
|
||||
// _onError?.call(
|
||||
// "Failed to fetch estimated amount: ${response.exception?.toString()}");
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
|
||||
Future<Decimal?> getStandardMinExchangeAmount({
|
||||
required Currency from,
|
||||
required Currency to,
|
||||
}) async {
|
||||
final response = await (cnTesting ?? ChangeNow.instance)
|
||||
.getMinimalExchangeAmount(fromTicker: from.ticker, toTicker: to.ticker);
|
||||
|
||||
if (response.value != null) {
|
||||
return response.value!;
|
||||
} else {
|
||||
_onError?.call(
|
||||
"Could not update minimal exchange amounts: ${response.exception?.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void setOnError({
|
||||
required void Function(String)? onError,
|
||||
bool shouldNotifyListeners = false,
|
||||
}) {
|
||||
_onError = onError;
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateRate({bool shouldNotifyListeners = false}) async {
|
||||
rate = null;
|
||||
final amount = _fromAmount;
|
||||
final minAmount = _minFromAmount;
|
||||
if (amount != null && amount > Decimal.zero) {
|
||||
Decimal? amt;
|
||||
if (minAmount != null) {
|
||||
if (minAmount <= amount) {
|
||||
amt = await getStandardEstimatedToAmount(
|
||||
fromAmount: amount, from: _from!, to: _to!);
|
||||
if (amt != null) {
|
||||
rate = (amt / amount).toDecimal(scaleOnInfinitePrecision: 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rate != null && amt != null) {
|
||||
_toAmount = amt;
|
||||
}
|
||||
}
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
400
lib/models/exchange/exchange_form_state.dart
Normal file
400
lib/models/exchange/exchange_form_state.dart
Normal file
|
@ -0,0 +1,400 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class ExchangeFormState extends ChangeNotifier {
|
||||
Exchange? _exchange;
|
||||
Exchange? get exchange => _exchange;
|
||||
set exchange(Exchange? value) {
|
||||
_exchange = value;
|
||||
_onExchangeTypeChanged();
|
||||
}
|
||||
|
||||
ExchangeRateType _exchangeType = ExchangeRateType.estimated;
|
||||
ExchangeRateType get exchangeType => _exchangeType;
|
||||
set exchangeType(ExchangeRateType value) {
|
||||
_exchangeType = value;
|
||||
_onExchangeRateTypeChanged();
|
||||
}
|
||||
|
||||
bool reversed = false;
|
||||
|
||||
Decimal? fromAmount;
|
||||
Decimal? toAmount;
|
||||
|
||||
Decimal? minAmount;
|
||||
Decimal? maxAmount;
|
||||
|
||||
Decimal? rate;
|
||||
Estimate? estimate;
|
||||
|
||||
FixedRateMarket? _market;
|
||||
FixedRateMarket? get market => _market;
|
||||
|
||||
Currency? _from;
|
||||
Currency? _to;
|
||||
|
||||
String? get fromTicker {
|
||||
switch (exchangeType) {
|
||||
case ExchangeRateType.estimated:
|
||||
return _from?.ticker;
|
||||
case ExchangeRateType.fixed:
|
||||
return _market?.from;
|
||||
}
|
||||
}
|
||||
|
||||
String? get toTicker {
|
||||
switch (exchangeType) {
|
||||
case ExchangeRateType.estimated:
|
||||
return _to?.ticker;
|
||||
case ExchangeRateType.fixed:
|
||||
return _market?.to;
|
||||
}
|
||||
}
|
||||
|
||||
void Function(String)? _onError;
|
||||
|
||||
Currency? get from => _from;
|
||||
Currency? get to => _to;
|
||||
|
||||
void setCurrencies(Currency from, Currency to) {
|
||||
_from = from;
|
||||
_to = to;
|
||||
}
|
||||
|
||||
String get warning {
|
||||
if (reversed) {
|
||||
if (toTicker != null && toAmount != null) {
|
||||
if (minAmount != null && toAmount! < minAmount!) {
|
||||
return "Minimum amount ${minAmount!.toString()} ${toTicker!.toUpperCase()}";
|
||||
} else if (maxAmount != null && toAmount! > maxAmount!) {
|
||||
return "Maximum amount ${maxAmount!.toString()} ${toTicker!.toUpperCase()}";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fromTicker != null && fromAmount != null) {
|
||||
if (minAmount != null && fromAmount! < minAmount!) {
|
||||
return "Minimum amount ${minAmount!.toString()} ${fromTicker!.toUpperCase()}";
|
||||
} else if (maxAmount != null && fromAmount! > maxAmount!) {
|
||||
return "Maximum amount ${maxAmount!.toString()} ${fromTicker!.toUpperCase()}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
String get fromAmountString => fromAmount?.toStringAsFixed(8) ?? "";
|
||||
String get toAmountString => toAmount?.toStringAsFixed(8) ?? "";
|
||||
|
||||
bool get canExchange {
|
||||
switch (exchangeType) {
|
||||
case ExchangeRateType.estimated:
|
||||
return fromAmount != null &&
|
||||
fromAmount != Decimal.zero &&
|
||||
toAmount != null &&
|
||||
rate != null &&
|
||||
warning.isEmpty;
|
||||
case ExchangeRateType.fixed:
|
||||
return _market != null &&
|
||||
fromAmount != null &&
|
||||
toAmount != null &&
|
||||
warning.isEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
void clearAmounts(bool shouldNotifyListeners) {
|
||||
fromAmount = null;
|
||||
toAmount = null;
|
||||
minAmount = null;
|
||||
maxAmount = null;
|
||||
rate = null;
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setFromAmountAndCalculateToAmount(
|
||||
Decimal newFromAmount,
|
||||
bool shouldNotifyListeners,
|
||||
) async {
|
||||
if (newFromAmount == Decimal.zero) {
|
||||
toAmount = Decimal.zero;
|
||||
}
|
||||
|
||||
fromAmount = newFromAmount;
|
||||
reversed = false;
|
||||
|
||||
await updateRanges(shouldNotifyListeners: false);
|
||||
|
||||
await updateEstimate(
|
||||
shouldNotifyListeners: false,
|
||||
reversed: reversed,
|
||||
);
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setToAmountAndCalculateFromAmount(
|
||||
Decimal newToAmount,
|
||||
bool shouldNotifyListeners,
|
||||
) async {
|
||||
if (newToAmount == Decimal.zero) {
|
||||
fromAmount = Decimal.zero;
|
||||
}
|
||||
|
||||
toAmount = newToAmount;
|
||||
reversed = true;
|
||||
|
||||
await updateRanges(shouldNotifyListeners: false);
|
||||
|
||||
await updateEstimate(
|
||||
shouldNotifyListeners: false,
|
||||
reversed: reversed,
|
||||
);
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateTo(Currency to, bool shouldNotifyListeners) async {
|
||||
try {
|
||||
_to = to;
|
||||
if (_from == null) {
|
||||
rate = null;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
await updateRanges(shouldNotifyListeners: false);
|
||||
|
||||
await updateEstimate(
|
||||
shouldNotifyListeners: false,
|
||||
reversed: reversed,
|
||||
);
|
||||
|
||||
debugPrint(
|
||||
"_updated TO: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$fromAmount _toAmount=$toAmount rate:$rate for: $exchange");
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateFrom(Currency from, bool shouldNotifyListeners) async {
|
||||
try {
|
||||
_from = from;
|
||||
|
||||
if (_to == null) {
|
||||
rate = null;
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
||||
await updateRanges(shouldNotifyListeners: false);
|
||||
|
||||
await updateEstimate(
|
||||
shouldNotifyListeners: false,
|
||||
reversed: reversed,
|
||||
);
|
||||
|
||||
debugPrint(
|
||||
"_updated FROM: _from=${_from!.ticker} _to=${_to!.ticker} _fromAmount=$fromAmount _toAmount=$toAmount rate:$rate for: $exchange");
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateMarket(
|
||||
FixedRateMarket? market,
|
||||
bool shouldNotifyListeners,
|
||||
) async {
|
||||
_market = market;
|
||||
|
||||
if (_market == null) {
|
||||
fromAmount = null;
|
||||
toAmount = null;
|
||||
} else {
|
||||
if (fromAmount != null) {
|
||||
if (fromAmount! <= Decimal.zero) {
|
||||
toAmount = Decimal.zero;
|
||||
} else {
|
||||
await updateRanges(shouldNotifyListeners: false);
|
||||
await updateEstimate(
|
||||
shouldNotifyListeners: false,
|
||||
reversed: reversed,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void _onExchangeRateTypeChanged() {
|
||||
print("_onExchangeRateTypeChanged");
|
||||
}
|
||||
|
||||
void _onExchangeTypeChanged() {
|
||||
updateRanges(shouldNotifyListeners: true).then(
|
||||
(_) => updateEstimate(
|
||||
shouldNotifyListeners: true,
|
||||
reversed: reversed,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> updateRanges({required bool shouldNotifyListeners}) async {
|
||||
if (exchange?.name == SimpleSwapExchange.exchangeName) {
|
||||
reversed = false;
|
||||
}
|
||||
final _fromTicker = reversed ? toTicker : fromTicker;
|
||||
final _toTicker = reversed ? fromTicker : toTicker;
|
||||
if (_fromTicker == null || _toTicker == null) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType.updateRanges where (from: $_fromTicker || to: $_toTicker) for: $exchange",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return;
|
||||
}
|
||||
final response = await exchange?.getRange(
|
||||
_fromTicker,
|
||||
_toTicker,
|
||||
exchangeType == ExchangeRateType.fixed,
|
||||
);
|
||||
|
||||
if (response?.value == null) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType.updateRanges for: $exchange where response: $response",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final range = response!.value!;
|
||||
|
||||
minAmount = range.min;
|
||||
maxAmount = range.max;
|
||||
|
||||
debugPrint(
|
||||
"updated range for: $exchange for $_fromTicker-$_toTicker: $range");
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateEstimate({
|
||||
required bool shouldNotifyListeners,
|
||||
required bool reversed,
|
||||
}) async {
|
||||
if (exchange?.name == SimpleSwapExchange.exchangeName) {
|
||||
reversed = false;
|
||||
}
|
||||
final amount = reversed ? toAmount : fromAmount;
|
||||
if (fromTicker == null ||
|
||||
toTicker == null ||
|
||||
amount == null ||
|
||||
amount <= Decimal.zero) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType.updateEstimate for: $exchange where (from: $fromTicker || to: $toTicker || amount: $amount)",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return;
|
||||
}
|
||||
final response = await exchange?.getEstimate(
|
||||
fromTicker!,
|
||||
toTicker!,
|
||||
amount,
|
||||
exchangeType == ExchangeRateType.fixed,
|
||||
reversed,
|
||||
);
|
||||
|
||||
if (response?.value == null) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType.updateEstimate for: $exchange where response: $response",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
estimate = response!.value!;
|
||||
|
||||
if (reversed) {
|
||||
fromAmount = estimate!.estimatedAmount;
|
||||
} else {
|
||||
toAmount = estimate!.estimatedAmount;
|
||||
}
|
||||
|
||||
rate = (toAmount! / fromAmount!).toDecimal(scaleOnInfinitePrecision: 12);
|
||||
|
||||
debugPrint(
|
||||
"updated estimate for: $exchange for $fromTicker-$toTicker: $estimate");
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void setOnError({
|
||||
required void Function(String)? onError,
|
||||
bool shouldNotifyListeners = false,
|
||||
}) {
|
||||
_onError = onError;
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> swap({FixedRateMarket? market}) async {
|
||||
final Decimal? newToAmount = fromAmount;
|
||||
final Decimal? newFromAmount = toAmount;
|
||||
|
||||
fromAmount = newFromAmount;
|
||||
toAmount = newToAmount;
|
||||
|
||||
minAmount = null;
|
||||
maxAmount = null;
|
||||
|
||||
switch (exchangeType) {
|
||||
case ExchangeRateType.estimated:
|
||||
final Currency? newTo = from;
|
||||
final Currency? newFrom = to;
|
||||
|
||||
_to = newTo;
|
||||
_from = newFrom;
|
||||
|
||||
await updateRanges(shouldNotifyListeners: false);
|
||||
|
||||
await updateEstimate(
|
||||
shouldNotifyListeners: false,
|
||||
reversed: reversed,
|
||||
);
|
||||
break;
|
||||
case ExchangeRateType.fixed:
|
||||
await updateMarket(market, false);
|
||||
break;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class FixedRateExchangeFormState extends ChangeNotifier {
|
||||
Decimal? _fromAmount;
|
||||
Decimal? _toAmount;
|
||||
|
||||
FixedRateMarket? _market;
|
||||
FixedRateMarket? get market => _market;
|
||||
|
||||
CNExchangeEstimate? _estimate;
|
||||
CNExchangeEstimate? get estimate => _estimate;
|
||||
|
||||
Decimal? get rate {
|
||||
if (_estimate == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (_estimate!.toAmount / _estimate!.fromAmount)
|
||||
.toDecimal(scaleOnInfinitePrecision: 12);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> swap(FixedRateMarket reverseFixedRateMarket) async {
|
||||
final Decimal? tmp = _fromAmount;
|
||||
_fromAmount = _toAmount;
|
||||
_toAmount = tmp;
|
||||
|
||||
await updateMarket(reverseFixedRateMarket, false);
|
||||
await updateRateEstimate(CNEstimateType.direct);
|
||||
_toAmount = _estimate?.toAmount ?? Decimal.zero;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
String get fromAmountString =>
|
||||
_fromAmount == null ? "" : _fromAmount!.toStringAsFixed(8);
|
||||
String get toAmountString =>
|
||||
_toAmount == null ? "" : _toAmount!.toStringAsFixed(8);
|
||||
|
||||
Future<void> updateMarket(
|
||||
FixedRateMarket? market,
|
||||
bool shouldNotifyListeners,
|
||||
) async {
|
||||
_market = market;
|
||||
|
||||
if (_market == null) {
|
||||
_fromAmount = null;
|
||||
_toAmount = null;
|
||||
} else {
|
||||
if (_fromAmount != null) {
|
||||
if (_fromAmount! <= Decimal.zero) {
|
||||
_toAmount = Decimal.zero;
|
||||
} else {
|
||||
await updateRateEstimate(CNEstimateType.direct);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
String get rateDisplayString {
|
||||
if (_market == null || _estimate == null) {
|
||||
return "N/A";
|
||||
} else {
|
||||
return "1 ${_estimate!.fromCurrency.toUpperCase()} ~${rate!.toStringAsFixed(8)} ${_estimate!.toCurrency.toUpperCase()}";
|
||||
}
|
||||
}
|
||||
|
||||
bool get canExchange {
|
||||
return _market != null &&
|
||||
_fromAmount != null &&
|
||||
_toAmount != null &&
|
||||
sendAmountWarning.isEmpty;
|
||||
}
|
||||
|
||||
String get sendAmountWarning {
|
||||
if (_market != null && _fromAmount != null) {
|
||||
if (_fromAmount! < _market!.min) {
|
||||
return "Minimum amount ${_market!.min.toString()} ${_market!.from.toUpperCase()}";
|
||||
} else if (_fromAmount! > _market!.max) {
|
||||
return "Maximum amount ${_market!.max.toString()} ${_market!.from.toUpperCase()}";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
Future<void> setToAmountAndCalculateFromAmount(
|
||||
Decimal newToAmount,
|
||||
bool shouldNotifyListeners,
|
||||
) async {
|
||||
_toAmount = newToAmount;
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
await updateRateEstimate(CNEstimateType.reverse);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setFromAmountAndCalculateToAmount(
|
||||
Decimal newFromAmount,
|
||||
bool shouldNotifyListeners,
|
||||
) async {
|
||||
_fromAmount = newFromAmount;
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
await updateRateEstimate(CNEstimateType.direct);
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void Function(String)? _onError;
|
||||
|
||||
void setOnError({
|
||||
required void Function(String)? onError,
|
||||
bool shouldNotifyListeners = false,
|
||||
}) {
|
||||
_onError = onError;
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> updateRateEstimate(CNEstimateType direction) async {
|
||||
if (market != null) {
|
||||
Decimal? amount;
|
||||
// set amount based on trade estimate direction
|
||||
switch (direction) {
|
||||
case CNEstimateType.direct:
|
||||
if (_fromAmount != null
|
||||
// &&
|
||||
// market!.min >= _fromAmount! &&
|
||||
// _fromAmount! <= market!.max
|
||||
) {
|
||||
amount = _fromAmount!;
|
||||
}
|
||||
break;
|
||||
case CNEstimateType.reverse:
|
||||
if (_toAmount != null
|
||||
// &&
|
||||
// market!.min >= _toAmount! &&
|
||||
// _toAmount! <= market!.max
|
||||
) {
|
||||
amount = _toAmount!;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (amount != null && market != null && amount > Decimal.zero) {
|
||||
final response = await ChangeNow.instance.getEstimatedExchangeAmountV2(
|
||||
fromTicker: market!.from,
|
||||
toTicker: market!.to,
|
||||
fromOrTo: direction,
|
||||
flow: CNFlowType.fixedRate,
|
||||
amount: amount,
|
||||
);
|
||||
|
||||
if (response.value != null) {
|
||||
// update estimate if response succeeded
|
||||
_estimate = response.value;
|
||||
|
||||
_toAmount = _estimate?.toAmount;
|
||||
_fromAmount = _estimate?.fromAmount;
|
||||
notifyListeners();
|
||||
} else if (response.exception != null) {
|
||||
Logging.instance.log("updateRateEstimate(): ${response.exception}",
|
||||
level: LogLevel.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
|
||||
|
||||
class IncompleteExchangeModel {
|
||||
|
@ -13,12 +13,14 @@ class IncompleteExchangeModel {
|
|||
|
||||
final ExchangeRateType rateType;
|
||||
|
||||
final bool reversed;
|
||||
|
||||
String? recipientAddress;
|
||||
String? refundAddress;
|
||||
|
||||
String? rateId;
|
||||
|
||||
ExchangeTransaction? trade;
|
||||
Trade? trade;
|
||||
|
||||
IncompleteExchangeModel({
|
||||
required this.sendTicker,
|
||||
|
@ -27,6 +29,7 @@ class IncompleteExchangeModel {
|
|||
required this.sendAmount,
|
||||
required this.receiveAmount,
|
||||
required this.rateType,
|
||||
required this.reversed,
|
||||
this.rateId,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,12 +5,18 @@ class Currency {
|
|||
/// Currency name
|
||||
final String name;
|
||||
|
||||
/// Currency network
|
||||
final String network;
|
||||
|
||||
/// Currency logo url
|
||||
final String image;
|
||||
|
||||
/// Indicates if a currency has an Extra ID
|
||||
final bool hasExternalId;
|
||||
|
||||
/// external id if it exists
|
||||
final String? externalId;
|
||||
|
||||
/// Indicates if a currency is a fiat currency (EUR, USD)
|
||||
final bool isFiat;
|
||||
|
||||
|
@ -30,8 +36,10 @@ class Currency {
|
|||
Currency({
|
||||
required this.ticker,
|
||||
required this.name,
|
||||
required this.network,
|
||||
required this.image,
|
||||
required this.hasExternalId,
|
||||
this.externalId,
|
||||
required this.isFiat,
|
||||
required this.featured,
|
||||
required this.isStable,
|
||||
|
@ -44,8 +52,10 @@ class Currency {
|
|||
return Currency(
|
||||
ticker: json["ticker"] as String,
|
||||
name: json["name"] as String,
|
||||
network: json["network"] as String? ?? "",
|
||||
image: json["image"] as String,
|
||||
hasExternalId: json["hasExternalId"] as bool,
|
||||
externalId: json["externalId"] as String?,
|
||||
isFiat: json["isFiat"] as bool,
|
||||
featured: json["featured"] as bool,
|
||||
isStable: json["isStable"] as bool,
|
||||
|
@ -61,8 +71,10 @@ class Currency {
|
|||
final map = {
|
||||
"ticker": ticker,
|
||||
"name": name,
|
||||
"network": network,
|
||||
"image": image,
|
||||
"hasExternalId": hasExternalId,
|
||||
"externalId": externalId,
|
||||
"isFiat": isFiat,
|
||||
"featured": featured,
|
||||
"isStable": isStable,
|
||||
|
@ -79,8 +91,10 @@ class Currency {
|
|||
Currency copyWith({
|
||||
String? ticker,
|
||||
String? name,
|
||||
String? network,
|
||||
String? image,
|
||||
bool? hasExternalId,
|
||||
String? externalId,
|
||||
bool? isFiat,
|
||||
bool? featured,
|
||||
bool? isStable,
|
||||
|
@ -90,8 +104,10 @@ class Currency {
|
|||
return Currency(
|
||||
ticker: ticker ?? this.ticker,
|
||||
name: name ?? this.name,
|
||||
network: network ?? this.network,
|
||||
image: image ?? this.image,
|
||||
hasExternalId: hasExternalId ?? this.hasExternalId,
|
||||
externalId: externalId ?? this.externalId,
|
||||
isFiat: isFiat ?? this.isFiat,
|
||||
featured: featured ?? this.featured,
|
||||
isStable: isStable ?? this.isStable,
|
46
lib/models/exchange/response_objects/estimate.dart
Normal file
46
lib/models/exchange/response_objects/estimate.dart
Normal file
|
@ -0,0 +1,46 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class Estimate {
|
||||
final Decimal estimatedAmount;
|
||||
final bool fixedRate;
|
||||
final bool reversed;
|
||||
final String? warningMessage;
|
||||
final String? rateId;
|
||||
|
||||
Estimate({
|
||||
required this.estimatedAmount,
|
||||
required this.fixedRate,
|
||||
required this.reversed,
|
||||
this.warningMessage,
|
||||
this.rateId,
|
||||
});
|
||||
|
||||
factory Estimate.fromMap(Map<String, dynamic> map) {
|
||||
try {
|
||||
return Estimate(
|
||||
estimatedAmount: Decimal.parse(map["estimatedAmount"] as String),
|
||||
fixedRate: map["fixedRate"] as bool,
|
||||
reversed: map["reversed"] as bool,
|
||||
warningMessage: map["warningMessage"] as String?,
|
||||
rateId: map["rateId"] as String?,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Estimate.fromMap(): $e\n$s", level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"estimatedAmount": estimatedAmount.toString(),
|
||||
"fixedRate": fixedRate,
|
||||
"reversed": reversed,
|
||||
"warningMessage": warningMessage,
|
||||
"rateId": rateId,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => "Estimate: ${toMap()}";
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class FixedRateMarket {
|
||||
/// Currency ticker
|
||||
|
@ -20,7 +21,7 @@ class FixedRateMarket {
|
|||
|
||||
/// Network fee for transferring funds between wallets, it should
|
||||
/// be deducted from the result.
|
||||
final Decimal minerFee;
|
||||
final Decimal? minerFee;
|
||||
|
||||
FixedRateMarket({
|
||||
required this.from,
|
||||
|
@ -31,7 +32,7 @@ class FixedRateMarket {
|
|||
required this.minerFee,
|
||||
});
|
||||
|
||||
factory FixedRateMarket.fromJson(Map<String, dynamic> json) {
|
||||
factory FixedRateMarket.fromMap(Map<String, dynamic> json) {
|
||||
try {
|
||||
return FixedRateMarket(
|
||||
from: json["from"] as String,
|
||||
|
@ -39,15 +40,19 @@ class FixedRateMarket {
|
|||
min: Decimal.parse(json["min"].toString()),
|
||||
max: Decimal.parse(json["max"].toString()),
|
||||
rate: Decimal.parse(json["rate"].toString()),
|
||||
minerFee: Decimal.parse(json["minerFee"].toString()),
|
||||
minerFee: Decimal.tryParse(json["minerFee"].toString()),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"FixedRateMarket.fromMap(): $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = {
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"from": from,
|
||||
"to": to,
|
||||
"min": min,
|
||||
|
@ -55,8 +60,6 @@ class FixedRateMarket {
|
|||
"rate": rate,
|
||||
"minerFee": minerFee,
|
||||
};
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
FixedRateMarket copyWith({
|
||||
|
@ -78,7 +81,5 @@ class FixedRateMarket {
|
|||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "FixedRateMarket: ${toJson()}";
|
||||
}
|
||||
String toString() => "FixedRateMarket: ${toMap()}";
|
||||
}
|
73
lib/models/exchange/response_objects/pair.dart
Normal file
73
lib/models/exchange/response_objects/pair.dart
Normal file
|
@ -0,0 +1,73 @@
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class Pair {
|
||||
final String from;
|
||||
final String fromNetwork;
|
||||
|
||||
final String to;
|
||||
final String toNetwork;
|
||||
|
||||
final bool fixedRate;
|
||||
final bool floatingRate;
|
||||
|
||||
Pair({
|
||||
required this.from,
|
||||
required this.fromNetwork,
|
||||
required this.to,
|
||||
required this.toNetwork,
|
||||
required this.fixedRate,
|
||||
required this.floatingRate,
|
||||
});
|
||||
|
||||
factory Pair.fromMap(Map<String, dynamic> map) {
|
||||
try {
|
||||
return Pair(
|
||||
from: map["from"] as String,
|
||||
fromNetwork: map["fromNetwork"] as String,
|
||||
to: map["to"] as String,
|
||||
toNetwork: map["toNetwork"] as String,
|
||||
fixedRate: map["fixedRate"] as bool,
|
||||
floatingRate: map["floatingRate"] as bool,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Pair.fromMap(): $e\n$s", level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
"from": from,
|
||||
"fromNetwork": fromNetwork,
|
||||
"to": to,
|
||||
"toNetwork": toNetwork,
|
||||
"fixedRate": fixedRate,
|
||||
"floatingRate": floatingRate,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(other) =>
|
||||
other is Pair &&
|
||||
from == other.from &&
|
||||
fromNetwork == other.fromNetwork &&
|
||||
to == other.to &&
|
||||
toNetwork == other.toNetwork &&
|
||||
fixedRate == other.fixedRate &&
|
||||
floatingRate == other.floatingRate;
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(
|
||||
from,
|
||||
fromNetwork,
|
||||
to,
|
||||
toNetwork,
|
||||
fixedRate,
|
||||
floatingRate,
|
||||
);
|
||||
|
||||
@override
|
||||
String toString() => "Pair: ${toMap()}";
|
||||
}
|
32
lib/models/exchange/response_objects/range.dart
Normal file
32
lib/models/exchange/response_objects/range.dart
Normal file
|
@ -0,0 +1,32 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
|
||||
class Range {
|
||||
final Decimal? min;
|
||||
final Decimal? max;
|
||||
|
||||
Range({this.min, this.max});
|
||||
|
||||
Range copyWith({
|
||||
Decimal? min,
|
||||
Decimal? max,
|
||||
}) {
|
||||
return Range(
|
||||
min: min ?? this.min,
|
||||
max: max ?? this.max,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
final map = {
|
||||
"min": min?.toString(),
|
||||
"max": max?.toString(),
|
||||
};
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "Range: ${toMap()}";
|
||||
}
|
||||
}
|
239
lib/models/exchange/response_objects/trade.dart
Normal file
239
lib/models/exchange/response_objects/trade.dart
Normal file
|
@ -0,0 +1,239 @@
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
|
||||
part 'trade.g.dart';
|
||||
|
||||
@HiveType(typeId: Trade.typeId)
|
||||
class Trade {
|
||||
static const typeId = 22;
|
||||
|
||||
@HiveField(0)
|
||||
final String uuid;
|
||||
|
||||
@HiveField(1)
|
||||
final String tradeId;
|
||||
|
||||
@HiveField(2)
|
||||
final String rateType;
|
||||
|
||||
@HiveField(3)
|
||||
final String direction;
|
||||
|
||||
@HiveField(4)
|
||||
final DateTime timestamp;
|
||||
|
||||
@HiveField(5)
|
||||
final DateTime updatedAt;
|
||||
|
||||
@HiveField(6)
|
||||
final String payInCurrency;
|
||||
|
||||
@HiveField(7)
|
||||
final String payInAmount;
|
||||
|
||||
@HiveField(8)
|
||||
final String payInAddress;
|
||||
|
||||
@HiveField(9)
|
||||
final String payInNetwork;
|
||||
|
||||
@HiveField(10)
|
||||
final String payInExtraId;
|
||||
|
||||
@HiveField(11)
|
||||
final String payInTxid;
|
||||
|
||||
@HiveField(12)
|
||||
final String payOutCurrency;
|
||||
|
||||
@HiveField(13)
|
||||
final String payOutAmount;
|
||||
|
||||
@HiveField(14)
|
||||
final String payOutAddress;
|
||||
|
||||
@HiveField(15)
|
||||
final String payOutNetwork;
|
||||
|
||||
@HiveField(16)
|
||||
final String payOutExtraId;
|
||||
|
||||
@HiveField(17)
|
||||
final String payOutTxid;
|
||||
|
||||
@HiveField(18)
|
||||
final String refundAddress;
|
||||
|
||||
@HiveField(19)
|
||||
final String refundExtraId;
|
||||
|
||||
@HiveField(20)
|
||||
final String status;
|
||||
|
||||
@HiveField(21)
|
||||
final String exchangeName;
|
||||
|
||||
const Trade({
|
||||
required this.uuid,
|
||||
required this.tradeId,
|
||||
required this.rateType,
|
||||
required this.direction,
|
||||
required this.timestamp,
|
||||
required this.updatedAt,
|
||||
required this.payInCurrency,
|
||||
required this.payInAmount,
|
||||
required this.payInAddress,
|
||||
required this.payInNetwork,
|
||||
required this.payInExtraId,
|
||||
required this.payInTxid,
|
||||
required this.payOutCurrency,
|
||||
required this.payOutAmount,
|
||||
required this.payOutAddress,
|
||||
required this.payOutNetwork,
|
||||
required this.payOutExtraId,
|
||||
required this.payOutTxid,
|
||||
required this.refundAddress,
|
||||
required this.refundExtraId,
|
||||
required this.status,
|
||||
required this.exchangeName,
|
||||
});
|
||||
|
||||
Trade copyWith({
|
||||
String? tradeId,
|
||||
String? rateType,
|
||||
String? direction,
|
||||
DateTime? timestamp,
|
||||
DateTime? updatedAt,
|
||||
String? payInCurrency,
|
||||
String? payInAmount,
|
||||
String? payInAddress,
|
||||
String? payInNetwork,
|
||||
String? payInExtraId,
|
||||
String? payInTxid,
|
||||
String? payOutCurrency,
|
||||
String? payOutAmount,
|
||||
String? payOutAddress,
|
||||
String? payOutNetwork,
|
||||
String? payOutExtraId,
|
||||
String? payOutTxid,
|
||||
String? refundAddress,
|
||||
String? refundExtraId,
|
||||
String? status,
|
||||
String? exchangeName,
|
||||
}) {
|
||||
return Trade(
|
||||
uuid: uuid,
|
||||
tradeId: tradeId ?? this.tradeId,
|
||||
rateType: rateType ?? this.rateType,
|
||||
direction: direction ?? this.direction,
|
||||
timestamp: timestamp ?? this.timestamp,
|
||||
updatedAt: updatedAt ?? this.updatedAt,
|
||||
payInCurrency: payInCurrency ?? this.payInCurrency,
|
||||
payInAmount: payInAmount ?? this.payInAmount,
|
||||
payInAddress: payInAddress ?? this.payInAddress,
|
||||
payInNetwork: payInNetwork ?? this.payInNetwork,
|
||||
payInExtraId: payInExtraId ?? this.payInExtraId,
|
||||
payInTxid: payInTxid ?? this.payInTxid,
|
||||
payOutCurrency: payOutCurrency ?? this.payOutCurrency,
|
||||
payOutAmount: payOutAmount ?? this.payOutAmount,
|
||||
payOutAddress: payOutAddress ?? this.payOutAddress,
|
||||
payOutNetwork: payOutNetwork ?? this.payOutNetwork,
|
||||
payOutExtraId: payOutExtraId ?? this.payOutExtraId,
|
||||
payOutTxid: payOutTxid ?? this.payOutTxid,
|
||||
refundAddress: refundAddress ?? this.refundAddress,
|
||||
refundExtraId: refundExtraId ?? this.refundExtraId,
|
||||
status: status ?? this.status,
|
||||
exchangeName: exchangeName ?? this.exchangeName,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, String> toMap() {
|
||||
return {
|
||||
"uuid": uuid,
|
||||
"tradeId": tradeId,
|
||||
"rateType": rateType,
|
||||
"direction": direction,
|
||||
"timestamp": timestamp.toIso8601String(),
|
||||
"updatedAt": updatedAt.toIso8601String(),
|
||||
"payInCurrency": payInCurrency,
|
||||
"payInAmount": payInAmount,
|
||||
"payInAddress": payInAddress,
|
||||
"payInNetwork": payInNetwork,
|
||||
"payInExtraId": payInExtraId,
|
||||
"payInTxid": payInTxid,
|
||||
"payOutCurrency": payOutCurrency,
|
||||
"payOutAmount": payOutAmount,
|
||||
"payOutAddress": payOutAddress,
|
||||
"payOutNetwork": payOutNetwork,
|
||||
"payOutExtraId": payOutExtraId,
|
||||
"payOutTxid": payOutTxid,
|
||||
"refundAddress": refundAddress,
|
||||
"refundExtraId": refundExtraId,
|
||||
"status": status,
|
||||
"exchangeName": exchangeName,
|
||||
};
|
||||
}
|
||||
|
||||
factory Trade.fromMap(Map<String, dynamic> map) {
|
||||
return Trade(
|
||||
uuid: map["uuid"] as String,
|
||||
tradeId: map["tradeId"] as String,
|
||||
rateType: map["rateType"] as String,
|
||||
direction: map["direction"] as String,
|
||||
timestamp: DateTime.parse(map["timestamp"] as String),
|
||||
updatedAt: DateTime.parse(map["updatedAt"] as String),
|
||||
payInCurrency: map["payInCurrency"] as String,
|
||||
payInAmount: map["payInAmount"] as String,
|
||||
payInAddress: map["payInAddress"] as String,
|
||||
payInNetwork: map["payInNetwork"] as String,
|
||||
payInExtraId: map["payInExtraId"] as String,
|
||||
payInTxid: map["payInTxid"] as String,
|
||||
payOutCurrency: map["payOutCurrency"] as String,
|
||||
payOutAmount: map["payOutAmount"] as String,
|
||||
payOutAddress: map["payOutAddress"] as String,
|
||||
payOutNetwork: map["payOutNetwork"] as String,
|
||||
payOutExtraId: map["payOutExtraId"] as String,
|
||||
payOutTxid: map["payOutTxid"] as String,
|
||||
refundAddress: map["refundAddress"] as String,
|
||||
refundExtraId: map["refundExtraId"] as String,
|
||||
status: map["status"] as String,
|
||||
exchangeName: map["exchangeName"] as String,
|
||||
);
|
||||
}
|
||||
|
||||
factory Trade.fromExchangeTransaction(
|
||||
ExchangeTransaction exTx, bool reversed) {
|
||||
return Trade(
|
||||
uuid: exTx.uuid,
|
||||
tradeId: exTx.id,
|
||||
rateType: "",
|
||||
direction: reversed ? "reverse" : "direct",
|
||||
timestamp: exTx.date,
|
||||
updatedAt: DateTime.tryParse(exTx.statusObject!.updatedAt) ?? exTx.date,
|
||||
payInCurrency: exTx.fromCurrency,
|
||||
payInAmount: exTx.statusObject!.amountSendDecimal.isEmpty
|
||||
? exTx.statusObject!.expectedSendAmountDecimal
|
||||
: exTx.statusObject!.amountSendDecimal,
|
||||
payInAddress: exTx.payinAddress,
|
||||
payInNetwork: "",
|
||||
payInExtraId: exTx.payinExtraId,
|
||||
payInTxid: exTx.statusObject!.payinHash,
|
||||
payOutCurrency: exTx.toCurrency,
|
||||
payOutAmount: exTx.amount,
|
||||
payOutAddress: exTx.payoutAddress,
|
||||
payOutNetwork: "",
|
||||
payOutExtraId: exTx.payoutExtraId,
|
||||
payOutTxid: exTx.statusObject!.payoutHash,
|
||||
refundAddress: exTx.refundAddress,
|
||||
refundExtraId: exTx.refundExtraId,
|
||||
status: exTx.statusObject!.status.name,
|
||||
exchangeName: ChangeNowExchange.exchangeName,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
}
|
104
lib/models/exchange/response_objects/trade.g.dart
Normal file
104
lib/models/exchange/response_objects/trade.g.dart
Normal file
|
@ -0,0 +1,104 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'trade.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// TypeAdapterGenerator
|
||||
// **************************************************************************
|
||||
|
||||
class TradeAdapter extends TypeAdapter<Trade> {
|
||||
@override
|
||||
final int typeId = 22;
|
||||
|
||||
@override
|
||||
Trade read(BinaryReader reader) {
|
||||
final numOfFields = reader.readByte();
|
||||
final fields = <int, dynamic>{
|
||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||
};
|
||||
return Trade(
|
||||
uuid: fields[0] as String,
|
||||
tradeId: fields[1] as String,
|
||||
rateType: fields[2] as String,
|
||||
direction: fields[3] as String,
|
||||
timestamp: fields[4] as DateTime,
|
||||
updatedAt: fields[5] as DateTime,
|
||||
payInCurrency: fields[6] as String,
|
||||
payInAmount: fields[7] as String,
|
||||
payInAddress: fields[8] as String,
|
||||
payInNetwork: fields[9] as String,
|
||||
payInExtraId: fields[10] as String,
|
||||
payInTxid: fields[11] as String,
|
||||
payOutCurrency: fields[12] as String,
|
||||
payOutAmount: fields[13] as String,
|
||||
payOutAddress: fields[14] as String,
|
||||
payOutNetwork: fields[15] as String,
|
||||
payOutExtraId: fields[16] as String,
|
||||
payOutTxid: fields[17] as String,
|
||||
refundAddress: fields[18] as String,
|
||||
refundExtraId: fields[19] as String,
|
||||
status: fields[20] as String,
|
||||
exchangeName: fields[21] as String,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void write(BinaryWriter writer, Trade obj) {
|
||||
writer
|
||||
..writeByte(22)
|
||||
..writeByte(0)
|
||||
..write(obj.uuid)
|
||||
..writeByte(1)
|
||||
..write(obj.tradeId)
|
||||
..writeByte(2)
|
||||
..write(obj.rateType)
|
||||
..writeByte(3)
|
||||
..write(obj.direction)
|
||||
..writeByte(4)
|
||||
..write(obj.timestamp)
|
||||
..writeByte(5)
|
||||
..write(obj.updatedAt)
|
||||
..writeByte(6)
|
||||
..write(obj.payInCurrency)
|
||||
..writeByte(7)
|
||||
..write(obj.payInAmount)
|
||||
..writeByte(8)
|
||||
..write(obj.payInAddress)
|
||||
..writeByte(9)
|
||||
..write(obj.payInNetwork)
|
||||
..writeByte(10)
|
||||
..write(obj.payInExtraId)
|
||||
..writeByte(11)
|
||||
..write(obj.payInTxid)
|
||||
..writeByte(12)
|
||||
..write(obj.payOutCurrency)
|
||||
..writeByte(13)
|
||||
..write(obj.payOutAmount)
|
||||
..writeByte(14)
|
||||
..write(obj.payOutAddress)
|
||||
..writeByte(15)
|
||||
..write(obj.payOutNetwork)
|
||||
..writeByte(16)
|
||||
..write(obj.payOutExtraId)
|
||||
..writeByte(17)
|
||||
..write(obj.payOutTxid)
|
||||
..writeByte(18)
|
||||
..write(obj.refundAddress)
|
||||
..writeByte(19)
|
||||
..write(obj.refundExtraId)
|
||||
..writeByte(20)
|
||||
..write(obj.status)
|
||||
..writeByte(21)
|
||||
..write(obj.exchangeName);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => typeId.hashCode;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is TradeAdapter &&
|
||||
runtimeType == other.runtimeType &&
|
||||
typeId == other.typeId;
|
||||
}
|
30
lib/models/exchange/simpleswap/sp_available_currencies.dart
Normal file
30
lib/models/exchange/simpleswap/sp_available_currencies.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
|
||||
class SPAvailableCurrencies {
|
||||
final List<Currency> floatingRateCurrencies = [];
|
||||
final List<Currency> fixedRateCurrencies = [];
|
||||
|
||||
final List<Pair> floatingRatePairs = [];
|
||||
final List<Pair> fixedRatePairs = [];
|
||||
|
||||
void updateFloatingCurrencies(List<Currency> newCurrencies) {
|
||||
floatingRateCurrencies.clear();
|
||||
floatingRateCurrencies.addAll(newCurrencies);
|
||||
}
|
||||
|
||||
void updateFixedCurrencies(List<Currency> newCurrencies) {
|
||||
fixedRateCurrencies.clear();
|
||||
fixedRateCurrencies.addAll(newCurrencies);
|
||||
}
|
||||
|
||||
void updateFloatingPairs(List<Pair> newPairs) {
|
||||
floatingRatePairs.clear();
|
||||
floatingRatePairs.addAll(newPairs);
|
||||
}
|
||||
|
||||
void updateFixedPairs(List<Pair> newPairs) {
|
||||
fixedRatePairs.clear();
|
||||
fixedRatePairs.addAll(newPairs);
|
||||
}
|
||||
}
|
99
lib/models/exchange/simpleswap/sp_currency.dart
Normal file
99
lib/models/exchange/simpleswap/sp_currency.dart
Normal file
|
@ -0,0 +1,99 @@
|
|||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class SPCurrency {
|
||||
/// currency name
|
||||
final String name;
|
||||
|
||||
/// currency symbol
|
||||
final String symbol;
|
||||
|
||||
/// currency network
|
||||
final String network;
|
||||
|
||||
/// has this currency extra id parameter
|
||||
final bool hasExtraId;
|
||||
|
||||
/// name of extra id (if exists)
|
||||
final String? extraId;
|
||||
|
||||
/// relative url for currency icon svg
|
||||
final String image;
|
||||
|
||||
/// informational messages about the currency they are changing
|
||||
final List<dynamic> warningsFrom;
|
||||
|
||||
/// informational messages about the currency for which they are exchanged
|
||||
final List<dynamic> warningsTo;
|
||||
|
||||
SPCurrency({
|
||||
required this.name,
|
||||
required this.symbol,
|
||||
required this.network,
|
||||
required this.hasExtraId,
|
||||
required this.extraId,
|
||||
required this.image,
|
||||
required this.warningsFrom,
|
||||
required this.warningsTo,
|
||||
});
|
||||
|
||||
factory SPCurrency.fromJson(Map<String, dynamic> json) {
|
||||
try {
|
||||
return SPCurrency(
|
||||
name: json["name"] as String,
|
||||
symbol: json["symbol"] as String,
|
||||
network: json["network"] as String? ?? "",
|
||||
hasExtraId: json["has_extra_id"] as bool,
|
||||
extraId: json["extra_id"] as String?,
|
||||
image: json["image"] as String,
|
||||
warningsFrom: json["warnings_from"] as List<dynamic>,
|
||||
warningsTo: json["warnings_to"] as List<dynamic>,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("SPCurrency.fromJson failed to parse: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final map = {
|
||||
"name": name,
|
||||
"symbol": symbol,
|
||||
"network": network,
|
||||
"has_extra_id": hasExtraId,
|
||||
"extra_id": extraId,
|
||||
"image": image,
|
||||
"warnings_from": warningsFrom,
|
||||
"warnings_to": warningsTo,
|
||||
};
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
SPCurrency copyWith({
|
||||
String? name,
|
||||
String? symbol,
|
||||
String? network,
|
||||
bool? hasExtraId,
|
||||
String? extraId,
|
||||
String? image,
|
||||
List<dynamic>? warningsFrom,
|
||||
List<dynamic>? warningsTo,
|
||||
}) {
|
||||
return SPCurrency(
|
||||
name: name ?? this.name,
|
||||
symbol: symbol ?? this.symbol,
|
||||
network: network ?? this.network,
|
||||
hasExtraId: hasExtraId ?? this.hasExtraId,
|
||||
extraId: extraId ?? this.extraId,
|
||||
image: image ?? this.image,
|
||||
warningsFrom: warningsFrom ?? this.warningsFrom,
|
||||
warningsTo: warningsTo ?? this.warningsTo,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "SPCurrency: ${toJson()}";
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/trade_wallet_lookup.dart';
|
||||
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
|
||||
|
@ -34,7 +34,7 @@ class ConfirmChangeNowSendView extends ConsumerStatefulWidget {
|
|||
final Map<String, dynamic> transactionInfo;
|
||||
final String walletId;
|
||||
final String routeOnSuccessName;
|
||||
final ExchangeTransaction trade;
|
||||
final Trade trade;
|
||||
|
||||
@override
|
||||
ConsumerState<ConfirmChangeNowSendView> createState() =>
|
||||
|
@ -46,7 +46,7 @@ class _ConfirmChangeNowSendViewState
|
|||
late final Map<String, dynamic> transactionInfo;
|
||||
late final String walletId;
|
||||
late final String routeOnSuccessName;
|
||||
late final ExchangeTransaction trade;
|
||||
late final Trade trade;
|
||||
|
||||
Future<void> _attemptSend(BuildContext context) async {
|
||||
unawaited(showDialog<void>(
|
||||
|
@ -75,7 +75,7 @@ class _ConfirmChangeNowSendViewState
|
|||
tradeWalletLookup: TradeWalletLookup(
|
||||
uuid: const Uuid().v1(),
|
||||
txid: txid,
|
||||
tradeId: trade.id,
|
||||
tradeId: trade.tradeId,
|
||||
walletIds: [walletId],
|
||||
),
|
||||
);
|
||||
|
@ -207,7 +207,7 @@ class _ConfirmChangeNowSendViewState
|
|||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"ChangeNOW address",
|
||||
"${trade.exchangeName} address",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -309,7 +309,7 @@ class _ConfirmChangeNowSendViewState
|
|||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
Text(
|
||||
trade.id,
|
||||
trade.tradeId,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
textAlign: TextAlign.right,
|
||||
),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
|
1343
lib/pages/exchange_view/exchange_form.dart
Normal file
1343
lib/pages/exchange_view/exchange_form.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -70,7 +70,7 @@ class _ExchangeLoadingOverlayViewState
|
|||
.overlay
|
||||
.withOpacity(0.7),
|
||||
child: const CustomLoadingOverlay(
|
||||
message: "Loading ChangeNOW data", eventBus: null),
|
||||
message: "Loading Exchange data", eventBus: null),
|
||||
),
|
||||
if ((_statusEst == ChangeNowLoadStatus.failed ||
|
||||
_statusFixed == ChangeNowLoadStatus.failed) &&
|
||||
|
@ -85,9 +85,9 @@ class _ExchangeLoadingOverlayViewState
|
|||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
StackDialog(
|
||||
title: "Failed to fetch ChangeNow data",
|
||||
title: "Failed to fetch Exchange data",
|
||||
message:
|
||||
"ChangeNOW requires a working internet connection. Tap OK to try fetching again.",
|
||||
"Exchange requires a working internet connection. Tap OK to try fetching again.",
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
|
|
@ -348,23 +348,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
"sendViewScanQrButtonKey"),
|
||||
onTap: () async {
|
||||
try {
|
||||
// ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = false;
|
||||
final qrResult =
|
||||
await scanner.scan();
|
||||
|
||||
// Future<void>.delayed(
|
||||
// const Duration(seconds: 2),
|
||||
// () => ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = true,
|
||||
// );
|
||||
|
||||
final results =
|
||||
AddressUtils.parseUri(
|
||||
qrResult.rawContent);
|
||||
|
@ -385,16 +371,10 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
setState(() {});
|
||||
}
|
||||
} on PlatformException catch (e, s) {
|
||||
// ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = true;
|
||||
// here we ignore the exception caused by not giving permission
|
||||
// to use the camera to scan a qr code
|
||||
Logging.instance.log(
|
||||
"Failed to get camera permissions while trying to scan qr code in SendView: $e\n$s",
|
||||
level: LogLevel.Warning);
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const QrCodeIcon(),
|
||||
|
@ -585,23 +565,9 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
"sendViewScanQrButtonKey"),
|
||||
onTap: () async {
|
||||
try {
|
||||
// ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = false;
|
||||
final qrResult =
|
||||
await scanner.scan();
|
||||
|
||||
// Future<void>.delayed(
|
||||
// const Duration(seconds: 2),
|
||||
// () => ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = true,
|
||||
// );
|
||||
|
||||
final results =
|
||||
AddressUtils.parseUri(
|
||||
qrResult.rawContent);
|
||||
|
@ -622,16 +588,10 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
setState(() {});
|
||||
}
|
||||
} on PlatformException catch (e, s) {
|
||||
// ref
|
||||
// .read(
|
||||
// shouldShowLockscreenOnResumeStateProvider
|
||||
// .state)
|
||||
// .state = true;
|
||||
// here we ignore the exception caused by not giving permission
|
||||
// to use the camera to scan a qr code
|
||||
Logging.instance.log(
|
||||
"Failed to get camera permissions while trying to scan qr code in SendView: $e\n$s",
|
||||
level: LogLevel.Warning);
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const QrCodeIcon(),
|
||||
|
@ -681,7 +641,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
onPressed: () {
|
||||
Navigator.of(context).pushNamed(
|
||||
Step3View.routeName,
|
||||
arguments: model);
|
||||
arguments: model,
|
||||
);
|
||||
},
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
|
|
@ -2,14 +2,14 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_step_views/step_4_view.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
||||
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/exchange_provider.dart';
|
||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/notifications_api.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
|
@ -243,33 +243,24 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
),
|
||||
);
|
||||
|
||||
ChangeNowResponse<ExchangeTransaction>
|
||||
response;
|
||||
if (model.rateType ==
|
||||
ExchangeRateType.estimated) {
|
||||
response = await ref
|
||||
.read(changeNowProvider)
|
||||
.createStandardExchangeTransaction(
|
||||
fromTicker: model.sendTicker,
|
||||
toTicker: model.receiveTicker,
|
||||
receivingAddress:
|
||||
model.recipientAddress!,
|
||||
amount: model.sendAmount,
|
||||
refundAddress: model.refundAddress!,
|
||||
final ExchangeResponse<Trade> response =
|
||||
await ref
|
||||
.read(exchangeProvider)
|
||||
.createTrade(
|
||||
from: model.sendTicker,
|
||||
to: model.receiveTicker,
|
||||
fixedRate: model.rateType !=
|
||||
ExchangeRateType.estimated,
|
||||
amount: model.reversed
|
||||
? model.receiveAmount
|
||||
: model.sendAmount,
|
||||
addressTo: model.recipientAddress!,
|
||||
extraId: null,
|
||||
addressRefund: model.refundAddress!,
|
||||
refundExtraId: "",
|
||||
rateId: model.rateId,
|
||||
reversed: model.reversed,
|
||||
);
|
||||
} else {
|
||||
response = await ref
|
||||
.read(changeNowProvider)
|
||||
.createFixedRateExchangeTransaction(
|
||||
fromTicker: model.sendTicker,
|
||||
toTicker: model.receiveTicker,
|
||||
receivingAddress:
|
||||
model.recipientAddress!,
|
||||
amount: model.sendAmount,
|
||||
refundAddress: model.refundAddress!,
|
||||
rateId: model.rateId!,
|
||||
);
|
||||
}
|
||||
|
||||
if (response.value == null) {
|
||||
if (mounted) {
|
||||
|
@ -293,20 +284,9 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
shouldNotifyListeners: true,
|
||||
);
|
||||
|
||||
final statusResponse = await ref
|
||||
.read(changeNowProvider)
|
||||
.getTransactionStatus(
|
||||
id: response.value!.id);
|
||||
String status = response.value!.status;
|
||||
|
||||
String status = "Waiting";
|
||||
if (statusResponse.value != null) {
|
||||
status = statusResponse.value!.status.name;
|
||||
}
|
||||
|
||||
model.trade = response.value!.copyWith(
|
||||
statusString: status,
|
||||
statusObject: statusResponse.value!,
|
||||
);
|
||||
model.trade = response.value!;
|
||||
|
||||
// extra info if status is waiting
|
||||
if (status == "Waiting") {
|
||||
|
@ -318,12 +298,12 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
}
|
||||
|
||||
unawaited(NotificationApi.showNotification(
|
||||
changeNowId: model.trade!.id,
|
||||
changeNowId: model.trade!.tradeId,
|
||||
title: status,
|
||||
body: "Trade ID ${model.trade!.id}",
|
||||
body: "Trade ID ${model.trade!.tradeId}",
|
||||
walletId: "",
|
||||
iconAssetName: Assets.svg.arrowRotate,
|
||||
date: model.trade!.date,
|
||||
date: model.trade!.timestamp,
|
||||
shouldWatchForUpdates: true,
|
||||
coinName: "coinName",
|
||||
));
|
||||
|
|
|
@ -5,7 +5,6 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/confirm_change_now_send.dart';
|
||||
|
@ -13,8 +12,6 @@ import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
|
|||
import 'package:stackwallet/pages/exchange_view/sub_widgets/step_row.dart';
|
||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
||||
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
|
@ -51,7 +48,6 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
late final ClipboardInterface clipboard;
|
||||
|
||||
String _statusString = "New";
|
||||
ChangeNowTransactionStatus _status = ChangeNowTransactionStatus.New;
|
||||
|
||||
Timer? _statusTimer;
|
||||
|
||||
|
@ -69,13 +65,11 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
}
|
||||
|
||||
Future<void> _updateStatus() async {
|
||||
final statusResponse = await ref
|
||||
.read(changeNowProvider)
|
||||
.getTransactionStatus(id: model.trade!.id);
|
||||
final statusResponse =
|
||||
await ref.read(exchangeProvider).updateTrade(model.trade!);
|
||||
String status = "Waiting";
|
||||
if (statusResponse.value != null) {
|
||||
_status = statusResponse.value!.status;
|
||||
status = _status.name;
|
||||
status = statusResponse.value!.status;
|
||||
}
|
||||
|
||||
// extra info if status is waiting
|
||||
|
@ -112,7 +106,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool isWalletCoin =
|
||||
_isWalletCoinAndHasWallet(model.trade!.fromCurrency, ref);
|
||||
_isWalletCoinAndHasWallet(model.trade!.payInCurrency, ref);
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
|
@ -164,7 +158,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
height: 8,
|
||||
),
|
||||
Text(
|
||||
"Send ${model.sendTicker.toUpperCase()} to the address below. Once it is received, ChangeNOW will send the ${model.receiveTicker.toUpperCase()} to the recipient address you provided. You can find this trade details and check its status in the list of trades.",
|
||||
"Send ${model.sendTicker.toUpperCase()} to the address below. Once it is received, ${model.trade!.exchangeName} will send the ${model.receiveTicker.toUpperCase()} to the recipient address you provided. You can find this trade details and check its status in the list of trades.",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -272,7 +266,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
GestureDetector(
|
||||
onTap: () async {
|
||||
final data = ClipboardData(
|
||||
text: model.trade!.payinAddress);
|
||||
text: model.trade!.payInAddress);
|
||||
await clipboard.setData(data);
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
|
@ -305,7 +299,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
height: 4,
|
||||
),
|
||||
Text(
|
||||
model.trade!.payinAddress,
|
||||
model.trade!.payInAddress,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
|
@ -325,7 +319,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
Row(
|
||||
children: [
|
||||
Text(
|
||||
model.trade!.id,
|
||||
model.trade!.tradeId,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -333,8 +327,8 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final data =
|
||||
ClipboardData(text: model.trade!.id);
|
||||
final data = ClipboardData(
|
||||
text: model.trade!.tradeId);
|
||||
await clipboard.setData(data);
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
|
@ -372,7 +366,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
STextStyles.itemSubtitle(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForStatus(_status),
|
||||
.colorForStatus(_statusString),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -408,7 +402,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
child: QrImage(
|
||||
// TODO: grab coin uri scheme from somewhere
|
||||
// data: "${coin.uriScheme}:$receivingAddress",
|
||||
data: model.trade!.payinAddress,
|
||||
data: model.trade!.payInAddress,
|
||||
size: MediaQuery.of(context)
|
||||
.size
|
||||
.width /
|
||||
|
@ -496,7 +490,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
Format.decimalAmountToSatoshis(
|
||||
model.sendAmount);
|
||||
final address =
|
||||
model.trade!.payinAddress;
|
||||
model.trade!.payInAddress;
|
||||
|
||||
try {
|
||||
bool wasCancelled = false;
|
||||
|
@ -534,7 +528,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
}
|
||||
|
||||
txData["note"] =
|
||||
"${model.trade!.fromCurrency.toUpperCase()}/${model.trade!.toCurrency.toUpperCase()} exchange";
|
||||
"${model.trade!.payInCurrency.toUpperCase()}/${model.trade!.payOutCurrency.toUpperCase()} exchange";
|
||||
txData["address"] = address;
|
||||
|
||||
if (mounted) {
|
||||
|
@ -611,10 +605,10 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
coin:
|
||||
coinFromTickerCaseInsensitive(
|
||||
model.trade!
|
||||
.fromCurrency),
|
||||
.payInCurrency),
|
||||
amount: model.sendAmount,
|
||||
address:
|
||||
model.trade!.payinAddress,
|
||||
model.trade!.payInAddress,
|
||||
trade: model.trade!,
|
||||
);
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,7 +4,7 @@ import 'package:decimal/decimal.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/confirm_change_now_send.dart';
|
||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
||||
|
@ -36,7 +36,7 @@ class SendFromView extends ConsumerStatefulWidget {
|
|||
final Coin coin;
|
||||
final Decimal amount;
|
||||
final String address;
|
||||
final ExchangeTransaction trade;
|
||||
final Trade trade;
|
||||
|
||||
@override
|
||||
ConsumerState<SendFromView> createState() => _SendFromViewState();
|
||||
|
@ -46,7 +46,7 @@ class _SendFromViewState extends ConsumerState<SendFromView> {
|
|||
late final Coin coin;
|
||||
late final Decimal amount;
|
||||
late final String address;
|
||||
late final ExchangeTransaction trade;
|
||||
late final Trade trade;
|
||||
|
||||
String formatAmount(Decimal amount, Coin coin) {
|
||||
switch (coin) {
|
||||
|
@ -148,7 +148,7 @@ class SendFromCard extends ConsumerStatefulWidget {
|
|||
final String walletId;
|
||||
final Decimal amount;
|
||||
final String address;
|
||||
final ExchangeTransaction trade;
|
||||
final Trade trade;
|
||||
|
||||
@override
|
||||
ConsumerState<SendFromCard> createState() => _SendFromCardState();
|
||||
|
@ -158,7 +158,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
late final String walletId;
|
||||
late final Decimal amount;
|
||||
late final String address;
|
||||
late final ExchangeTransaction trade;
|
||||
late final Trade trade;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -230,7 +230,7 @@ class _SendFromCardState extends ConsumerState<SendFromCard> {
|
|||
}
|
||||
|
||||
txData["note"] =
|
||||
"${trade.fromCurrency.toUpperCase()}/${trade.toCurrency.toUpperCase()} exchange";
|
||||
"${trade.payInCurrency.toUpperCase()}/${trade.payOutCurrency.toUpperCase()} exchange";
|
||||
txData["address"] = address;
|
||||
|
||||
if (mounted) {
|
||||
|
|
|
@ -0,0 +1,380 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/animated_text.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
class ExchangeProviderOptions extends ConsumerWidget {
|
||||
const ExchangeProviderOptions({
|
||||
Key? key,
|
||||
required this.from,
|
||||
required this.to,
|
||||
required this.fromAmount,
|
||||
required this.toAmount,
|
||||
required this.fixedRate,
|
||||
required this.reversed,
|
||||
}) : super(key: key);
|
||||
|
||||
final String? from;
|
||||
final String? to;
|
||||
final Decimal? fromAmount;
|
||||
final Decimal? toAmount;
|
||||
final bool fixedRate;
|
||||
final bool reversed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return RoundedWhiteContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (ref.read(currentExchangeNameStateProvider.state).state !=
|
||||
ChangeNowExchange.exchangeName) {
|
||||
ref.read(currentExchangeNameStateProvider.state).state =
|
||||
ChangeNowExchange.exchangeName;
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: ChangeNowExchange.exchangeName,
|
||||
groupValue: ref
|
||||
.watch(currentExchangeNameStateProvider.state)
|
||||
.state,
|
||||
onChanged: (value) {
|
||||
if (value is String) {
|
||||
ref
|
||||
.read(currentExchangeNameStateProvider.state)
|
||||
.state = value;
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.exchange.changeNow,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
ChangeNowExchange.exchangeName,
|
||||
style: STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark2,
|
||||
),
|
||||
),
|
||||
if (from != null &&
|
||||
to != null &&
|
||||
toAmount != null &&
|
||||
toAmount! > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount! > Decimal.zero)
|
||||
FutureBuilder(
|
||||
future: ChangeNowExchange().getEstimate(
|
||||
from!,
|
||||
to!,
|
||||
reversed ? toAmount! : fromAmount!,
|
||||
fixedRate,
|
||||
reversed,
|
||||
),
|
||||
builder: (context,
|
||||
AsyncSnapshot<ExchangeResponse<Estimate>>
|
||||
snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
final estimate = snapshot.data?.value;
|
||||
if (estimate != null) {
|
||||
Decimal rate;
|
||||
if (estimate.reversed) {
|
||||
rate =
|
||||
(toAmount! / estimate.estimatedAmount)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 12);
|
||||
} else {
|
||||
rate =
|
||||
(estimate.estimatedAmount / fromAmount!)
|
||||
.toDecimal(
|
||||
scaleOnInfinitePrecision: 12);
|
||||
}
|
||||
return Text(
|
||||
"1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed(
|
||||
value: rate,
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
decimalPlaces: to!.toUpperCase() ==
|
||||
Coin.monero.ticker.toUpperCase()
|
||||
? Constants.decimalPlacesMonero
|
||||
: Constants.decimalPlaces,
|
||||
)} ${to!.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return Text(
|
||||
"Failed to fetch rate",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading",
|
||||
"Loading.",
|
||||
"Loading..",
|
||||
"Loading...",
|
||||
],
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!(from != null &&
|
||||
to != null &&
|
||||
toAmount != null &&
|
||||
toAmount! > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount! > Decimal.zero))
|
||||
Text(
|
||||
"n/a",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (ref.read(currentExchangeNameStateProvider.state).state !=
|
||||
SimpleSwapExchange.exchangeName) {
|
||||
ref.read(currentExchangeNameStateProvider.state).state =
|
||||
SimpleSwapExchange.exchangeName;
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: Radio(
|
||||
activeColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.radioButtonIconEnabled,
|
||||
value: SimpleSwapExchange.exchangeName,
|
||||
groupValue: ref
|
||||
.watch(currentExchangeNameStateProvider.state)
|
||||
.state,
|
||||
onChanged: (value) {
|
||||
if (value is String) {
|
||||
ref
|
||||
.read(currentExchangeNameStateProvider.state)
|
||||
.state = value;
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 14,
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.exchange.simpleSwap,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
SimpleSwapExchange.exchangeName,
|
||||
style: STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark2,
|
||||
),
|
||||
),
|
||||
if (from != null &&
|
||||
to != null &&
|
||||
toAmount != null &&
|
||||
toAmount! > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount! > Decimal.zero)
|
||||
FutureBuilder(
|
||||
future: SimpleSwapExchange().getEstimate(
|
||||
from!,
|
||||
to!,
|
||||
// reversed ? toAmount! : fromAmount!,
|
||||
fromAmount!,
|
||||
fixedRate,
|
||||
// reversed,
|
||||
false,
|
||||
),
|
||||
builder: (context,
|
||||
AsyncSnapshot<ExchangeResponse<Estimate>>
|
||||
snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
final estimate = snapshot.data?.value;
|
||||
if (estimate != null) {
|
||||
Decimal rate = (estimate.estimatedAmount /
|
||||
fromAmount!)
|
||||
.toDecimal(scaleOnInfinitePrecision: 12);
|
||||
|
||||
return Text(
|
||||
"1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed(
|
||||
value: rate,
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
decimalPlaces: to!.toUpperCase() ==
|
||||
Coin.monero.ticker.toUpperCase()
|
||||
? Constants.decimalPlacesMonero
|
||||
: Constants.decimalPlaces,
|
||||
)} ${to!.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for SimpleSwap: ${snapshot.data}",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return Text(
|
||||
"Failed to fetch rate",
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return AnimatedText(
|
||||
stringsToLoopThrough: const [
|
||||
"Loading",
|
||||
"Loading.",
|
||||
"Loading..",
|
||||
"Loading...",
|
||||
],
|
||||
style: STextStyles.itemSubtitle12(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
// if (!(from != null &&
|
||||
// to != null &&
|
||||
// (reversed
|
||||
// ? toAmount != null && toAmount! > Decimal.zero
|
||||
// : fromAmount != null &&
|
||||
// fromAmount! > Decimal.zero)))
|
||||
if (!(from != null &&
|
||||
to != null &&
|
||||
toAmount != null &&
|
||||
toAmount! > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount! > Decimal.zero))
|
||||
Text(
|
||||
"n/a",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
132
lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart
Normal file
132
lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart
Normal file
|
@ -0,0 +1,132 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
class RateTypeToggle extends ConsumerWidget {
|
||||
const RateTypeToggle({
|
||||
Key? key,
|
||||
this.onChanged,
|
||||
}) : super(key: key);
|
||||
|
||||
final void Function(ExchangeRateType)? onChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
final estimated = ref.watch(prefsChangeNotifierProvider
|
||||
.select((value) => value.exchangeRateType)) ==
|
||||
ExchangeRateType.estimated;
|
||||
|
||||
return RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (!estimated) {
|
||||
ref.read(prefsChangeNotifierProvider).exchangeRateType =
|
||||
ExchangeRateType.estimated;
|
||||
onChanged?.call(ExchangeRateType.estimated);
|
||||
}
|
||||
},
|
||||
child: RoundedContainer(
|
||||
color: estimated
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG
|
||||
: Colors.transparent,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.lock,
|
||||
width: 12,
|
||||
height: 14,
|
||||
color: estimated
|
||||
? Theme.of(context).extension<StackColors>()!.textDark
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Text(
|
||||
"Estimate rate",
|
||||
style: STextStyles.smallMed12(context).copyWith(
|
||||
color: estimated
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (estimated) {
|
||||
ref.read(prefsChangeNotifierProvider).exchangeRateType =
|
||||
ExchangeRateType.fixed;
|
||||
onChanged?.call(ExchangeRateType.fixed);
|
||||
}
|
||||
},
|
||||
child: RoundedContainer(
|
||||
color: !estimated
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG
|
||||
: Colors.transparent,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.lock,
|
||||
width: 12,
|
||||
height: 14,
|
||||
color: !estimated
|
||||
? Theme.of(context).extension<StackColors>()!.textDark
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
Text(
|
||||
"Fixed rate",
|
||||
style: STextStyles.smallMed12(context).copyWith(
|
||||
color: !estimated
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,10 +13,11 @@ import 'package:stackwallet/pages/exchange_view/edit_trade_note_view.dart';
|
|||
import 'package:stackwallet/pages/exchange_view/send_from_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/trade_note_service_provider.dart';
|
||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -82,18 +83,16 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
final trade = ref
|
||||
.read(tradesServiceProvider)
|
||||
.trades
|
||||
.firstWhere((e) => e.id == tradeId);
|
||||
.firstWhere((e) => e.tradeId == tradeId);
|
||||
|
||||
if (mounted && trade.statusObject == null ||
|
||||
trade.statusObject!.amountSendDecimal.isEmpty) {
|
||||
final status = await ref
|
||||
.read(changeNowProvider)
|
||||
.getTransactionStatus(id: trade.id);
|
||||
if (mounted) {
|
||||
final exchange = Exchange.fromName(trade.exchangeName);
|
||||
final response = await exchange.updateTrade(trade);
|
||||
|
||||
if (mounted && status.value != null) {
|
||||
await ref.read(tradesServiceProvider).edit(
|
||||
trade: trade.copyWith(statusObject: status.value),
|
||||
shouldNotifyListeners: true);
|
||||
if (mounted && response.value != null) {
|
||||
await ref
|
||||
.read(tradesServiceProvider)
|
||||
.edit(trade: response.value!, shouldNotifyListeners: true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -132,23 +131,29 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
final bool sentFromStack =
|
||||
transactionIfSentFromStack != null && walletId != null;
|
||||
|
||||
final trade = ref.watch(tradesServiceProvider
|
||||
.select((value) => value.trades.firstWhere((e) => e.id == tradeId)));
|
||||
final trade = ref.watch(tradesServiceProvider.select(
|
||||
(value) => value.trades.firstWhere((e) => e.tradeId == tradeId)));
|
||||
|
||||
final bool hasTx = sentFromStack ||
|
||||
!(trade.statusObject?.status == ChangeNowTransactionStatus.New ||
|
||||
trade.statusObject?.status == ChangeNowTransactionStatus.Waiting ||
|
||||
trade.statusObject?.status == ChangeNowTransactionStatus.Refunded ||
|
||||
trade.statusObject?.status == ChangeNowTransactionStatus.Failed);
|
||||
!(trade.status == "New" ||
|
||||
trade.status == "new" ||
|
||||
trade.status == "Waiting" ||
|
||||
trade.status == "waiting" ||
|
||||
trade.status == "Refunded" ||
|
||||
trade.status == "refunded" ||
|
||||
trade.status == "Closed" ||
|
||||
trade.status == "closed" ||
|
||||
trade.status == "Expired" ||
|
||||
trade.status == "expired" ||
|
||||
trade.status == "Failed" ||
|
||||
trade.status == "failed");
|
||||
|
||||
debugPrint("sentFromStack: $sentFromStack");
|
||||
debugPrint("hasTx: $hasTx");
|
||||
debugPrint("trade: ${trade.toString()}");
|
||||
|
||||
final sendAmount = Decimal.tryParse(
|
||||
trade.statusObject?.amountSendDecimal ?? "") ??
|
||||
Decimal.tryParse(trade.statusObject?.expectedSendAmountDecimal ?? "") ??
|
||||
Decimal.parse("-1");
|
||||
final sendAmount =
|
||||
Decimal.tryParse(trade.payInAmount) ?? Decimal.parse("-1");
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
|
@ -180,7 +185,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SelectableText(
|
||||
"${trade.fromCurrency.toUpperCase()} → ${trade.toCurrency.toUpperCase()}",
|
||||
"${trade.payInCurrency.toUpperCase()} → ${trade.payOutCurrency.toUpperCase()}",
|
||||
style: STextStyles.titleBold12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -190,7 +195,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
"${Format.localizedStringAsFixed(value: sendAmount, locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
), decimalPlaces: trade.fromCurrency.toLowerCase() == "xmr" ? 12 : 8)} ${trade.fromCurrency.toUpperCase()}",
|
||||
), decimalPlaces: trade.payInCurrency.toLowerCase() == "xmr" ? 12 : 8)} ${trade.payInCurrency.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
],
|
||||
|
@ -203,9 +208,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
_fetchIconAssetForStatus(
|
||||
trade.statusObject?.status.name ??
|
||||
trade.statusString),
|
||||
_fetchIconAssetForStatus(trade.status),
|
||||
width: 32,
|
||||
height: 32,
|
||||
),
|
||||
|
@ -229,15 +232,11 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
trade.statusObject?.status.name ?? trade.statusString,
|
||||
trade.status,
|
||||
style: STextStyles.itemSubtitle(context).copyWith(
|
||||
color: trade.statusObject != null
|
||||
? Theme.of(context)
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForStatus(trade.statusObject!.status)
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
.colorForStatus(trade.status),
|
||||
),
|
||||
),
|
||||
// ),
|
||||
|
@ -258,8 +257,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
text: TextSpan(
|
||||
text:
|
||||
"You must send at least ${sendAmount.toStringAsFixed(
|
||||
trade.fromCurrency.toLowerCase() == "xmr" ? 12 : 8,
|
||||
)} ${trade.fromCurrency.toUpperCase()}. ",
|
||||
trade.payInCurrency.toLowerCase() == "xmr" ? 12 : 8,
|
||||
)} ${trade.payInCurrency.toUpperCase()}. ",
|
||||
style: STextStyles.label700(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
@ -269,10 +268,10 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
TextSpan(
|
||||
text:
|
||||
"If you send less than ${sendAmount.toStringAsFixed(
|
||||
trade.fromCurrency.toLowerCase() == "xmr"
|
||||
trade.payInCurrency.toLowerCase() == "xmr"
|
||||
? 12
|
||||
: 8,
|
||||
)} ${trade.fromCurrency.toUpperCase()}, your transaction may not be converted and it may not be refunded.",
|
||||
)} ${trade.payInCurrency.toUpperCase()}, your transaction may not be converted and it may not be refunded.",
|
||||
style: STextStyles.label(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
@ -308,7 +307,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
GestureDetector(
|
||||
onTap: () {
|
||||
final Coin coin = coinFromTickerCaseInsensitive(
|
||||
trade.fromCurrency);
|
||||
trade.payInCurrency);
|
||||
|
||||
Navigator.of(context).pushNamed(
|
||||
TransactionDetailsView.routeName,
|
||||
|
@ -334,14 +333,14 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"ChangeNOW address",
|
||||
"${trade.exchangeName} address",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
trade.payinAddress,
|
||||
trade.payInAddress,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
|
@ -360,12 +359,12 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Send ${trade.fromCurrency.toUpperCase()} to this address",
|
||||
"Send ${trade.payInCurrency.toUpperCase()} to this address",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final address = trade.payinAddress;
|
||||
final address = trade.payInAddress;
|
||||
await Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: address,
|
||||
|
@ -403,7 +402,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
height: 4,
|
||||
),
|
||||
SelectableText(
|
||||
trade.payinAddress,
|
||||
trade.payInAddress,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -425,7 +424,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
children: [
|
||||
Center(
|
||||
child: Text(
|
||||
"Send ${trade.fromCurrency.toUpperCase()} to this address",
|
||||
"Send ${trade.payInCurrency.toUpperCase()} to this address",
|
||||
style:
|
||||
STextStyles.pageTitleH2(context),
|
||||
),
|
||||
|
@ -440,7 +439,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
width: width + 20,
|
||||
height: width + 20,
|
||||
child: QrImage(
|
||||
data: trade.payinAddress,
|
||||
data: trade.payInAddress,
|
||||
size: width,
|
||||
backgroundColor: Theme.of(
|
||||
context)
|
||||
|
@ -658,7 +657,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
// child:
|
||||
SelectableText(
|
||||
Format.extractDateFrom(
|
||||
trade.date.millisecondsSinceEpoch ~/ 1000),
|
||||
trade.timestamp.millisecondsSinceEpoch ~/ 1000),
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
// ),
|
||||
|
@ -677,16 +676,10 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
"Exchange",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
// Flexible(
|
||||
// child: FittedBox(
|
||||
// fit: BoxFit.scaleDown,
|
||||
// child:
|
||||
SelectableText(
|
||||
"ChangeNOW",
|
||||
trade.exchangeName,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -704,7 +697,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
Row(
|
||||
children: [
|
||||
Text(
|
||||
trade.id,
|
||||
trade.tradeId,
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -712,7 +705,7 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final data = ClipboardData(text: trade.id);
|
||||
final data = ClipboardData(text: trade.tradeId);
|
||||
await clipboard.setData(data);
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.info,
|
||||
|
@ -747,40 +740,50 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
GestureDetector(
|
||||
Builder(builder: (context) {
|
||||
late final String url;
|
||||
switch (trade.exchangeName) {
|
||||
case ChangeNowExchange.exchangeName:
|
||||
url =
|
||||
"https://changenow.io/exchange/txs/${trade.tradeId}";
|
||||
break;
|
||||
case SimpleSwapExchange.exchangeName:
|
||||
url =
|
||||
"https://simpleswap.io/exchange?id=${trade.tradeId}";
|
||||
break;
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
final url =
|
||||
"https://changenow.io/exchange/txs/${trade.id}";
|
||||
launchUrl(
|
||||
Uri.parse(url),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
"https://changenow.io/exchange/txs/${trade.id}",
|
||||
url,
|
||||
style: STextStyles.link2(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
if (isStackCoin(trade.fromCurrency) &&
|
||||
trade.statusObject != null &&
|
||||
(trade.statusObject!.status ==
|
||||
ChangeNowTransactionStatus.New ||
|
||||
trade.statusObject!.status ==
|
||||
ChangeNowTransactionStatus.Waiting))
|
||||
if (isStackCoin(trade.payInCurrency) &&
|
||||
(trade.status == "New" ||
|
||||
trade.status == "new" ||
|
||||
trade.status == "waiting" ||
|
||||
trade.status == "Waiting"))
|
||||
SecondaryButton(
|
||||
label: "Send from Stack",
|
||||
onPressed: () {
|
||||
final amount = sendAmount;
|
||||
final address = trade.payinAddress;
|
||||
final address = trade.payInAddress;
|
||||
|
||||
final coin =
|
||||
coinFromTickerCaseInsensitive(trade.fromCurrency);
|
||||
coinFromTickerCaseInsensitive(trade.payInCurrency);
|
||||
|
||||
Navigator.of(context).pushNamed(
|
||||
SendFromView.routeName,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,7 +13,7 @@ import 'package:stackwallet/pages/wallets_view/wallets_view.dart';
|
|||
import 'package:stackwallet/providers/global/notifications_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/home_view_index_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now_loading_service.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -41,7 +41,7 @@ class _HomeViewState extends ConsumerState<HomeView> {
|
|||
|
||||
bool _exitEnabled = false;
|
||||
|
||||
final _cnLoadingService = ChangeNowLoadingService();
|
||||
final _cnLoadingService = ExchangeDataLoadingService();
|
||||
|
||||
Future<bool> _onWillPop() async {
|
||||
// go to home view when tapping back on the main exchange view
|
||||
|
|
|
@ -1,16 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/exchange_view.dart';
|
||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
@ -26,111 +17,14 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
|||
final DateTime _lastRefreshed = DateTime.now();
|
||||
final Duration _refreshInterval = const Duration(hours: 1);
|
||||
|
||||
Future<void> _loadChangeNowData(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
) async {
|
||||
List<Future<void>> futures = [];
|
||||
if (kFixedRateEnabled) {
|
||||
futures.add(_loadFixedRateMarkets(context, ref));
|
||||
}
|
||||
futures.add(_loadStandardCurrencies(context, ref));
|
||||
|
||||
await Future.wait(futures);
|
||||
}
|
||||
|
||||
Future<void> _loadStandardCurrencies(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
) async {
|
||||
final response = await ref.read(changeNowProvider).getAvailableCurrencies();
|
||||
final response2 =
|
||||
await ref.read(changeNowProvider).getAvailableFloatingRatePairs();
|
||||
if (response.value != null && response2.value != null) {
|
||||
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
||||
response.value!;
|
||||
ref.read(availableFloatingRatePairsStateProvider.state).state =
|
||||
response2.value!;
|
||||
|
||||
if (response.value!.length > 1) {
|
||||
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
||||
if (response.value!.where((e) => e.ticker == "btc").isNotEmpty) {
|
||||
await ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
||||
response.value!.firstWhere((e) => e.ticker == "btc"), true);
|
||||
}
|
||||
}
|
||||
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
||||
if (response.value!.where((e) => e.ticker == "doge").isNotEmpty) {
|
||||
await ref.read(estimatedRateExchangeFormProvider).updateTo(
|
||||
response.value!.firstWhere((e) => e.ticker == "doge"), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logging.instance
|
||||
.log("loaded floating rate change now data", level: LogLevel.Info);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Failed to load changeNOW floating rate market data: \n${response.exception?.errorMessage}\n${response2.exception?.toString()}",
|
||||
level: LogLevel.Error);
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (_) => StackDialog(
|
||||
title: "Failed to fetch available currencies",
|
||||
message:
|
||||
"${response.exception?.toString()}\n\n${response2.exception?.toString()}",
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadFixedRateMarkets(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
) async {
|
||||
final response3 =
|
||||
await ref.read(changeNowProvider).getAvailableFixedRateMarkets();
|
||||
|
||||
if (response3.value != null) {
|
||||
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
||||
response3.value!;
|
||||
|
||||
if (ref.read(fixedRateExchangeFormProvider).market == null) {
|
||||
final matchingMarkets =
|
||||
response3.value!.where((e) => e.to == "doge" && e.from == "btc");
|
||||
|
||||
if (matchingMarkets.isNotEmpty) {
|
||||
await ref
|
||||
.read(fixedRateExchangeFormProvider)
|
||||
.updateMarket(matchingMarkets.first, true);
|
||||
}
|
||||
}
|
||||
Logging.instance
|
||||
.log("loaded fixed rate change now data", level: LogLevel.Info);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"Failed to load changeNOW fixed rate markets: ${response3.exception?.errorMessage}",
|
||||
level: LogLevel.Error);
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (_) => StackDialog(
|
||||
title: "ChangeNOW API call failed",
|
||||
message: "${response3.exception?.toString()}",
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
ref.read(estimatedRateExchangeFormProvider).setOnError(
|
||||
ref.read(exchangeFormStateProvider).setOnError(
|
||||
onError: (String message) => showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: true,
|
||||
builder: (_) => StackDialog(
|
||||
title: "ChangeNOW API Call Failed",
|
||||
title: "Exchange API Call Failed",
|
||||
message: message,
|
||||
),
|
||||
),
|
||||
|
@ -224,7 +118,7 @@ class _HomeViewButtonBarState extends ConsumerState<HomeViewButtonBar> {
|
|||
// // },
|
||||
// ),
|
||||
// );
|
||||
await _loadChangeNowData(context, ref);
|
||||
await ExchangeDataLoadingService().loadAll(ref);
|
||||
// if (!okPressed && mounted) {
|
||||
// Navigator.of(context).pop();
|
||||
// }
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:stackwallet/hive/db.dart';
|
|||
import 'package:stackwallet/models/contact.dart';
|
||||
import 'package:stackwallet/models/contact_address_entry.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/models/stack_restoring_ui_state.dart';
|
||||
import 'package:stackwallet/models/trade_wallet_lookup.dart';
|
||||
|
@ -1026,8 +1027,7 @@ abstract class SWB {
|
|||
// trade existed before attempted restore so we don't delete it, only
|
||||
// revert data to pre restore state
|
||||
await tradesService.edit(
|
||||
trade: ExchangeTransaction.fromJson(
|
||||
tradeData as Map<String, dynamic>),
|
||||
trade: Trade.fromMap(tradeData as Map<String, dynamic>),
|
||||
shouldNotifyListeners: true);
|
||||
} else {
|
||||
// trade did not exist before so we delete it
|
||||
|
@ -1048,7 +1048,7 @@ abstract class SWB {
|
|||
}
|
||||
} else {
|
||||
// grab all trade IDs of (reverted to pre state) trades
|
||||
final idsToKeep = tradesService.trades.map((e) => e.id);
|
||||
final idsToKeep = tradesService.trades.map((e) => e.tradeId);
|
||||
|
||||
// delete all notes that don't correspond to an id that we have
|
||||
for (final noteEntry in currentNotes.entries) {
|
||||
|
@ -1189,16 +1189,44 @@ abstract class SWB {
|
|||
) async {
|
||||
final tradesService = TradesService();
|
||||
for (int i = 0; i < trades.length - 1; i++) {
|
||||
ExchangeTransaction? exTx;
|
||||
try {
|
||||
exTx = ExchangeTransaction.fromJson(trades[i] as Map<String, dynamic>);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Warning);
|
||||
}
|
||||
|
||||
Trade trade;
|
||||
if (exTx != null) {
|
||||
trade = Trade.fromExchangeTransaction(exTx, false);
|
||||
} else {
|
||||
trade = Trade.fromMap(trades[i] as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
await tradesService.add(
|
||||
trade: ExchangeTransaction.fromJson(trades[i] as Map<String, dynamic>),
|
||||
trade: trade,
|
||||
shouldNotifyListeners: false,
|
||||
);
|
||||
}
|
||||
// only call notifyListeners on last one added
|
||||
if (trades.isNotEmpty) {
|
||||
ExchangeTransaction? exTx;
|
||||
try {
|
||||
exTx =
|
||||
ExchangeTransaction.fromJson(trades.last as Map<String, dynamic>);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Warning);
|
||||
}
|
||||
|
||||
Trade trade;
|
||||
if (exTx != null) {
|
||||
trade = Trade.fromExchangeTransaction(exTx, false);
|
||||
} else {
|
||||
trade = Trade.fromMap(trades.last as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
await tradesService.add(
|
||||
trade:
|
||||
ExchangeTransaction.fromJson(trades.last as Map<String, dynamic>),
|
||||
trade: trade,
|
||||
shouldNotifyListeners: true,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -389,7 +389,7 @@ class _StackRestoreProgressViewState
|
|||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "ChangeNOW history",
|
||||
title: "Exchange history",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
|
|
|
@ -3,7 +3,9 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/paymint/transactions_model.dart';
|
||||
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/no_transactions_found.dart';
|
||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
|
@ -13,9 +15,6 @@ import 'package:stackwallet/widgets/trade_card.dart';
|
|||
import 'package:stackwallet/widgets/transaction_card.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
import '../../../providers/global/trades_service_provider.dart';
|
||||
import '../../exchange_view/trade_details_view.dart';
|
||||
|
||||
class TransactionsList extends ConsumerStatefulWidget {
|
||||
const TransactionsList({
|
||||
Key? key,
|
||||
|
@ -135,9 +134,7 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
|||
.read(tradesServiceProvider)
|
||||
.trades
|
||||
.where((e) =>
|
||||
e.statusObject != null &&
|
||||
(e.statusObject!.payinHash == tx.txid ||
|
||||
e.statusObject!.payoutHash == tx.txid));
|
||||
e.payInTxid == tx.txid || e.payOutTxid == tx.txid);
|
||||
if (tx.txType == "Sent" && matchingTrades.isNotEmpty) {
|
||||
final trade = matchingTrades.first;
|
||||
return Container(
|
||||
|
@ -164,7 +161,7 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
|||
Navigator.of(context).pushNamed(
|
||||
TradeDetailsView.routeName,
|
||||
arguments: Tuple4(
|
||||
trade.id,
|
||||
trade.tradeId,
|
||||
tx,
|
||||
widget.walletId,
|
||||
ref.read(managerProvider).walletName,
|
||||
|
|
|
@ -18,20 +18,19 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/transactions_list.dart
|
|||
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_navigation_bar.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_summary.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/transaction_views/all_transactions_view.dart';
|
||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now_loading_service.dart';
|
||||
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||
|
@ -79,7 +78,7 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
late StreamSubscription<dynamic> _syncStatusSubscription;
|
||||
late StreamSubscription<dynamic> _nodeStatusSubscription;
|
||||
|
||||
final _cnLoadingService = ChangeNowLoadingService();
|
||||
final _cnLoadingService = ExchangeDataLoadingService();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -236,50 +235,59 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => const StackOkDialog(
|
||||
title: "ChangeNOW not available for Epic Cash",
|
||||
title: "Exchange not available for Epic Cash",
|
||||
),
|
||||
);
|
||||
} else if (coin.name.endsWith("TestNet")) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => const StackOkDialog(
|
||||
title: "ChangeNOW not available for test net coins",
|
||||
title: "Exchange not available for test net coins",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ref.read(currentExchangeNameStateProvider.state).state =
|
||||
ChangeNowExchange.exchangeName;
|
||||
final walletId = ref.read(managerProvider).walletId;
|
||||
ref.read(prefsChangeNotifierProvider).exchangeRateType =
|
||||
ExchangeRateType.estimated;
|
||||
|
||||
ref.read(exchangeFormStateProvider).exchange = ref.read(exchangeProvider);
|
||||
ref.read(exchangeFormStateProvider).exchangeType =
|
||||
ExchangeRateType.estimated;
|
||||
|
||||
final currencies = ref
|
||||
.read(availableChangeNowCurrenciesStateProvider.state)
|
||||
.state
|
||||
.read(availableChangeNowCurrenciesProvider)
|
||||
.currencies
|
||||
.where((element) =>
|
||||
element.ticker.toLowerCase() == coin.ticker.toLowerCase());
|
||||
|
||||
if (currencies.isNotEmpty) {
|
||||
unawaited(ref
|
||||
.read(estimatedRateExchangeFormProvider)
|
||||
.updateFrom(currencies.first, false));
|
||||
unawaited(ref.read(estimatedRateExchangeFormProvider).updateTo(
|
||||
ref.read(exchangeFormStateProvider).setCurrencies(
|
||||
currencies.first,
|
||||
ref
|
||||
.read(availableChangeNowCurrenciesStateProvider.state)
|
||||
.state
|
||||
.read(availableChangeNowCurrenciesProvider)
|
||||
.currencies
|
||||
.firstWhere(
|
||||
(element) =>
|
||||
element.ticker.toLowerCase() != coin.ticker.toLowerCase(),
|
||||
element.ticker.toLowerCase() !=
|
||||
coin.ticker.toLowerCase(),
|
||||
),
|
||||
false));
|
||||
);
|
||||
}
|
||||
|
||||
unawaited(Navigator.of(context).pushNamed(
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamed(
|
||||
WalletInitiatedExchangeView.routeName,
|
||||
arguments: Tuple3(
|
||||
walletId,
|
||||
coin,
|
||||
_loadCNData,
|
||||
),
|
||||
));
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/cn_available_currencies.dart';
|
||||
|
||||
final availableChangeNowCurrenciesProvider = Provider<CNAvailableCurrencies>(
|
||||
(ref) => CNAvailableCurrencies(),
|
||||
);
|
|
@ -1,5 +0,0 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
||||
|
||||
final availableChangeNowCurrenciesStateProvider =
|
||||
StateProvider<List<Currency>>((ref) => <Currency>[]);
|
|
@ -1,6 +0,0 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart';
|
||||
|
||||
final availableFloatingRatePairsStateProvider =
|
||||
StateProvider<List<AvailableFloatingRatePair>>(
|
||||
(ref) => <AvailableFloatingRatePair>[]);
|
|
@ -0,0 +1,6 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/simpleswap/sp_available_currencies.dart';
|
||||
|
||||
final availableSimpleswapCurrenciesProvider = Provider<SPAvailableCurrencies>(
|
||||
(ref) => SPAvailableCurrencies(),
|
||||
);
|
|
@ -1,4 +0,0 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||
|
||||
final changeNowProvider = Provider<ChangeNow>((ref) => ChangeNow.instance);
|
|
@ -1,13 +1,14 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
enum ChangeNowLoadStatus {
|
||||
waiting,
|
||||
loading,
|
||||
success,
|
||||
failed,
|
||||
}
|
||||
|
||||
final changeNowEstimatedInitialLoadStatusStateProvider =
|
||||
StateProvider<ChangeNowLoadStatus>((ref) => ChangeNowLoadStatus.loading);
|
||||
StateProvider<ChangeNowLoadStatus>((ref) => ChangeNowLoadStatus.waiting);
|
||||
|
||||
final changeNowFixedInitialLoadStatusStateProvider =
|
||||
StateProvider<ChangeNowLoadStatus>((ref) => ChangeNowLoadStatus.loading);
|
||||
StateProvider<ChangeNowLoadStatus>((ref) => ChangeNowLoadStatus.waiting);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
|
||||
final currentExchangeNameStateProvider = StateProvider<String>(
|
||||
(ref) => ChangeNowExchange.exchangeName,
|
||||
);
|
|
@ -1,5 +0,0 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/estimated_rate_exchange_form_state.dart';
|
||||
|
||||
final estimatedRateExchangeFormProvider =
|
||||
ChangeNotifierProvider((ref) => EstimatedRateExchangeFormState());
|
6
lib/providers/exchange/exchange_form_state_provider.dart
Normal file
6
lib/providers/exchange/exchange_form_state_provider.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/exchange_form_state.dart';
|
||||
|
||||
final exchangeFormStateProvider = ChangeNotifierProvider<ExchangeFormState>(
|
||||
(ref) => ExchangeFormState(),
|
||||
);
|
9
lib/providers/exchange/exchange_provider.dart
Normal file
9
lib/providers/exchange/exchange_provider.dart
Normal file
|
@ -0,0 +1,9 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/exchange/current_exchange_name_state_provider.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
|
||||
final exchangeProvider = Provider<Exchange>(
|
||||
(ref) => Exchange.fromName(
|
||||
ref.watch(currentExchangeNameStateProvider.state).state,
|
||||
),
|
||||
);
|
|
@ -1,6 +0,0 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/fixed_rate_exchange_form_state.dart';
|
||||
|
||||
final fixedRateExchangeFormProvider =
|
||||
ChangeNotifierProvider<FixedRateExchangeFormState>(
|
||||
(ref) => FixedRateExchangeFormState());
|
|
@ -1,5 +0,0 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
|
||||
|
||||
final fixedRateMarketPairsStateProvider =
|
||||
StateProvider<List<FixedRateMarket>>((ref) => []);
|
|
@ -1,3 +1,13 @@
|
|||
export './exchange/available_changenow_currencies_provider.dart';
|
||||
export './exchange/available_simpleswap_currencies_provider.dart';
|
||||
export './exchange/changenow_initial_load_status.dart';
|
||||
export './exchange/current_exchange_name_state_provider.dart';
|
||||
export './exchange/exchange_flow_is_active_state_provider.dart';
|
||||
export './exchange/exchange_form_state_provider.dart';
|
||||
export './exchange/exchange_provider.dart';
|
||||
export './exchange/exchange_send_from_wallet_id_provider.dart';
|
||||
export './exchange/trade_note_service_provider.dart';
|
||||
export './exchange/trade_sent_from_stack_lookup_provider.dart';
|
||||
export './global/favorites_provider.dart';
|
||||
export './global/locale_provider.dart';
|
||||
export './global/node_service_provider.dart';
|
||||
|
|
|
@ -3,8 +3,8 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/models/contact_address_entry.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/paymint/transactions_model.dart';
|
||||
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
||||
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
|
||||
|
@ -898,7 +898,7 @@ class RouteGenerator {
|
|||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||
|
||||
case SendFromView.routeName:
|
||||
if (args is Tuple4<Coin, Decimal, String, ExchangeTransaction>) {
|
||||
if (args is Tuple4<Coin, Decimal, String, Trade>) {
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => SendFromView(
|
||||
|
|
|
@ -4,25 +4,27 @@ import 'package:decimal/decimal.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:stackwallet/external_api_keys.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class ChangeNow {
|
||||
class ChangeNowAPI {
|
||||
static const String scheme = "https";
|
||||
static const String authority = "api.changenow.io";
|
||||
static const String apiVersion = "/v1";
|
||||
static const String apiVersionV2 = "/v2";
|
||||
|
||||
ChangeNow._();
|
||||
static final ChangeNow _instance = ChangeNow._();
|
||||
static ChangeNow get instance => _instance;
|
||||
ChangeNowAPI._();
|
||||
static final ChangeNowAPI _instance = ChangeNowAPI._();
|
||||
static ChangeNowAPI get instance => _instance;
|
||||
|
||||
/// set this to override using standard http client. Useful for testing
|
||||
http.Client? client;
|
||||
|
@ -100,7 +102,7 @@ class ChangeNow {
|
|||
///
|
||||
/// Set [active] to true to return only active currencies.
|
||||
/// Set [fixedRate] to true to return only currencies available on a fixed-rate flow.
|
||||
Future<ChangeNowResponse<List<Currency>>> getAvailableCurrencies({
|
||||
Future<ExchangeResponse<List<Currency>>> getAvailableCurrencies({
|
||||
bool? fixedRate,
|
||||
bool? active,
|
||||
}) async {
|
||||
|
@ -129,26 +131,26 @@ class ChangeNow {
|
|||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableCurrencies exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Error: $jsonArray",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableCurrencies exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ChangeNowResponse<List<Currency>> _parseAvailableCurrenciesJson(
|
||||
ExchangeResponse<List<Currency>> _parseAvailableCurrenciesJson(
|
||||
List<dynamic> jsonArray) {
|
||||
try {
|
||||
List<Currency> currencies = [];
|
||||
|
@ -158,13 +160,13 @@ class ChangeNow {
|
|||
currencies
|
||||
.add(Currency.fromJson(Map<String, dynamic>.from(json as Map)));
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException("Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError));
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException("Failed to serialize $json",
|
||||
ExchangeExceptionType.serializeResponseError));
|
||||
}
|
||||
}
|
||||
|
||||
return ChangeNowResponse(value: currencies);
|
||||
return ExchangeResponse(value: currencies);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
|
@ -175,7 +177,7 @@ class ChangeNow {
|
|||
///
|
||||
/// Required [ticker] to fetch paired currencies for.
|
||||
/// Set [fixedRate] to true to return only currencies available on a fixed-rate flow.
|
||||
Future<ChangeNowResponse<List<Currency>>> getPairedCurrencies({
|
||||
Future<ExchangeResponse<List<Currency>>> getPairedCurrencies({
|
||||
required String ticker,
|
||||
bool? fixedRate,
|
||||
}) async {
|
||||
|
@ -199,10 +201,10 @@ class ChangeNow {
|
|||
currencies
|
||||
.add(Currency.fromJson(Map<String, dynamic>.from(json as Map)));
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -210,18 +212,18 @@ class ChangeNow {
|
|||
} catch (e, s) {
|
||||
Logging.instance.log("getPairedCurrencies exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException("Error: $jsonArray",
|
||||
ChangeNowExceptionType.serializeResponseError));
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException("Error: $jsonArray",
|
||||
ExchangeExceptionType.serializeResponseError));
|
||||
}
|
||||
return ChangeNowResponse(value: currencies);
|
||||
return ExchangeResponse(value: currencies);
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("getPairedCurrencies exception: $e\n$s", level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -230,7 +232,7 @@ class ChangeNow {
|
|||
/// The API endpoint returns minimal payment amount required to make
|
||||
/// an exchange of [fromTicker] to [toTicker].
|
||||
/// If you try to exchange less, the transaction will most likely fail.
|
||||
Future<ChangeNowResponse<Decimal>> getMinimalExchangeAmount({
|
||||
Future<ExchangeResponse<Decimal>> getMinimalExchangeAmount({
|
||||
required String fromTicker,
|
||||
required String toTicker,
|
||||
String? apiKey,
|
||||
|
@ -245,22 +247,62 @@ class ChangeNow {
|
|||
|
||||
try {
|
||||
final value = Decimal.parse(json["minAmount"].toString());
|
||||
return ChangeNowResponse(value: value);
|
||||
return ExchangeResponse(value: value);
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getMinimalExchangeAmount exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The API endpoint returns minimal payment amount and maximum payment amount
|
||||
/// required to make an exchange. If you try to exchange less than minimum or
|
||||
/// more than maximum, the transaction will most likely fail. Any pair of
|
||||
/// assets has minimum amount and some of pairs have maximum amount.
|
||||
Future<ExchangeResponse<Range>> getRange({
|
||||
required String fromTicker,
|
||||
required String toTicker,
|
||||
required bool isFixedRate,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
Map<String, dynamic>? params = {"api_key": apiKey ?? kChangeNowApiKey};
|
||||
|
||||
final uri = _buildUri(
|
||||
"/exchange-range${isFixedRate ? "/fixed-rate" : ""}/${fromTicker}_$toTicker",
|
||||
params);
|
||||
|
||||
try {
|
||||
final jsonObject = await _makeGetRequest(uri);
|
||||
|
||||
final json = Map<String, dynamic>.from(jsonObject as Map);
|
||||
return ExchangeResponse(
|
||||
value: Range(
|
||||
max: Decimal.tryParse(json["maxAmount"]?.toString() ?? ""),
|
||||
min: Decimal.tryParse(json["minAmount"]?.toString() ?? ""),
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"getRange exception: $e\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -268,8 +310,7 @@ class ChangeNow {
|
|||
|
||||
/// Get estimated amount of [toTicker] cryptocurrency to receive
|
||||
/// for [fromAmount] of [fromTicker]
|
||||
Future<ChangeNowResponse<EstimatedExchangeAmount>>
|
||||
getEstimatedExchangeAmount({
|
||||
Future<ExchangeResponse<Estimate>> getEstimatedExchangeAmount({
|
||||
required String fromTicker,
|
||||
required String toTicker,
|
||||
required Decimal fromAmount,
|
||||
|
@ -289,22 +330,94 @@ class ChangeNow {
|
|||
try {
|
||||
final value = EstimatedExchangeAmount.fromJson(
|
||||
Map<String, dynamic>.from(json as Map));
|
||||
return ChangeNowResponse(value: value);
|
||||
return ExchangeResponse(
|
||||
value: Estimate(
|
||||
estimatedAmount: value.estimatedAmount,
|
||||
fixedRate: false,
|
||||
reversed: false,
|
||||
rateId: value.rateId,
|
||||
warningMessage: value.warningMessage,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getEstimatedExchangeAmount exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get estimated amount of [toTicker] cryptocurrency to receive
|
||||
/// for [fromAmount] of [fromTicker]
|
||||
Future<ExchangeResponse<Estimate>> getEstimatedExchangeAmountFixedRate({
|
||||
required String fromTicker,
|
||||
required String toTicker,
|
||||
required Decimal fromAmount,
|
||||
required bool reversed,
|
||||
bool useRateId = true,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
Map<String, dynamic> params = {
|
||||
"api_key": apiKey ?? kChangeNowApiKey,
|
||||
"useRateId": useRateId.toString(),
|
||||
};
|
||||
|
||||
late final Uri uri;
|
||||
if (reversed) {
|
||||
uri = _buildUri(
|
||||
"/exchange-deposit/fixed-rate/${fromAmount.toString()}/${fromTicker}_$toTicker",
|
||||
params,
|
||||
);
|
||||
} else {
|
||||
uri = _buildUri(
|
||||
"/exchange-amount/fixed-rate/${fromAmount.toString()}/${fromTicker}_$toTicker",
|
||||
params,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
// simple json object is expected here
|
||||
final json = await _makeGetRequest(uri);
|
||||
|
||||
try {
|
||||
final value = EstimatedExchangeAmount.fromJson(
|
||||
Map<String, dynamic>.from(json as Map));
|
||||
return ExchangeResponse(
|
||||
value: Estimate(
|
||||
estimatedAmount: value.estimatedAmount,
|
||||
fixedRate: true,
|
||||
reversed: reversed,
|
||||
rateId: value.rateId,
|
||||
warningMessage: value.warningMessage,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getEstimatedExchangeAmount exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -313,7 +426,7 @@ class ChangeNow {
|
|||
// old v1 version
|
||||
/// This API endpoint returns fixed-rate estimated exchange amount of
|
||||
/// [toTicker] cryptocurrency to receive for [fromAmount] of [fromTicker]
|
||||
// Future<ChangeNowResponse<EstimatedExchangeAmount>>
|
||||
// Future<ExchangeResponse<EstimatedExchangeAmount>>
|
||||
// getEstimatedFixedRateExchangeAmount({
|
||||
// required String fromTicker,
|
||||
// required String toTicker,
|
||||
|
@ -342,12 +455,12 @@ class ChangeNow {
|
|||
// try {
|
||||
// final value = EstimatedExchangeAmount.fromJson(
|
||||
// Map<String, dynamic>.from(json as Map));
|
||||
// return ChangeNowResponse(value: value);
|
||||
// return ExchangeResponse(value: value);
|
||||
// } catch (_) {
|
||||
// return ChangeNowResponse(
|
||||
// exception: ChangeNowException(
|
||||
// return ExchangeResponse(
|
||||
// exception: ExchangeException(
|
||||
// "Failed to serialize $json",
|
||||
// ChangeNowExceptionType.serializeResponseError,
|
||||
// ExchangeExceptionType.serializeResponseError,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
@ -355,10 +468,10 @@ class ChangeNow {
|
|||
// Logging.instance.log(
|
||||
// "getEstimatedFixedRateExchangeAmount exception: $e\n$s",
|
||||
// level: LogLevel.Error);
|
||||
// return ChangeNowResponse(
|
||||
// exception: ChangeNowException(
|
||||
// return ExchangeResponse(
|
||||
// exception: ExchangeException(
|
||||
// e.toString(),
|
||||
// ChangeNowExceptionType.generic,
|
||||
// ExchangeExceptionType.generic,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
@ -366,7 +479,7 @@ class ChangeNow {
|
|||
|
||||
/// Get estimated amount of [toTicker] cryptocurrency to receive
|
||||
/// for [fromAmount] of [fromTicker]
|
||||
Future<ChangeNowResponse<CNExchangeEstimate>> getEstimatedExchangeAmountV2({
|
||||
Future<ExchangeResponse<CNExchangeEstimate>> getEstimatedExchangeAmountV2({
|
||||
required String fromTicker,
|
||||
required String toTicker,
|
||||
required CNEstimateType fromOrTo,
|
||||
|
@ -413,22 +526,22 @@ class ChangeNow {
|
|||
try {
|
||||
final value =
|
||||
CNExchangeEstimate.fromJson(Map<String, dynamic>.from(json as Map));
|
||||
return ChangeNowResponse(value: value);
|
||||
return ExchangeResponse(value: value);
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getEstimatedExchangeAmountV2 exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -438,8 +551,7 @@ class ChangeNow {
|
|||
/// fixed-rate flow. Some currencies get enabled or disabled from time to
|
||||
/// time and the market info gets updates, so make sure to refresh the list
|
||||
/// occasionally. One time per minute is sufficient.
|
||||
Future<ChangeNowResponse<List<FixedRateMarket>>>
|
||||
getAvailableFixedRateMarkets({
|
||||
Future<ExchangeResponse<List<FixedRateMarket>>> getAvailableFixedRateMarkets({
|
||||
String? apiKey,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
|
@ -456,40 +568,40 @@ class ChangeNow {
|
|||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableFixedRateMarkets exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Error: $jsonArray",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableFixedRateMarkets exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ChangeNowResponse<List<FixedRateMarket>> _parseFixedRateMarketsJson(
|
||||
ExchangeResponse<List<FixedRateMarket>> _parseFixedRateMarketsJson(
|
||||
List<dynamic> jsonArray) {
|
||||
try {
|
||||
List<FixedRateMarket> markets = [];
|
||||
for (final json in jsonArray) {
|
||||
try {
|
||||
markets.add(
|
||||
FixedRateMarket.fromJson(Map<String, dynamic>.from(json as Map)));
|
||||
FixedRateMarket.fromMap(Map<String, dynamic>.from(json as Map)));
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException("Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError));
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException("Failed to serialize $json",
|
||||
ExchangeExceptionType.serializeResponseError));
|
||||
}
|
||||
}
|
||||
return ChangeNowResponse(value: markets);
|
||||
return ExchangeResponse(value: markets);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
|
@ -497,7 +609,7 @@ class ChangeNow {
|
|||
|
||||
/// The API endpoint creates a transaction, generates an address for
|
||||
/// sending funds and returns transaction attributes.
|
||||
Future<ChangeNowResponse<ExchangeTransaction>>
|
||||
Future<ExchangeResponse<ExchangeTransaction>>
|
||||
createStandardExchangeTransaction({
|
||||
required String fromTicker,
|
||||
required String toTicker,
|
||||
|
@ -535,12 +647,12 @@ class ChangeNow {
|
|||
try {
|
||||
final value = ExchangeTransaction.fromJson(
|
||||
Map<String, dynamic>.from(json as Map));
|
||||
return ChangeNowResponse(value: value);
|
||||
return ExchangeResponse(value: value);
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -548,10 +660,10 @@ class ChangeNow {
|
|||
Logging.instance.log(
|
||||
"createStandardExchangeTransaction exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -559,13 +671,14 @@ class ChangeNow {
|
|||
|
||||
/// The API endpoint creates a transaction, generates an address for
|
||||
/// sending funds and returns transaction attributes.
|
||||
Future<ChangeNowResponse<ExchangeTransaction>>
|
||||
Future<ExchangeResponse<ExchangeTransaction>>
|
||||
createFixedRateExchangeTransaction({
|
||||
required String fromTicker,
|
||||
required String toTicker,
|
||||
required String receivingAddress,
|
||||
required Decimal amount,
|
||||
required String rateId,
|
||||
required bool reversed,
|
||||
String extraId = "",
|
||||
String userId = "",
|
||||
String contactEmail = "",
|
||||
|
@ -577,7 +690,6 @@ class ChangeNow {
|
|||
"from": fromTicker,
|
||||
"to": toTicker,
|
||||
"address": receivingAddress,
|
||||
"amount": amount.toString(),
|
||||
"flow": "fixed-rate",
|
||||
"extraId": extraId,
|
||||
"userId": userId,
|
||||
|
@ -587,8 +699,16 @@ class ChangeNow {
|
|||
"rateId": rateId,
|
||||
};
|
||||
|
||||
if (reversed) {
|
||||
map["result"] = amount.toString();
|
||||
} else {
|
||||
map["amount"] = amount.toString();
|
||||
}
|
||||
|
||||
final uri = _buildUri(
|
||||
"/transactions/fixed-rate/${apiKey ?? kChangeNowApiKey}", null);
|
||||
"/transactions/fixed-rate${reversed ? "/from-result" : ""}/${apiKey ?? kChangeNowApiKey}",
|
||||
null,
|
||||
);
|
||||
|
||||
try {
|
||||
// simple json object is expected here
|
||||
|
@ -600,12 +720,12 @@ class ChangeNow {
|
|||
try {
|
||||
final value = ExchangeTransaction.fromJson(
|
||||
Map<String, dynamic>.from(json as Map));
|
||||
return ChangeNowResponse(value: value);
|
||||
return ExchangeResponse(value: value);
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -613,16 +733,16 @@ class ChangeNow {
|
|||
Logging.instance.log(
|
||||
"createFixedRateExchangeTransaction exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<ChangeNowResponse<ExchangeTransactionStatus>> getTransactionStatus({
|
||||
Future<ExchangeResponse<ExchangeTransactionStatus>> getTransactionStatus({
|
||||
required String id,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
|
@ -636,29 +756,28 @@ class ChangeNow {
|
|||
try {
|
||||
final value = ExchangeTransactionStatus.fromJson(
|
||||
Map<String, dynamic>.from(json as Map));
|
||||
return ChangeNowResponse(value: value);
|
||||
return ExchangeResponse(value: value);
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("getTransactionStatus exception: $e\n$s", level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<ChangeNowResponse<List<AvailableFloatingRatePair>>>
|
||||
getAvailableFloatingRatePairs({
|
||||
Future<ExchangeResponse<List<Pair>>> getAvailableFloatingRatePairs({
|
||||
bool includePartners = false,
|
||||
}) async {
|
||||
final uri = _buildUri("/market-info/available-pairs",
|
||||
|
@ -675,41 +794,49 @@ class ChangeNow {
|
|||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableFloatingRatePairs exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Error: $jsonArray",
|
||||
ChangeNowExceptionType.serializeResponseError,
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableFloatingRatePairs exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException(
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ChangeNowExceptionType.generic,
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ChangeNowResponse<List<AvailableFloatingRatePair>>
|
||||
_parseAvailableFloatingRatePairsJson(List<dynamic> jsonArray) {
|
||||
ExchangeResponse<List<Pair>> _parseAvailableFloatingRatePairsJson(
|
||||
List<dynamic> jsonArray) {
|
||||
try {
|
||||
List<AvailableFloatingRatePair> pairs = [];
|
||||
List<Pair> pairs = [];
|
||||
for (final json in jsonArray) {
|
||||
try {
|
||||
final List<String> stringPair = (json as String).split("_");
|
||||
pairs.add(AvailableFloatingRatePair(
|
||||
fromTicker: stringPair[0], toTicker: stringPair[1]));
|
||||
pairs.add(
|
||||
Pair(
|
||||
from: stringPair[0],
|
||||
to: stringPair[1],
|
||||
fromNetwork: "",
|
||||
toNetwork: "",
|
||||
fixedRate: false,
|
||||
floatingRate: true,
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
return ChangeNowResponse(
|
||||
exception: ChangeNowException("Failed to serialize $json",
|
||||
ChangeNowExceptionType.serializeResponseError));
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException("Failed to serialize $json",
|
||||
ExchangeExceptionType.serializeResponseError));
|
||||
}
|
||||
}
|
||||
return ChangeNowResponse(value: pairs);
|
||||
return ExchangeResponse(value: pairs);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
226
lib/services/exchange/change_now/change_now_exchange.dart
Normal file
226
lib/services/exchange/change_now/change_now_exchange.dart
Normal file
|
@ -0,0 +1,226 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class ChangeNowExchange extends Exchange {
|
||||
static const exchangeName = "ChangeNOW";
|
||||
|
||||
@override
|
||||
String get name => exchangeName;
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Trade>> createTrade({
|
||||
required String from,
|
||||
required String to,
|
||||
required bool fixedRate,
|
||||
required Decimal amount,
|
||||
required String addressTo,
|
||||
String? extraId,
|
||||
required String addressRefund,
|
||||
required String refundExtraId,
|
||||
String? rateId,
|
||||
required bool reversed,
|
||||
}) async {
|
||||
late final ExchangeResponse<ExchangeTransaction> response;
|
||||
if (fixedRate) {
|
||||
response = await ChangeNowAPI.instance.createFixedRateExchangeTransaction(
|
||||
fromTicker: from,
|
||||
toTicker: to,
|
||||
receivingAddress: addressTo,
|
||||
amount: amount,
|
||||
rateId: rateId!,
|
||||
extraId: extraId ?? "",
|
||||
refundAddress: addressRefund,
|
||||
refundExtraId: refundExtraId,
|
||||
reversed: reversed,
|
||||
);
|
||||
} else {
|
||||
response = await ChangeNowAPI.instance.createStandardExchangeTransaction(
|
||||
fromTicker: from,
|
||||
toTicker: to,
|
||||
receivingAddress: addressTo,
|
||||
amount: amount,
|
||||
extraId: extraId ?? "",
|
||||
refundAddress: addressRefund,
|
||||
refundExtraId: refundExtraId,
|
||||
);
|
||||
}
|
||||
if (response.exception != null) {
|
||||
return ExchangeResponse(exception: response.exception);
|
||||
}
|
||||
|
||||
final statusResponse = await ChangeNowAPI.instance
|
||||
.getTransactionStatus(id: response.value!.id);
|
||||
if (statusResponse.exception != null) {
|
||||
return ExchangeResponse(exception: statusResponse.exception);
|
||||
}
|
||||
|
||||
return ExchangeResponse(
|
||||
value: Trade.fromExchangeTransaction(
|
||||
response.value!.copyWith(
|
||||
statusObject: statusResponse.value!,
|
||||
),
|
||||
reversed,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(
|
||||
bool fixedRate,
|
||||
) async {
|
||||
return await ChangeNowAPI.instance.getAvailableCurrencies(
|
||||
fixedRate: fixedRate ? true : null,
|
||||
active: true,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate) async {
|
||||
// TODO: implement getAllPairs
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
bool fixedRate,
|
||||
bool reversed,
|
||||
) async {
|
||||
late final ExchangeResponse<Estimate> response;
|
||||
if (fixedRate) {
|
||||
response =
|
||||
await ChangeNowAPI.instance.getEstimatedExchangeAmountFixedRate(
|
||||
fromTicker: from,
|
||||
toTicker: to,
|
||||
fromAmount: amount,
|
||||
reversed: reversed,
|
||||
);
|
||||
} else {
|
||||
response = await ChangeNowAPI.instance.getEstimatedExchangeAmount(
|
||||
fromTicker: from,
|
||||
toTicker: to,
|
||||
fromAmount: amount,
|
||||
);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Range>> getRange(
|
||||
String from,
|
||||
String to,
|
||||
bool fixedRate,
|
||||
) async {
|
||||
return await ChangeNowAPI.instance.getRange(
|
||||
fromTicker: from,
|
||||
toTicker: to,
|
||||
isFixedRate: fixedRate,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Pair>>> getPairsFor(
|
||||
String currency,
|
||||
bool fixedRate,
|
||||
) async {
|
||||
// TODO: implement getPairsFor
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Trade>> getTrade(String tradeId) async {
|
||||
final response =
|
||||
await ChangeNowAPI.instance.getTransactionStatus(id: tradeId);
|
||||
if (response.exception != null) {
|
||||
return ExchangeResponse(exception: response.exception);
|
||||
}
|
||||
final t = response.value!;
|
||||
final timestamp = DateTime.tryParse(t.createdAt) ?? DateTime.now();
|
||||
|
||||
final trade = Trade(
|
||||
uuid: const Uuid().v1(),
|
||||
tradeId: tradeId,
|
||||
rateType: "",
|
||||
direction: "",
|
||||
timestamp: timestamp,
|
||||
updatedAt: DateTime.tryParse(t.updatedAt) ?? timestamp,
|
||||
payInCurrency: t.fromCurrency,
|
||||
payInAmount: t.expectedSendAmountDecimal,
|
||||
payInAddress: t.payinAddress,
|
||||
payInNetwork: "",
|
||||
payInExtraId: t.payinExtraId,
|
||||
payInTxid: t.payinHash,
|
||||
payOutCurrency: t.toCurrency,
|
||||
payOutAmount: t.expectedReceiveAmountDecimal,
|
||||
payOutAddress: t.payoutAddress,
|
||||
payOutNetwork: "",
|
||||
payOutExtraId: t.payoutExtraId,
|
||||
payOutTxid: t.payoutHash,
|
||||
refundAddress: t.refundAddress,
|
||||
refundExtraId: t.refundExtraId,
|
||||
status: t.status.name,
|
||||
exchangeName: ChangeNowExchange.exchangeName,
|
||||
);
|
||||
|
||||
return ExchangeResponse(value: trade);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Trade>> updateTrade(Trade trade) async {
|
||||
final response =
|
||||
await ChangeNowAPI.instance.getTransactionStatus(id: trade.tradeId);
|
||||
if (response.exception != null) {
|
||||
return ExchangeResponse(exception: response.exception);
|
||||
}
|
||||
final t = response.value!;
|
||||
final timestamp = DateTime.tryParse(t.createdAt) ?? DateTime.now();
|
||||
|
||||
final _trade = Trade(
|
||||
uuid: trade.uuid,
|
||||
tradeId: trade.tradeId,
|
||||
rateType: trade.rateType,
|
||||
direction: trade.direction,
|
||||
timestamp: timestamp,
|
||||
updatedAt: DateTime.tryParse(t.updatedAt) ?? timestamp,
|
||||
payInCurrency: t.fromCurrency,
|
||||
payInAmount: t.amountSendDecimal.isEmpty
|
||||
? t.expectedSendAmountDecimal
|
||||
: t.amountSendDecimal,
|
||||
payInAddress: t.payinAddress,
|
||||
payInNetwork: trade.payInNetwork,
|
||||
payInExtraId: t.payinExtraId,
|
||||
payInTxid: t.payinHash,
|
||||
payOutCurrency: t.toCurrency,
|
||||
payOutAmount: t.amountReceiveDecimal.isEmpty
|
||||
? t.expectedReceiveAmountDecimal
|
||||
: t.amountReceiveDecimal,
|
||||
payOutAddress: t.payoutAddress,
|
||||
payOutNetwork: trade.payOutNetwork,
|
||||
payOutExtraId: t.payoutExtraId,
|
||||
payOutTxid: t.payoutHash,
|
||||
refundAddress: t.refundAddress,
|
||||
refundExtraId: t.refundExtraId,
|
||||
status: t.status.name,
|
||||
exchangeName: ChangeNowExchange.exchangeName,
|
||||
);
|
||||
|
||||
return ExchangeResponse(value: _trade);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Trade>>> getTrades() async {
|
||||
// TODO: implement getTrades
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
65
lib/services/exchange/exchange.dart
Normal file
65
lib/services/exchange/exchange.dart
Normal file
|
@ -0,0 +1,65 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
|
||||
abstract class Exchange {
|
||||
static Exchange fromName(String name) {
|
||||
switch (name) {
|
||||
case ChangeNowExchange.exchangeName:
|
||||
return ChangeNowExchange();
|
||||
case SimpleSwapExchange.exchangeName:
|
||||
return SimpleSwapExchange();
|
||||
default:
|
||||
throw ArgumentError("Unknown exchange name");
|
||||
}
|
||||
}
|
||||
|
||||
String get name;
|
||||
|
||||
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(bool fixedRate);
|
||||
|
||||
Future<ExchangeResponse<List<Pair>>> getPairsFor(
|
||||
String currency,
|
||||
bool fixedRate,
|
||||
);
|
||||
|
||||
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate);
|
||||
|
||||
Future<ExchangeResponse<Trade>> getTrade(String tradeId);
|
||||
Future<ExchangeResponse<Trade>> updateTrade(Trade trade);
|
||||
|
||||
Future<ExchangeResponse<List<Trade>>> getTrades();
|
||||
|
||||
Future<ExchangeResponse<Range>> getRange(
|
||||
String from,
|
||||
String to,
|
||||
bool fixedRate,
|
||||
);
|
||||
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
bool fixedRate,
|
||||
bool reversed,
|
||||
);
|
||||
|
||||
Future<ExchangeResponse<Trade>> createTrade({
|
||||
required String from,
|
||||
required String to,
|
||||
required bool fixedRate,
|
||||
required Decimal amount,
|
||||
required String addressTo,
|
||||
String? extraId,
|
||||
required String addressRefund,
|
||||
required String refundExtraId,
|
||||
String? rateId,
|
||||
required bool reversed,
|
||||
});
|
||||
}
|
|
@ -1,23 +1,21 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/change_now_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/changenow_initial_load_status.dart';
|
||||
import 'package:stackwallet/providers/exchange/estimate_rate_exchange_form_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/fixed_rate_exchange_form_provider.dart';
|
||||
import 'package:stackwallet/providers/exchange/fixed_rate_market_pairs_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class ChangeNowLoadingService {
|
||||
class ExchangeDataLoadingService {
|
||||
Future<void> loadAll(WidgetRef ref, {Coin? coin}) async {
|
||||
try {
|
||||
await Future.wait([
|
||||
_loadFixedRateMarkets(ref, coin: coin),
|
||||
_loadChangeNowStandardCurrencies(ref, coin: coin),
|
||||
loadSimpleswapFixedRateCurrencies(ref),
|
||||
loadSimpleswapFloatingRateCurrencies(ref),
|
||||
]);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("ChangeNowLoadingService.loadAll failed: $e\n$s",
|
||||
Logging.instance.log("ExchangeDataLoadingService.loadAll failed: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
}
|
||||
}
|
||||
|
@ -33,12 +31,13 @@ class ChangeNowLoadingService {
|
|||
ChangeNowLoadStatus.loading;
|
||||
|
||||
final response3 =
|
||||
await ref.read(changeNowProvider).getAvailableFixedRateMarkets();
|
||||
await ChangeNowAPI.instance.getAvailableFixedRateMarkets();
|
||||
if (response3.value != null) {
|
||||
ref.read(fixedRateMarketPairsStateProvider.state).state =
|
||||
response3.value!;
|
||||
ref
|
||||
.read(availableChangeNowCurrenciesProvider)
|
||||
.updateMarkets(response3.value!);
|
||||
|
||||
if (ref.read(fixedRateExchangeFormProvider).market == null) {
|
||||
if (ref.read(exchangeFormStateProvider).market == null) {
|
||||
String fromTicker = "btc";
|
||||
String toTicker = "xmr";
|
||||
|
||||
|
@ -50,7 +49,7 @@ class ChangeNowLoadingService {
|
|||
.where((e) => e.to == toTicker && e.from == fromTicker);
|
||||
if (matchingMarkets.isNotEmpty) {
|
||||
await ref
|
||||
.read(fixedRateExchangeFormProvider)
|
||||
.read(exchangeFormStateProvider)
|
||||
.updateMarket(matchingMarkets.first, true);
|
||||
}
|
||||
}
|
||||
|
@ -68,8 +67,10 @@ class ChangeNowLoadingService {
|
|||
ChangeNowLoadStatus.success;
|
||||
}
|
||||
|
||||
Future<void> _loadChangeNowStandardCurrencies(WidgetRef ref,
|
||||
{Coin? coin}) async {
|
||||
Future<void> _loadChangeNowStandardCurrencies(
|
||||
WidgetRef ref, {
|
||||
Coin? coin,
|
||||
}) async {
|
||||
if (ref
|
||||
.read(changeNowEstimatedInitialLoadStatusStateProvider.state)
|
||||
.state ==
|
||||
|
@ -81,15 +82,18 @@ class ChangeNowLoadingService {
|
|||
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
|
||||
ChangeNowLoadStatus.loading;
|
||||
|
||||
final response = await ref.read(changeNowProvider).getAvailableCurrencies();
|
||||
final response = await ChangeNowAPI.instance.getAvailableCurrencies();
|
||||
final response2 =
|
||||
await ref.read(changeNowProvider).getAvailableFloatingRatePairs();
|
||||
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
|
||||
if (response.value != null) {
|
||||
ref.read(availableChangeNowCurrenciesStateProvider.state).state =
|
||||
response.value!;
|
||||
ref
|
||||
.read(availableChangeNowCurrenciesProvider)
|
||||
.updateCurrencies(response.value!);
|
||||
|
||||
if (response2.value != null) {
|
||||
ref.read(availableFloatingRatePairsStateProvider.state).state =
|
||||
response2.value!;
|
||||
ref
|
||||
.read(availableChangeNowCurrenciesProvider)
|
||||
.updateFloatingPairs(response2.value!);
|
||||
|
||||
String fromTicker = "btc";
|
||||
String toTicker = "xmr";
|
||||
|
@ -99,18 +103,18 @@ class ChangeNowLoadingService {
|
|||
}
|
||||
|
||||
if (response.value!.length > 1) {
|
||||
if (ref.read(estimatedRateExchangeFormProvider).from == null) {
|
||||
if (ref.read(exchangeFormStateProvider).from == null) {
|
||||
if (response.value!
|
||||
.where((e) => e.ticker == fromTicker)
|
||||
.isNotEmpty) {
|
||||
await ref.read(estimatedRateExchangeFormProvider).updateFrom(
|
||||
await ref.read(exchangeFormStateProvider).updateFrom(
|
||||
response.value!.firstWhere((e) => e.ticker == fromTicker),
|
||||
false);
|
||||
}
|
||||
}
|
||||
if (ref.read(estimatedRateExchangeFormProvider).to == null) {
|
||||
if (ref.read(exchangeFormStateProvider).to == null) {
|
||||
if (response.value!.where((e) => e.ticker == toTicker).isNotEmpty) {
|
||||
await ref.read(estimatedRateExchangeFormProvider).updateTo(
|
||||
await ref.read(exchangeFormStateProvider).updateTo(
|
||||
response.value!.firstWhere((e) => e.ticker == toTicker),
|
||||
false);
|
||||
}
|
||||
|
@ -137,4 +141,62 @@ class ChangeNowLoadingService {
|
|||
ref.read(changeNowEstimatedInitialLoadStatusStateProvider.state).state =
|
||||
ChangeNowLoadStatus.success;
|
||||
}
|
||||
|
||||
Future<void> loadSimpleswapFloatingRateCurrencies(WidgetRef ref) async {
|
||||
final exchange = SimpleSwapExchange();
|
||||
final responseCurrencies = await exchange.getAllCurrencies(false);
|
||||
|
||||
if (responseCurrencies.value != null) {
|
||||
ref
|
||||
.read(availableSimpleswapCurrenciesProvider)
|
||||
.updateFloatingCurrencies(responseCurrencies.value!);
|
||||
|
||||
final responsePairs = await exchange.getAllPairs(false);
|
||||
|
||||
if (responsePairs.value != null) {
|
||||
ref
|
||||
.read(availableSimpleswapCurrenciesProvider)
|
||||
.updateFloatingPairs(responsePairs.value!);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"loadSimpleswapFloatingRateCurrencies: $responsePairs",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"loadSimpleswapFloatingRateCurrencies: $responseCurrencies",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadSimpleswapFixedRateCurrencies(WidgetRef ref) async {
|
||||
final exchange = SimpleSwapExchange();
|
||||
final responseCurrencies = await exchange.getAllCurrencies(true);
|
||||
|
||||
if (responseCurrencies.value != null) {
|
||||
ref
|
||||
.read(availableSimpleswapCurrenciesProvider)
|
||||
.updateFixedCurrencies(responseCurrencies.value!);
|
||||
|
||||
final responsePairs = await exchange.getAllPairs(true);
|
||||
|
||||
if (responsePairs.value != null) {
|
||||
ref
|
||||
.read(availableSimpleswapCurrenciesProvider)
|
||||
.updateFixedPairs(responsePairs.value!);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"loadSimpleswapFixedRateCurrencies: $responsePairs",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"loadSimpleswapFixedRateCurrencies: $responseCurrencies",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
24
lib/services/exchange/exchange_response.dart
Normal file
24
lib/services/exchange/exchange_response.dart
Normal file
|
@ -0,0 +1,24 @@
|
|||
enum ExchangeExceptionType { generic, serializeResponseError }
|
||||
|
||||
class ExchangeException implements Exception {
|
||||
String errorMessage;
|
||||
ExchangeExceptionType type;
|
||||
ExchangeException(this.errorMessage, this.type);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
class ExchangeResponse<T> {
|
||||
late final T? value;
|
||||
late final ExchangeException? exception;
|
||||
|
||||
ExchangeResponse({this.value, this.exception});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "{error: $exception, value: $value}";
|
||||
}
|
||||
}
|
499
lib/services/exchange/simpleswap/simpleswap_api.dart
Normal file
499
lib/services/exchange/simpleswap/simpleswap_api.dart
Normal file
|
@ -0,0 +1,499 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:stackwallet/external_api_keys.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/exchange/simpleswap/sp_currency.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
class SimpleSwapAPI {
|
||||
static const String scheme = "https";
|
||||
static const String authority = "api.simpleswap.io";
|
||||
|
||||
SimpleSwapAPI._();
|
||||
static final SimpleSwapAPI _instance = SimpleSwapAPI._();
|
||||
static SimpleSwapAPI get instance => _instance;
|
||||
|
||||
/// set this to override using standard http client. Useful for testing
|
||||
http.Client? client;
|
||||
|
||||
Uri _buildUri(String path, Map<String, String>? params) {
|
||||
return Uri.https(authority, path, params);
|
||||
}
|
||||
|
||||
Future<dynamic> _makeGetRequest(Uri uri) async {
|
||||
final client = this.client ?? http.Client();
|
||||
try {
|
||||
final response = await client.get(
|
||||
uri,
|
||||
);
|
||||
|
||||
final parsed = jsonDecode(response.body);
|
||||
|
||||
return parsed;
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("_makeRequest($uri) threw: $e\n$s", level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<dynamic> _makePostRequest(
|
||||
Uri uri,
|
||||
Map<String, dynamic> body,
|
||||
) async {
|
||||
final client = this.client ?? http.Client();
|
||||
try {
|
||||
final response = await client.post(
|
||||
uri,
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: jsonEncode(body),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final parsed = jsonDecode(response.body);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
throw Exception("response: ${response.body}");
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("_makeRequest($uri) threw: $e\n$s", level: LogLevel.Error);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<ExchangeResponse<Trade>> createNewExchange({
|
||||
required bool isFixedRate,
|
||||
required String currencyFrom,
|
||||
required String currencyTo,
|
||||
required String addressTo,
|
||||
required String userRefundAddress,
|
||||
required String userRefundExtraId,
|
||||
required String amount,
|
||||
String? extraIdTo,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
Map<String, dynamic> body = {
|
||||
"fixed": isFixedRate,
|
||||
"currency_from": currencyFrom,
|
||||
"currency_to": currencyTo,
|
||||
"addressTo": addressTo,
|
||||
"userRefundAddress": userRefundAddress,
|
||||
"userRefundExtraId": userRefundExtraId,
|
||||
"amount": double.parse(amount),
|
||||
"extraIdTo": extraIdTo,
|
||||
};
|
||||
|
||||
final uri =
|
||||
_buildUri("/create_exchange", {"api_key": apiKey ?? kSimpleSwapApiKey});
|
||||
|
||||
try {
|
||||
final jsonObject = await _makePostRequest(uri, body);
|
||||
|
||||
final json = Map<String, dynamic>.from(jsonObject as Map);
|
||||
final trade = Trade(
|
||||
uuid: const Uuid().v1(),
|
||||
tradeId: json["id"] as String,
|
||||
rateType: json["type"] as String,
|
||||
direction: "direct",
|
||||
timestamp: DateTime.parse(json["timestamp"] as String),
|
||||
updatedAt: DateTime.parse(json["updated_at"] as String),
|
||||
payInCurrency: json["currency_from"] as String,
|
||||
payInAmount: json["amount_from"] as String,
|
||||
payInAddress: json["address_from"] as String,
|
||||
payInNetwork: "",
|
||||
payInExtraId: json["extra_id_from"] as String? ?? "",
|
||||
payInTxid: json["tx_from"] as String? ?? "",
|
||||
payOutCurrency: json["currency_to"] as String,
|
||||
payOutAmount: json["amount_to"] as String,
|
||||
payOutAddress: json["address_to"] as String,
|
||||
payOutNetwork: "",
|
||||
payOutExtraId: json["extra_id_to"] as String? ?? "",
|
||||
payOutTxid: json["tx_to"] as String? ?? "",
|
||||
refundAddress: json["user_refund_address"] as String,
|
||||
refundExtraId: json["user_refund_extra_id"] as String,
|
||||
status: json["status"] as String,
|
||||
exchangeName: SimpleSwapExchange.exchangeName,
|
||||
);
|
||||
return ExchangeResponse(value: trade, exception: null);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableCurrencies exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
value: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<ExchangeResponse<List<SPCurrency>>> getAllCurrencies({
|
||||
String? apiKey,
|
||||
required bool fixedRate,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
"/get_all_currencies", {"api_key": apiKey ?? kSimpleSwapApiKey});
|
||||
|
||||
try {
|
||||
final jsonArray = await _makeGetRequest(uri);
|
||||
|
||||
return await compute(_parseAvailableCurrenciesJson, jsonArray as List);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableCurrencies exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ExchangeResponse<List<SPCurrency>> _parseAvailableCurrenciesJson(
|
||||
List<dynamic> jsonArray) {
|
||||
try {
|
||||
List<SPCurrency> currencies = [];
|
||||
|
||||
for (final json in jsonArray) {
|
||||
try {
|
||||
currencies
|
||||
.add(SPCurrency.fromJson(Map<String, dynamic>.from(json as Map)));
|
||||
} catch (_) {
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException("Failed to serialize $json",
|
||||
ExchangeExceptionType.serializeResponseError));
|
||||
}
|
||||
}
|
||||
|
||||
return ExchangeResponse(value: currencies);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("_parseAvailableCurrenciesJson exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<ExchangeResponse<SPCurrency>> getCurrency({
|
||||
required String symbol,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
"/get_currency",
|
||||
{
|
||||
"api_key": apiKey ?? kSimpleSwapApiKey,
|
||||
"symbol": symbol,
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final jsonObject = await _makeGetRequest(uri);
|
||||
|
||||
return ExchangeResponse(
|
||||
value: SPCurrency.fromJson(
|
||||
Map<String, dynamic>.from(jsonObject as Map)));
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("getCurrency exception: $e\n$s", level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// returns a map where the key currency symbol is a valid pair with any of
|
||||
/// the symbols in its value list
|
||||
Future<ExchangeResponse<List<Pair>>> getAllPairs({
|
||||
required bool isFixedRate,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
"/get_all_pairs",
|
||||
{
|
||||
"api_key": apiKey ?? kSimpleSwapApiKey,
|
||||
"fixed": isFixedRate.toString(),
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final jsonObject = await _makeGetRequest(uri);
|
||||
final result = await compute(
|
||||
_parseAvailablePairsJson,
|
||||
Tuple2(jsonObject as Map, isFixedRate),
|
||||
);
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("getAllPairs exception: $e\n$s", level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ExchangeResponse<List<Pair>> _parseAvailablePairsJson(
|
||||
Tuple2<Map<dynamic, dynamic>, bool> args,
|
||||
) {
|
||||
try {
|
||||
List<Pair> pairs = [];
|
||||
|
||||
for (final entry in args.item1.entries) {
|
||||
try {
|
||||
final from = entry.key as String;
|
||||
for (final to in entry.value as List) {
|
||||
pairs.add(
|
||||
Pair(
|
||||
from: from,
|
||||
fromNetwork: "",
|
||||
to: to as String,
|
||||
toNetwork: "",
|
||||
fixedRate: args.item2,
|
||||
floatingRate: !args.item2,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException("Failed to serialize $json",
|
||||
ExchangeExceptionType.serializeResponseError));
|
||||
}
|
||||
}
|
||||
|
||||
return ExchangeResponse(value: pairs);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("_parseAvailableCurrenciesJson exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the estimated amount as a string
|
||||
Future<ExchangeResponse<String>> getEstimated({
|
||||
required bool isFixedRate,
|
||||
required String currencyFrom,
|
||||
required String currencyTo,
|
||||
required String amount,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
"/get_estimated",
|
||||
{
|
||||
"api_key": apiKey ?? kSimpleSwapApiKey,
|
||||
"fixed": isFixedRate.toString(),
|
||||
"currency_from": currencyFrom,
|
||||
"currency_to": currencyTo,
|
||||
"amount": amount,
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final jsonObject = await _makeGetRequest(uri);
|
||||
|
||||
return ExchangeResponse(value: jsonObject as String);
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("getEstimated exception: $e\n$s", level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the exchange for the given id
|
||||
Future<ExchangeResponse<Trade>> getExchange({
|
||||
required String exchangeId,
|
||||
String? apiKey,
|
||||
Trade? oldTrade,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
"/get_exchange",
|
||||
{
|
||||
"api_key": apiKey ?? kSimpleSwapApiKey,
|
||||
"id": exchangeId,
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final jsonObject = await _makeGetRequest(uri);
|
||||
|
||||
final json = Map<String, dynamic>.from(jsonObject as Map);
|
||||
final ts = DateTime.parse(json["timestamp"] as String);
|
||||
final trade = Trade(
|
||||
uuid: oldTrade?.uuid ?? const Uuid().v1(),
|
||||
tradeId: json["id"] as String,
|
||||
rateType: json["type"] as String,
|
||||
direction: "direct",
|
||||
timestamp: ts,
|
||||
updatedAt: DateTime.tryParse(json["updated_at"] as String? ?? "") ?? ts,
|
||||
payInCurrency: json["currency_from"] as String,
|
||||
payInAmount: json["amount_from"] as String,
|
||||
payInAddress: json["address_from"] as String,
|
||||
payInNetwork: "",
|
||||
payInExtraId: json["extra_id_from"] as String? ?? "",
|
||||
payInTxid: json["tx_from"] as String? ?? "",
|
||||
payOutCurrency: json["currency_to"] as String,
|
||||
payOutAmount: json["amount_to"] as String,
|
||||
payOutAddress: json["address_to"] as String,
|
||||
payOutNetwork: "",
|
||||
payOutExtraId: json["extra_id_to"] as String? ?? "",
|
||||
payOutTxid: json["tx_to"] as String? ?? "",
|
||||
refundAddress: json["user_refund_address"] as String,
|
||||
refundExtraId: json["user_refund_extra_id"] as String,
|
||||
status: json["status"] as String,
|
||||
exchangeName: SimpleSwapExchange.exchangeName,
|
||||
);
|
||||
|
||||
return ExchangeResponse(value: trade);
|
||||
} catch (e, s) {
|
||||
Logging.instance
|
||||
.log("getExchange exception: $e\n$s", level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the minimal exchange amount
|
||||
Future<ExchangeResponse<Range>> getRange({
|
||||
required bool isFixedRate,
|
||||
required String currencyFrom,
|
||||
required String currencyTo,
|
||||
String? apiKey,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
"/get_ranges",
|
||||
{
|
||||
"api_key": apiKey ?? kSimpleSwapApiKey,
|
||||
"fixed": isFixedRate.toString(),
|
||||
"currency_from": currencyFrom,
|
||||
"currency_to": currencyTo,
|
||||
},
|
||||
);
|
||||
|
||||
try {
|
||||
final jsonObject = await _makeGetRequest(uri);
|
||||
|
||||
final json = Map<String, dynamic>.from(jsonObject as Map);
|
||||
return ExchangeResponse(
|
||||
value: Range(
|
||||
max: Decimal.tryParse(json["max"] as String? ?? ""),
|
||||
min: Decimal.tryParse(json["min"] as String? ?? ""),
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getRange exception: $e\n$s", level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<ExchangeResponse<List<FixedRateMarket>>> getFixedRateMarketInfo({
|
||||
String? apiKey,
|
||||
}) async {
|
||||
final uri = _buildUri(
|
||||
"/get_market_info",
|
||||
null,
|
||||
// {
|
||||
// "api_key": apiKey ?? kSimpleSwapApiKey,
|
||||
// "fixed": isFixedRate.toString(),
|
||||
// "currency_from": currencyFrom,
|
||||
// "currency_to": currencyTo,
|
||||
// },
|
||||
);
|
||||
|
||||
try {
|
||||
final jsonArray = await _makeGetRequest(uri);
|
||||
|
||||
try {
|
||||
final result = await compute(
|
||||
_parseFixedRateMarketsJson,
|
||||
jsonArray as List,
|
||||
);
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableFixedRateMarkets exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
"Error: $jsonArray",
|
||||
ExchangeExceptionType.serializeResponseError,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("getAvailableFixedRateMarkets exception: $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException(
|
||||
e.toString(),
|
||||
ExchangeExceptionType.generic,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ExchangeResponse<List<FixedRateMarket>> _parseFixedRateMarketsJson(
|
||||
List<dynamic> jsonArray) {
|
||||
try {
|
||||
final List<FixedRateMarket> markets = [];
|
||||
for (final json in jsonArray) {
|
||||
try {
|
||||
final map = Map<String, dynamic>.from(json as Map);
|
||||
markets.add(FixedRateMarket(
|
||||
from: map["currency_from"] as String,
|
||||
to: map["currency_to"] as String,
|
||||
min: Decimal.parse(map["min"] as String),
|
||||
max: Decimal.parse(map["max"] as String),
|
||||
rate: Decimal.parse(map["rate"] as String),
|
||||
minerFee: null,
|
||||
));
|
||||
} catch (_) {
|
||||
return ExchangeResponse(
|
||||
exception: ExchangeException("Failed to serialize $json",
|
||||
ExchangeExceptionType.serializeResponseError));
|
||||
}
|
||||
}
|
||||
return ExchangeResponse(value: markets);
|
||||
} catch (_) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
149
lib/services/exchange/simpleswap/simpleswap_exchange.dart
Normal file
149
lib/services/exchange/simpleswap/simpleswap_exchange.dart
Normal file
|
@ -0,0 +1,149 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_api.dart';
|
||||
|
||||
class SimpleSwapExchange extends Exchange {
|
||||
static const exchangeName = "SimpleSwap";
|
||||
|
||||
@override
|
||||
String get name => exchangeName;
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Trade>> createTrade({
|
||||
required String from,
|
||||
required String to,
|
||||
required bool fixedRate,
|
||||
required Decimal amount,
|
||||
required String addressTo,
|
||||
String? extraId,
|
||||
required String addressRefund,
|
||||
required String refundExtraId,
|
||||
String? rateId,
|
||||
required bool reversed,
|
||||
}) async {
|
||||
return await SimpleSwapAPI.instance.createNewExchange(
|
||||
isFixedRate: fixedRate,
|
||||
currencyFrom: from,
|
||||
currencyTo: to,
|
||||
addressTo: addressTo,
|
||||
userRefundAddress: addressRefund,
|
||||
userRefundExtraId: refundExtraId,
|
||||
amount: amount.toString(),
|
||||
extraIdTo: extraId,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(
|
||||
bool fixedRate,
|
||||
) async {
|
||||
final response =
|
||||
await SimpleSwapAPI.instance.getAllCurrencies(fixedRate: fixedRate);
|
||||
if (response.value != null) {
|
||||
final List<Currency> currencies = response.value!
|
||||
.map((e) => Currency(
|
||||
ticker: e.symbol,
|
||||
name: e.name,
|
||||
network: e.network,
|
||||
image: e.image,
|
||||
hasExternalId: e.hasExtraId,
|
||||
externalId: e.extraId,
|
||||
isFiat: false,
|
||||
featured: false,
|
||||
isStable: false,
|
||||
supportsFixedRate: fixedRate,
|
||||
))
|
||||
.toList();
|
||||
return ExchangeResponse<List<Currency>>(
|
||||
value: currencies,
|
||||
exception: response.exception,
|
||||
);
|
||||
}
|
||||
|
||||
return ExchangeResponse<List<Currency>>(
|
||||
value: null,
|
||||
exception: response.exception,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate) async {
|
||||
return await SimpleSwapAPI.instance.getAllPairs(isFixedRate: fixedRate);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Estimate>> getEstimate(
|
||||
String from,
|
||||
String to,
|
||||
Decimal amount,
|
||||
bool fixedRate,
|
||||
bool reversed,
|
||||
) async {
|
||||
final response = await SimpleSwapAPI.instance.getEstimated(
|
||||
isFixedRate: fixedRate,
|
||||
currencyFrom: from,
|
||||
currencyTo: to,
|
||||
amount: amount.toString(),
|
||||
);
|
||||
if (response.exception != null) {
|
||||
return ExchangeResponse(
|
||||
exception: response.exception,
|
||||
);
|
||||
}
|
||||
|
||||
return ExchangeResponse(
|
||||
value: Estimate(
|
||||
estimatedAmount: Decimal.parse(response.value!),
|
||||
fixedRate: fixedRate,
|
||||
reversed: reversed,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Range>> getRange(
|
||||
String from,
|
||||
String to,
|
||||
bool fixedRate,
|
||||
) async {
|
||||
return await SimpleSwapAPI.instance.getRange(
|
||||
isFixedRate: fixedRate,
|
||||
currencyFrom: from,
|
||||
currencyTo: to,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Pair>>> getPairsFor(
|
||||
String currency,
|
||||
bool fixedRate,
|
||||
) async {
|
||||
// return await SimpleSwapAPI.instance.ge
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Trade>> getTrade(String tradeId) async {
|
||||
return await SimpleSwapAPI.instance.getExchange(exchangeId: tradeId);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<Trade>> updateTrade(Trade trade) async {
|
||||
return await SimpleSwapAPI.instance.getExchange(
|
||||
exchangeId: trade.tradeId,
|
||||
oldTrade: trade,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ExchangeResponse<List<Trade>>> getTrades() async {
|
||||
// TODO: implement getTrades
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
|
@ -3,9 +3,11 @@ import 'dart:async';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/notification_model.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/notifications_api.dart';
|
||||
import 'package:stackwallet/services/trade_service.dart';
|
||||
|
@ -17,7 +19,6 @@ class NotificationsService extends ChangeNotifier {
|
|||
late NodeService nodeService;
|
||||
late TradesService tradesService;
|
||||
late Prefs prefs;
|
||||
late ChangeNow changeNow;
|
||||
|
||||
NotificationsService._();
|
||||
static final NotificationsService _instance = NotificationsService._();
|
||||
|
@ -27,12 +28,10 @@ class NotificationsService extends ChangeNotifier {
|
|||
required NodeService nodeService,
|
||||
required TradesService tradesService,
|
||||
required Prefs prefs,
|
||||
required ChangeNow changeNow,
|
||||
}) async {
|
||||
this.nodeService = nodeService;
|
||||
this.tradesService = tradesService;
|
||||
this.prefs = prefs;
|
||||
this.changeNow = changeNow;
|
||||
}
|
||||
|
||||
// watched transactions
|
||||
|
@ -184,33 +183,52 @@ class NotificationsService extends ChangeNotifier {
|
|||
for (final notification in _watchedChangeNowTradeNotifications) {
|
||||
final id = notification.changeNowId!;
|
||||
|
||||
final result = await changeNow.getTransactionStatus(id: id);
|
||||
final trades =
|
||||
tradesService.trades.where((element) => element.tradeId == id);
|
||||
|
||||
ChangeNowTransactionStatus? status = result.value?.status;
|
||||
if (trades.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final oldTrade = trades.first;
|
||||
late final ExchangeResponse<Trade> response;
|
||||
switch (oldTrade.exchangeName) {
|
||||
case SimpleSwapExchange.exchangeName:
|
||||
response = await SimpleSwapExchange().updateTrade(oldTrade);
|
||||
break;
|
||||
case ChangeNowExchange.exchangeName:
|
||||
response = await ChangeNowExchange().updateTrade(oldTrade);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final trade = response.value!;
|
||||
|
||||
// only update if status has changed
|
||||
if (status != null && status.name != notification.title) {
|
||||
if (trade.status != notification.title) {
|
||||
bool shouldWatchForUpdates = true;
|
||||
// TODO: make sure we set shouldWatchForUpdates to correct value here
|
||||
switch (status) {
|
||||
case ChangeNowTransactionStatus.New:
|
||||
case ChangeNowTransactionStatus.Waiting:
|
||||
case ChangeNowTransactionStatus.Confirming:
|
||||
case ChangeNowTransactionStatus.Exchanging:
|
||||
case ChangeNowTransactionStatus.Verifying:
|
||||
case ChangeNowTransactionStatus.Sending:
|
||||
shouldWatchForUpdates = true;
|
||||
break;
|
||||
|
||||
case ChangeNowTransactionStatus.Finished:
|
||||
case ChangeNowTransactionStatus.Failed:
|
||||
case ChangeNowTransactionStatus.Refunded:
|
||||
switch (trade.status) {
|
||||
case "Refunded":
|
||||
case "refunded":
|
||||
case "Failed":
|
||||
case "failed":
|
||||
case "closed":
|
||||
case "expired":
|
||||
case "Finished":
|
||||
case "finished":
|
||||
shouldWatchForUpdates = false;
|
||||
break;
|
||||
default:
|
||||
shouldWatchForUpdates = true;
|
||||
}
|
||||
|
||||
final updatedNotification = notification.copyWith(
|
||||
title: status.name,
|
||||
title: trade.status,
|
||||
shouldWatchForUpdates: shouldWatchForUpdates,
|
||||
);
|
||||
|
||||
|
@ -220,23 +238,11 @@ class NotificationsService extends ChangeNotifier {
|
|||
}
|
||||
|
||||
// replaces the current notification with the updated one
|
||||
add(updatedNotification, true);
|
||||
unawaited(add(updatedNotification, true));
|
||||
|
||||
// update the trade in db
|
||||
if (result.value != null) {
|
||||
// fetch matching trade from db
|
||||
final trade = tradesService.trades
|
||||
.firstWhere((element) => element.id == result.value!.id);
|
||||
|
||||
// update status
|
||||
final updatedTrade = trade.copyWith(
|
||||
statusObject: result.value!,
|
||||
statusString: result.value!.status.name,
|
||||
);
|
||||
|
||||
// over write trade stored in db with updated version
|
||||
tradesService.add(trade: updatedTrade, shouldNotifyListeners: true);
|
||||
}
|
||||
await tradesService.edit(trade: trade, shouldNotifyListeners: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
|
||||
class TradesService extends ChangeNotifier {
|
||||
List<ExchangeTransaction> get trades {
|
||||
final list =
|
||||
DB.instance.values<ExchangeTransaction>(boxName: DB.boxNameTrades);
|
||||
List<Trade> get trades {
|
||||
final list = DB.instance.values<Trade>(boxName: DB.boxNameTradesV2);
|
||||
list.sort((a, b) =>
|
||||
b.date.millisecondsSinceEpoch - a.date.millisecondsSinceEpoch);
|
||||
b.timestamp.millisecondsSinceEpoch -
|
||||
a.timestamp.millisecondsSinceEpoch);
|
||||
return list;
|
||||
}
|
||||
|
||||
Future<void> add({
|
||||
required ExchangeTransaction trade,
|
||||
required Trade trade,
|
||||
required bool shouldNotifyListeners,
|
||||
}) async {
|
||||
await DB.instance.put<ExchangeTransaction>(
|
||||
boxName: DB.boxNameTrades, key: trade.uuid, value: trade);
|
||||
await DB.instance
|
||||
.put<Trade>(boxName: DB.boxNameTradesV2, key: trade.uuid, value: trade);
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
|
@ -24,11 +24,10 @@ class TradesService extends ChangeNotifier {
|
|||
}
|
||||
|
||||
Future<void> edit({
|
||||
required ExchangeTransaction trade,
|
||||
required Trade trade,
|
||||
required bool shouldNotifyListeners,
|
||||
}) async {
|
||||
if (DB.instance.get<ExchangeTransaction>(
|
||||
boxName: DB.boxNameTrades, key: trade.uuid) ==
|
||||
if (DB.instance.get<Trade>(boxName: DB.boxNameTradesV2, key: trade.uuid) ==
|
||||
null) {
|
||||
throw Exception("Attempted to edit a trade that does not exist in Hive!");
|
||||
}
|
||||
|
@ -38,7 +37,7 @@ class TradesService extends ChangeNotifier {
|
|||
}
|
||||
|
||||
Future<void> delete({
|
||||
required ExchangeTransaction trade,
|
||||
required Trade trade,
|
||||
required bool shouldNotifyListeners,
|
||||
}) async {
|
||||
await deleteByUuid(
|
||||
|
@ -49,8 +48,7 @@ class TradesService extends ChangeNotifier {
|
|||
required String uuid,
|
||||
required bool shouldNotifyListeners,
|
||||
}) async {
|
||||
await DB.instance
|
||||
.delete<ExchangeTransaction>(boxName: DB.boxNameTrades, key: uuid);
|
||||
await DB.instance.delete<Trade>(boxName: DB.boxNameTradesV2, key: uuid);
|
||||
|
||||
if (shouldNotifyListeners) {
|
||||
notifyListeners();
|
||||
|
|
|
@ -7,6 +7,7 @@ abstract class Assets {
|
|||
static const png = _PNG();
|
||||
static const lottie = _ANIMATIONS();
|
||||
static const socials = _SOCIALS();
|
||||
static const exchange = _EXCHANGE();
|
||||
}
|
||||
|
||||
class _SOCIALS {
|
||||
|
@ -18,6 +19,13 @@ class _SOCIALS {
|
|||
String get telegram => "assets/svg/socials/telegram-brands.svg";
|
||||
}
|
||||
|
||||
class _EXCHANGE {
|
||||
const _EXCHANGE();
|
||||
|
||||
String get changeNow => "assets/svg/exchange_icons/change_now_logo_1.svg";
|
||||
String get simpleSwap => "assets/svg/exchange_icons/simpleswap-icon.svg";
|
||||
}
|
||||
|
||||
class _SVG {
|
||||
const _SVG();
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ abstract class Constants {
|
|||
// Enable Logger.print statements
|
||||
static const bool disableLogger = false;
|
||||
|
||||
static const int currentHiveDbVersion = 1;
|
||||
static const int currentHiveDbVersion = 2;
|
||||
|
||||
static List<int> possibleLengthsForCoin(Coin coin) {
|
||||
final List<int> values = [];
|
||||
|
|
|
@ -2,6 +2,8 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/lelantus_coin.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
|
@ -19,6 +21,10 @@ class DbVersionMigrator {
|
|||
FlutterSecureStorage(),
|
||||
),
|
||||
}) async {
|
||||
Logging.instance.log(
|
||||
"Running migrate fromVersion $fromVersion",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
switch (fromVersion) {
|
||||
case 0:
|
||||
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
|
@ -114,26 +120,29 @@ class DbVersionMigrator {
|
|||
// try to continue migrating
|
||||
return await migrate(1);
|
||||
|
||||
// case 1:
|
||||
// await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
// final walletsService = WalletsService();
|
||||
// final walletInfoList = await walletsService.walletNames;
|
||||
// for (final walletInfo in walletInfoList.values) {
|
||||
// if (walletInfo.coin == Coin.firo) {
|
||||
// await Hive.openBox<dynamic>(walletInfo.walletId);
|
||||
// await DB.instance.delete<dynamic>(
|
||||
// key: "latest_tx_model", boxName: walletInfo.walletId);
|
||||
// await DB.instance.delete<dynamic>(
|
||||
// key: "latest_lelantus_tx_model", boxName: walletInfo.walletId);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // update version
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 2);
|
||||
//
|
||||
// // try to continue migrating
|
||||
// return await migrate(2);
|
||||
case 1:
|
||||
await Hive.openBox<ExchangeTransaction>(DB.boxNameTrades);
|
||||
await Hive.openBox<Trade>(DB.boxNameTradesV2);
|
||||
final trades =
|
||||
DB.instance.values<ExchangeTransaction>(boxName: DB.boxNameTrades);
|
||||
|
||||
for (final old in trades) {
|
||||
if (old.statusObject != null) {
|
||||
final trade = Trade.fromExchangeTransaction(old, false);
|
||||
await DB.instance.put<Trade>(
|
||||
boxName: DB.boxNameTradesV2,
|
||||
key: trade.uuid,
|
||||
value: trade,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// update version
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 2);
|
||||
|
||||
// try to continue migrating
|
||||
return await migrate(2);
|
||||
|
||||
default:
|
||||
// finally return
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/theme/color_theme.dart';
|
||||
|
||||
|
@ -1435,21 +1434,34 @@ class StackColors extends ThemeExtension<StackColors> {
|
|||
blurRadius: 4,
|
||||
);
|
||||
|
||||
Color colorForStatus(ChangeNowTransactionStatus status) {
|
||||
Color colorForStatus(String status) {
|
||||
switch (status) {
|
||||
case ChangeNowTransactionStatus.New:
|
||||
case ChangeNowTransactionStatus.Waiting:
|
||||
case ChangeNowTransactionStatus.Confirming:
|
||||
case ChangeNowTransactionStatus.Exchanging:
|
||||
case ChangeNowTransactionStatus.Sending:
|
||||
case ChangeNowTransactionStatus.Verifying:
|
||||
case "New":
|
||||
case "new":
|
||||
case "Waiting":
|
||||
case "waiting":
|
||||
case "Confirming":
|
||||
case "confirming":
|
||||
case "Exchanging":
|
||||
case "exchanging":
|
||||
case "Sending":
|
||||
case "sending":
|
||||
case "Verifying":
|
||||
case "verifying":
|
||||
return const Color(0xFFD3A90F);
|
||||
case ChangeNowTransactionStatus.Finished:
|
||||
case "Finished":
|
||||
case "finished":
|
||||
return accentColorGreen;
|
||||
case ChangeNowTransactionStatus.Failed:
|
||||
case "Failed":
|
||||
case "failed":
|
||||
case "closed":
|
||||
case "expired":
|
||||
return accentColorRed;
|
||||
case ChangeNowTransactionStatus.Refunded:
|
||||
case "Refunded":
|
||||
case "refunded":
|
||||
return textSubtitle2;
|
||||
default:
|
||||
return const Color(0xFFD3A90F);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import 'package:decimal/decimal.dart';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
|
@ -16,7 +16,7 @@ class TradeCard extends ConsumerWidget {
|
|||
required this.onTap,
|
||||
}) : super(key: key);
|
||||
|
||||
final ExchangeTransaction trade;
|
||||
final Trade trade;
|
||||
final VoidCallback onTap;
|
||||
|
||||
String _fetchIconAssetForStatus(String statusString, BuildContext context) {
|
||||
|
@ -62,7 +62,7 @@ class TradeCard extends ConsumerWidget {
|
|||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
_fetchIconAssetForStatus(
|
||||
trade.statusObject?.status.name ?? trade.statusString,
|
||||
trade.status,
|
||||
context,
|
||||
),
|
||||
width: 32,
|
||||
|
@ -80,11 +80,11 @@ class TradeCard extends ConsumerWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"${trade.fromCurrency.toUpperCase()} → ${trade.toCurrency.toUpperCase()}",
|
||||
"${trade.payInCurrency.toUpperCase()} → ${trade.payOutCurrency.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
Text(
|
||||
"${Decimal.tryParse(trade.statusObject?.amountSendDecimal ?? "") ?? "..."} ${trade.fromCurrency.toUpperCase()}",
|
||||
"${Decimal.tryParse(trade.payInAmount) ?? "..."} ${trade.payInCurrency.toUpperCase()}",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
],
|
||||
|
@ -96,12 +96,12 @@ class TradeCard extends ConsumerWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"ChangeNOW",
|
||||
trade.exchangeName,
|
||||
style: STextStyles.label(context),
|
||||
),
|
||||
Text(
|
||||
Format.extractDateFrom(
|
||||
trade.date.millisecondsSinceEpoch ~/ 1000),
|
||||
trade.timestamp.millisecondsSinceEpoch ~/ 1000),
|
||||
style: STextStyles.label(context),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -314,6 +314,9 @@ flutter:
|
|||
- assets/svg/message-question-1.svg
|
||||
- assets/svg/drd-icon.svg
|
||||
- assets/svg/box-auto.svg
|
||||
# exchange icons
|
||||
- assets/svg/exchange_icons/change_now_logo_1.svg
|
||||
- assets/svg/exchange_icons/simpleswap-icon.svg
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||
|
|
|
@ -1,215 +1,219 @@
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
|
||||
import 'package:stackwallet/models/exchange/estimated_rate_exchange_form_state.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||
|
||||
import 'estimated_rate_exchange_form_state_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([ChangeNow])
|
||||
void main() {
|
||||
final currencyA = Currency(
|
||||
ticker: "btc",
|
||||
name: "Bitcoin",
|
||||
image: "image.url",
|
||||
hasExternalId: false,
|
||||
isFiat: false,
|
||||
featured: false,
|
||||
isStable: true,
|
||||
supportsFixedRate: true,
|
||||
);
|
||||
final currencyB = Currency(
|
||||
ticker: "xmr",
|
||||
name: "Monero",
|
||||
image: "image.url",
|
||||
hasExternalId: false,
|
||||
isFiat: false,
|
||||
featured: false,
|
||||
isStable: true,
|
||||
supportsFixedRate: true,
|
||||
);
|
||||
final currencyC = Currency(
|
||||
ticker: "firo",
|
||||
name: "Firo",
|
||||
image: "image.url",
|
||||
hasExternalId: false,
|
||||
isFiat: false,
|
||||
featured: false,
|
||||
isStable: true,
|
||||
supportsFixedRate: true,
|
||||
);
|
||||
|
||||
test("EstimatedRateExchangeFormState constructor", () async {
|
||||
final state = EstimatedRateExchangeFormState();
|
||||
|
||||
expect(state.from, null);
|
||||
expect(state.to, null);
|
||||
expect(state.canExchange, false);
|
||||
expect(state.rate, null);
|
||||
expect(state.rateDisplayString, "N/A");
|
||||
expect(state.fromAmountString, "");
|
||||
expect(state.toAmountString, "");
|
||||
expect(state.minimumSendWarning, "");
|
||||
});
|
||||
|
||||
test("init EstimatedRateExchangeFormState", () async {
|
||||
final state = EstimatedRateExchangeFormState();
|
||||
|
||||
await state.init(currencyA, currencyB);
|
||||
|
||||
expect(state.from, currencyA);
|
||||
expect(state.to, currencyB);
|
||||
expect(state.canExchange, false);
|
||||
expect(state.rate, null);
|
||||
expect(state.rateDisplayString, "N/A");
|
||||
expect(state.fromAmountString, "");
|
||||
expect(state.toAmountString, "");
|
||||
expect(state.minimumSendWarning, "");
|
||||
});
|
||||
|
||||
test("updateTo on fresh state", () async {
|
||||
final state = EstimatedRateExchangeFormState();
|
||||
|
||||
await state.updateTo(currencyA, false);
|
||||
|
||||
expect(state.from, null);
|
||||
expect(state.to, currencyA);
|
||||
expect(state.canExchange, false);
|
||||
expect(state.rate, null);
|
||||
expect(state.rateDisplayString, "N/A");
|
||||
expect(state.fromAmountString, "");
|
||||
expect(state.toAmountString, "");
|
||||
expect(state.minimumSendWarning, "");
|
||||
});
|
||||
|
||||
test(
|
||||
"updateTo after updateFrom where amounts are null and getMinimalExchangeAmount succeeds",
|
||||
() async {
|
||||
final cn = MockChangeNow();
|
||||
|
||||
final state = EstimatedRateExchangeFormState();
|
||||
state.cnTesting = cn;
|
||||
|
||||
when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.thenAnswer((_) async => ChangeNowResponse(value: Decimal.fromInt(42)));
|
||||
|
||||
await state.updateFrom(currencyA, true);
|
||||
await state.updateTo(currencyB, true);
|
||||
|
||||
expect(state.from, currencyA);
|
||||
expect(state.to, currencyB);
|
||||
expect(state.canExchange, false);
|
||||
expect(state.rate, null);
|
||||
expect(state.rateDisplayString, "N/A");
|
||||
expect(state.fromAmountString, "");
|
||||
expect(state.toAmountString, "");
|
||||
expect(state.minimumSendWarning, "");
|
||||
|
||||
verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test(
|
||||
"updateTo after updateFrom where amounts are null and getMinimalExchangeAmount fails",
|
||||
() async {
|
||||
final cn = MockChangeNow();
|
||||
|
||||
final state = EstimatedRateExchangeFormState();
|
||||
state.cnTesting = cn;
|
||||
|
||||
when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.thenAnswer((_) async => ChangeNowResponse());
|
||||
|
||||
await state.updateFrom(currencyA, true);
|
||||
await state.updateTo(currencyB, true);
|
||||
|
||||
expect(state.from, currencyA);
|
||||
expect(state.to, currencyB);
|
||||
expect(state.canExchange, false);
|
||||
expect(state.rate, null);
|
||||
expect(state.rateDisplayString, "N/A");
|
||||
expect(state.fromAmountString, "");
|
||||
expect(state.toAmountString, "");
|
||||
expect(state.minimumSendWarning, "");
|
||||
|
||||
verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test(
|
||||
"updateTo after updateFrom and setFromAmountAndCalculateToAmount where fromAmount is less than the minimum required exchange amount",
|
||||
() async {
|
||||
final cn = MockChangeNow();
|
||||
|
||||
final state = EstimatedRateExchangeFormState();
|
||||
state.cnTesting = cn;
|
||||
|
||||
when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.thenAnswer((_) async => ChangeNowResponse(value: Decimal.fromInt(42)));
|
||||
|
||||
await state.updateFrom(currencyA, true);
|
||||
await state.setFromAmountAndCalculateToAmount(Decimal.parse("10.10"), true);
|
||||
await state.updateTo(currencyB, true);
|
||||
|
||||
expect(state.from, currencyA);
|
||||
expect(state.to, currencyB);
|
||||
expect(state.canExchange, false);
|
||||
expect(state.rate, null);
|
||||
expect(state.rateDisplayString, "N/A");
|
||||
expect(state.fromAmountString, "10.10000000");
|
||||
expect(state.toAmountString, "");
|
||||
expect(state.minimumSendWarning, "Minimum amount 42 BTC");
|
||||
|
||||
verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.called(1);
|
||||
});
|
||||
|
||||
test(
|
||||
"updateTo after updateFrom and setFromAmountAndCalculateToAmount where fromAmount is greater than the minimum required exchange amount",
|
||||
() async {
|
||||
final cn = MockChangeNow();
|
||||
|
||||
final state = EstimatedRateExchangeFormState();
|
||||
state.cnTesting = cn;
|
||||
|
||||
when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.thenAnswer((_) async => ChangeNowResponse(value: Decimal.fromInt(42)));
|
||||
when(cn.getEstimatedExchangeAmount(
|
||||
fromTicker: "btc",
|
||||
toTicker: "xmr",
|
||||
fromAmount: Decimal.parse("110.10")))
|
||||
.thenAnswer((_) async => ChangeNowResponse(
|
||||
value: EstimatedExchangeAmount(
|
||||
transactionSpeedForecast: '10-60',
|
||||
rateId: 'some rate id',
|
||||
warningMessage: '',
|
||||
estimatedAmount: Decimal.parse("302.002348"),
|
||||
)));
|
||||
|
||||
await state.updateFrom(currencyA, true);
|
||||
await state.setFromAmountAndCalculateToAmount(
|
||||
Decimal.parse("110.10"), true);
|
||||
await state.updateTo(currencyB, true);
|
||||
|
||||
expect(state.from, currencyA);
|
||||
expect(state.to, currencyB);
|
||||
expect(state.canExchange, true);
|
||||
expect(state.rate, Decimal.parse("2.742982270663"));
|
||||
expect(state.rateDisplayString, "1 BTC ~2.74298227 XMR");
|
||||
expect(state.fromAmountString, "110.10000000");
|
||||
expect(state.toAmountString, "302.00234800");
|
||||
expect(state.minimumSendWarning, "");
|
||||
|
||||
verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
.called(1);
|
||||
verify(cn.getEstimatedExchangeAmount(
|
||||
fromTicker: "btc",
|
||||
toTicker: "xmr",
|
||||
fromAmount: Decimal.parse("110.10")))
|
||||
.called(1);
|
||||
});
|
||||
}
|
||||
// import 'package:decimal/decimal.dart';
|
||||
// import 'package:flutter_test/flutter_test.dart';
|
||||
// import 'package:mockito/annotations.dart';
|
||||
// import 'package:mockito/mockito.dart';
|
||||
// import 'package:stackwallet/models/exchange/estimated_rate_exchange_form_state.dart';
|
||||
// import 'package:stackwallet/models/exchange/response_objects/currency.dart';
|
||||
// import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
// import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
|
||||
// import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
//
|
||||
// import 'estimated_rate_exchange_form_state_test.mocks.dart';
|
||||
//
|
||||
// @GenerateMocks([ChangeNowAPI])
|
||||
// void main() {
|
||||
// final currencyA = Currency(
|
||||
// ticker: "btc",
|
||||
// name: "Bitcoin",
|
||||
// image: "image.url",
|
||||
// hasExternalId: false,
|
||||
// isFiat: false,
|
||||
// featured: false,
|
||||
// isStable: true,
|
||||
// supportsFixedRate: true,
|
||||
// network: '',
|
||||
// );
|
||||
// final currencyB = Currency(
|
||||
// ticker: "xmr",
|
||||
// name: "Monero",
|
||||
// image: "image.url",
|
||||
// hasExternalId: false,
|
||||
// isFiat: false,
|
||||
// featured: false,
|
||||
// isStable: true,
|
||||
// supportsFixedRate: true,
|
||||
// network: '',
|
||||
// );
|
||||
// final currencyC = Currency(
|
||||
// ticker: "firo",
|
||||
// name: "Firo",
|
||||
// image: "image.url",
|
||||
// hasExternalId: false,
|
||||
// isFiat: false,
|
||||
// featured: false,
|
||||
// isStable: true,
|
||||
// supportsFixedRate: true,
|
||||
// network: '',
|
||||
// );
|
||||
//
|
||||
// test("EstimatedRateExchangeFormState constructor", () async {
|
||||
// final state = EstimatedRateExchangeFormState();
|
||||
//
|
||||
// expect(state.from, null);
|
||||
// expect(state.to, null);
|
||||
// expect(state.canExchange, false);
|
||||
// expect(state.rate, null);
|
||||
// expect(state.rateDisplayString, "N/A");
|
||||
// expect(state.fromAmountString, "");
|
||||
// expect(state.toAmountString, "");
|
||||
// expect(state.minimumSendWarning, "");
|
||||
// });
|
||||
//
|
||||
// test("init EstimatedRateExchangeFormState", () async {
|
||||
// final state = EstimatedRateExchangeFormState();
|
||||
//
|
||||
// await state.init(currencyA, currencyB);
|
||||
//
|
||||
// expect(state.from, currencyA);
|
||||
// expect(state.to, currencyB);
|
||||
// expect(state.canExchange, false);
|
||||
// expect(state.rate, null);
|
||||
// expect(state.rateDisplayString, "N/A");
|
||||
// expect(state.fromAmountString, "");
|
||||
// expect(state.toAmountString, "");
|
||||
// expect(state.minimumSendWarning, "");
|
||||
// });
|
||||
//
|
||||
// test("updateTo on fresh state", () async {
|
||||
// final state = EstimatedRateExchangeFormState();
|
||||
//
|
||||
// await state.updateTo(currencyA, false);
|
||||
//
|
||||
// expect(state.from, null);
|
||||
// expect(state.to, currencyA);
|
||||
// expect(state.canExchange, false);
|
||||
// expect(state.rate, null);
|
||||
// expect(state.rateDisplayString, "N/A");
|
||||
// expect(state.fromAmountString, "");
|
||||
// expect(state.toAmountString, "");
|
||||
// expect(state.minimumSendWarning, "");
|
||||
// });
|
||||
//
|
||||
// test(
|
||||
// "updateTo after updateFrom where amounts are null and getMinimalExchangeAmount succeeds",
|
||||
// () async {
|
||||
// final cn = MockChangeNowAPI();
|
||||
//
|
||||
// final state = EstimatedRateExchangeFormState();
|
||||
// state.cnTesting = cn;
|
||||
//
|
||||
// when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .thenAnswer((_) async => ExchangeResponse(value: Decimal.fromInt(42)));
|
||||
//
|
||||
// await state.updateFrom(currencyA, true);
|
||||
// await state.updateTo(currencyB, true);
|
||||
//
|
||||
// expect(state.from, currencyA);
|
||||
// expect(state.to, currencyB);
|
||||
// expect(state.canExchange, false);
|
||||
// expect(state.rate, null);
|
||||
// expect(state.rateDisplayString, "N/A");
|
||||
// expect(state.fromAmountString, "");
|
||||
// expect(state.toAmountString, "");
|
||||
// expect(state.minimumSendWarning, "");
|
||||
//
|
||||
// verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .called(1);
|
||||
// });
|
||||
//
|
||||
// test(
|
||||
// "updateTo after updateFrom where amounts are null and getMinimalExchangeAmount fails",
|
||||
// () async {
|
||||
// final cn = MockChangeNowAPI();
|
||||
//
|
||||
// final state = EstimatedRateExchangeFormState();
|
||||
// state.cnTesting = cn;
|
||||
//
|
||||
// when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .thenAnswer((_) async => ExchangeResponse());
|
||||
//
|
||||
// await state.updateFrom(currencyA, true);
|
||||
// await state.updateTo(currencyB, true);
|
||||
//
|
||||
// expect(state.from, currencyA);
|
||||
// expect(state.to, currencyB);
|
||||
// expect(state.canExchange, false);
|
||||
// expect(state.rate, null);
|
||||
// expect(state.rateDisplayString, "N/A");
|
||||
// expect(state.fromAmountString, "");
|
||||
// expect(state.toAmountString, "");
|
||||
// expect(state.minimumSendWarning, "");
|
||||
//
|
||||
// verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .called(1);
|
||||
// });
|
||||
//
|
||||
// test(
|
||||
// "updateTo after updateFrom and setFromAmountAndCalculateToAmount where fromAmount is less than the minimum required exchange amount",
|
||||
// () async {
|
||||
// final cn = MockChangeNowAPI();
|
||||
//
|
||||
// final state = EstimatedRateExchangeFormState();
|
||||
// state.cnTesting = cn;
|
||||
//
|
||||
// when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .thenAnswer((_) async => ExchangeResponse(value: Decimal.fromInt(42)));
|
||||
//
|
||||
// await state.updateFrom(currencyA, true);
|
||||
// await state.setFromAmountAndCalculateToAmount(Decimal.parse("10.10"), true);
|
||||
// await state.updateTo(currencyB, true);
|
||||
//
|
||||
// expect(state.from, currencyA);
|
||||
// expect(state.to, currencyB);
|
||||
// expect(state.canExchange, false);
|
||||
// expect(state.rate, null);
|
||||
// expect(state.rateDisplayString, "N/A");
|
||||
// expect(state.fromAmountString, "10.10000000");
|
||||
// expect(state.toAmountString, "");
|
||||
// expect(state.minimumSendWarning, "Minimum amount 42 BTC");
|
||||
//
|
||||
// verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .called(1);
|
||||
// });
|
||||
//
|
||||
// test(
|
||||
// "updateTo after updateFrom and setFromAmountAndCalculateToAmount where fromAmount is greater than the minimum required exchange amount",
|
||||
// () async {
|
||||
// final cn = MockChangeNowAPI();
|
||||
//
|
||||
// final state = EstimatedRateExchangeFormState();
|
||||
// state.cnTesting = cn;
|
||||
//
|
||||
// when(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .thenAnswer((_) async => ExchangeResponse(value: Decimal.fromInt(42)));
|
||||
// when(cn.getEstimatedExchangeAmount(
|
||||
// fromTicker: "btc",
|
||||
// toTicker: "xmr",
|
||||
// fromAmount: Decimal.parse("110.10")))
|
||||
// .thenAnswer((_) async => ExchangeResponse(
|
||||
// value: Estimate(
|
||||
// reversed: false,
|
||||
// fixedRate: false,
|
||||
// rateId: 'some rate id',
|
||||
// warningMessage: '',
|
||||
// estimatedAmount: Decimal.parse("302.002348"),
|
||||
// )));
|
||||
//
|
||||
// await state.updateFrom(currencyA, true);
|
||||
// await state.setFromAmountAndCalculateToAmount(
|
||||
// Decimal.parse("110.10"), true);
|
||||
// await state.updateTo(currencyB, true);
|
||||
//
|
||||
// expect(state.from, currencyA);
|
||||
// expect(state.to, currencyB);
|
||||
// expect(state.canExchange, true);
|
||||
// expect(state.rate, Decimal.parse("2.742982270663"));
|
||||
// expect(state.rateDisplayString, "1 BTC ~2.74298227 XMR");
|
||||
// expect(state.fromAmountString, "110.10000000");
|
||||
// expect(state.toAmountString, "302.00234800");
|
||||
// expect(state.minimumSendWarning, "");
|
||||
//
|
||||
// verify(cn.getMinimalExchangeAmount(fromTicker: "btc", toTicker: "xmr"))
|
||||
// .called(1);
|
||||
// verify(cn.getEstimatedExchangeAmount(
|
||||
// fromTicker: "btc",
|
||||
// toTicker: "xmr",
|
||||
// fromAmount: Decimal.parse("110.10")))
|
||||
// .called(1);
|
||||
// });
|
||||
// }
|
||||
|
|
|
@ -1,218 +0,0 @@
|
|||
// Mocks generated by Mockito 5.2.0 from annotations
|
||||
// in stackwallet/test/models/exchange/estimated_rate_exchange_form_state_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
import 'dart:async' as _i5;
|
||||
|
||||
import 'package:decimal/decimal.dart' as _i7;
|
||||
import 'package:http/http.dart' as _i4;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart'
|
||||
as _i13;
|
||||
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart'
|
||||
as _i2;
|
||||
import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart'
|
||||
as _i9;
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart' as _i6;
|
||||
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart'
|
||||
as _i8;
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'
|
||||
as _i11;
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'
|
||||
as _i12;
|
||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart'
|
||||
as _i10;
|
||||
import 'package:stackwallet/services/change_now/change_now.dart' as _i3;
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: avoid_redundant_argument_values
|
||||
// ignore_for_file: avoid_setters_without_getters
|
||||
// ignore_for_file: comment_references
|
||||
// ignore_for_file: implementation_imports
|
||||
// ignore_for_file: invalid_use_of_visible_for_testing_member
|
||||
// ignore_for_file: prefer_const_constructors
|
||||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
|
||||
class _FakeChangeNowResponse_0<T> extends _i1.Fake
|
||||
implements _i2.ChangeNowResponse<T> {}
|
||||
|
||||
/// A class which mocks [ChangeNow].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockChangeNow extends _i1.Mock implements _i3.ChangeNow {
|
||||
MockChangeNow() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
set client(_i4.Client? _client) =>
|
||||
super.noSuchMethod(Invocation.setter(#client, _client),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<List<_i6.Currency>>> getAvailableCurrencies(
|
||||
{bool? fixedRate, bool? active}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getAvailableCurrencies, [],
|
||||
{#fixedRate: fixedRate, #active: active}),
|
||||
returnValue: Future<_i2.ChangeNowResponse<List<_i6.Currency>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i6.Currency>>())) as _i5
|
||||
.Future<_i2.ChangeNowResponse<List<_i6.Currency>>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<List<_i6.Currency>>> getPairedCurrencies(
|
||||
{String? ticker, bool? fixedRate}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getPairedCurrencies, [],
|
||||
{#ticker: ticker, #fixedRate: fixedRate}),
|
||||
returnValue: Future<_i2.ChangeNowResponse<List<_i6.Currency>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i6.Currency>>())) as _i5
|
||||
.Future<_i2.ChangeNowResponse<List<_i6.Currency>>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<_i7.Decimal>> getMinimalExchangeAmount(
|
||||
{String? fromTicker, String? toTicker, String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getMinimalExchangeAmount, [], {
|
||||
#fromTicker: fromTicker,
|
||||
#toTicker: toTicker,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<_i2.ChangeNowResponse<_i7.Decimal>>.value(
|
||||
_FakeChangeNowResponse_0<_i7.Decimal>()))
|
||||
as _i5.Future<_i2.ChangeNowResponse<_i7.Decimal>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<_i8.EstimatedExchangeAmount>>
|
||||
getEstimatedExchangeAmount(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
_i7.Decimal? fromAmount,
|
||||
String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getEstimatedExchangeAmount, [], {
|
||||
#fromTicker: fromTicker,
|
||||
#toTicker: toTicker,
|
||||
#fromAmount: fromAmount,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<
|
||||
_i8.EstimatedExchangeAmount>>.value(
|
||||
_FakeChangeNowResponse_0<_i8.EstimatedExchangeAmount>()))
|
||||
as _i5
|
||||
.Future<_i2.ChangeNowResponse<_i8.EstimatedExchangeAmount>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<_i9.CNExchangeEstimate>>
|
||||
getEstimatedExchangeAmountV2(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
_i9.CNEstimateType? fromOrTo,
|
||||
_i7.Decimal? amount,
|
||||
String? fromNetwork,
|
||||
String? toNetwork,
|
||||
_i9.CNFlowType? flow = _i9.CNFlowType.standard,
|
||||
String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getEstimatedExchangeAmountV2, [], {
|
||||
#fromTicker: fromTicker,
|
||||
#toTicker: toTicker,
|
||||
#fromOrTo: fromOrTo,
|
||||
#amount: amount,
|
||||
#fromNetwork: fromNetwork,
|
||||
#toNetwork: toNetwork,
|
||||
#flow: flow,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<_i9.CNExchangeEstimate>>.value(
|
||||
_FakeChangeNowResponse_0<_i9.CNExchangeEstimate>()))
|
||||
as _i5.Future<_i2.ChangeNowResponse<_i9.CNExchangeEstimate>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<List<_i10.FixedRateMarket>>>
|
||||
getAvailableFixedRateMarkets({String? apiKey}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getAvailableFixedRateMarkets, [], {#apiKey: apiKey}),
|
||||
returnValue:
|
||||
Future<_i2.ChangeNowResponse<List<_i10.FixedRateMarket>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i10.FixedRateMarket>>())) as _i5
|
||||
.Future<_i2.ChangeNowResponse<List<_i10.FixedRateMarket>>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<_i11.ExchangeTransaction>>
|
||||
createStandardExchangeTransaction(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
String? receivingAddress,
|
||||
_i7.Decimal? amount,
|
||||
String? extraId = r'',
|
||||
String? userId = r'',
|
||||
String? contactEmail = r'',
|
||||
String? refundAddress = r'',
|
||||
String? refundExtraId = r'',
|
||||
String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#createStandardExchangeTransaction, [], {
|
||||
#fromTicker: fromTicker,
|
||||
#toTicker: toTicker,
|
||||
#receivingAddress: receivingAddress,
|
||||
#amount: amount,
|
||||
#extraId: extraId,
|
||||
#userId: userId,
|
||||
#contactEmail: contactEmail,
|
||||
#refundAddress: refundAddress,
|
||||
#refundExtraId: refundExtraId,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<_i11.ExchangeTransaction>>.value(
|
||||
_FakeChangeNowResponse_0<_i11.ExchangeTransaction>())) as _i5
|
||||
.Future<_i2.ChangeNowResponse<_i11.ExchangeTransaction>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<_i11.ExchangeTransaction>>
|
||||
createFixedRateExchangeTransaction(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
String? receivingAddress,
|
||||
_i7.Decimal? amount,
|
||||
String? rateId,
|
||||
String? extraId = r'',
|
||||
String? userId = r'',
|
||||
String? contactEmail = r'',
|
||||
String? refundAddress = r'',
|
||||
String? refundExtraId = r'',
|
||||
String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#createFixedRateExchangeTransaction, [], {
|
||||
#fromTicker: fromTicker,
|
||||
#toTicker: toTicker,
|
||||
#receivingAddress: receivingAddress,
|
||||
#amount: amount,
|
||||
#rateId: rateId,
|
||||
#extraId: extraId,
|
||||
#userId: userId,
|
||||
#contactEmail: contactEmail,
|
||||
#refundAddress: refundAddress,
|
||||
#refundExtraId: refundExtraId,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<_i11.ExchangeTransaction>>.value(
|
||||
_FakeChangeNowResponse_0<_i11.ExchangeTransaction>())) as _i5
|
||||
.Future<_i2.ChangeNowResponse<_i11.ExchangeTransaction>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<_i12.ExchangeTransactionStatus>>
|
||||
getTransactionStatus({String? id, String? apiKey}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getTransactionStatus, [], {#id: id, #apiKey: apiKey}),
|
||||
returnValue:
|
||||
Future<_i2.ChangeNowResponse<_i12.ExchangeTransactionStatus>>.value(
|
||||
_FakeChangeNowResponse_0<_i12.ExchangeTransactionStatus>())) as _i5
|
||||
.Future<_i2.ChangeNowResponse<_i12.ExchangeTransactionStatus>>);
|
||||
@override
|
||||
_i5.Future<_i2.ChangeNowResponse<List<_i13.AvailableFloatingRatePair>>>
|
||||
getAvailableFloatingRatePairs({bool? includePartners = false}) => (super
|
||||
.noSuchMethod(
|
||||
Invocation.method(#getAvailableFloatingRatePairs, [],
|
||||
{#includePartners: includePartners}),
|
||||
returnValue:
|
||||
Future<_i2.ChangeNowResponse<List<_i13.AvailableFloatingRatePair>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i13.AvailableFloatingRatePair>>())) as _i5
|
||||
.Future<_i2.ChangeNowResponse<List<_i13.AvailableFloatingRatePair>>>);
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:mockito/annotations.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
|
||||
import 'package:stackwallet/services/trade_notes_service.dart';
|
||||
import 'package:stackwallet/services/trade_service.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
|
||||
@GenerateMocks([Prefs, TradesService, TradeNotesService, ChangeNow])
|
||||
@GenerateMocks([Prefs, TradesService, TradeNotesService, ChangeNowAPI])
|
||||
void main() {
|
||||
// testWidgets("ExchangeView builds correctly with no trade history",
|
||||
// (widgetTester) async {
|
||||
|
|
|
@ -8,24 +8,28 @@ import 'dart:ui' as _i8;
|
|||
import 'package:decimal/decimal.dart' as _i15;
|
||||
import 'package:http/http.dart' as _i13;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart'
|
||||
as _i20;
|
||||
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart'
|
||||
as _i2;
|
||||
import 'package:stackwallet/models/exchange/change_now/cn_exchange_estimate.dart'
|
||||
as _i17;
|
||||
import 'package:stackwallet/models/exchange/change_now/currency.dart' as _i14;
|
||||
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart'
|
||||
as _i16;
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'
|
||||
as _i10;
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'
|
||||
as _i19;
|
||||
import 'package:stackwallet/models/exchange/change_now/fixed_rate_market.dart'
|
||||
as _i18;
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart'
|
||||
as _i20;
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'
|
||||
as _i21;
|
||||
import 'package:stackwallet/models/exchange/response_objects/currency.dart'
|
||||
as _i14;
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart'
|
||||
as _i17;
|
||||
import 'package:stackwallet/models/exchange/response_objects/fixed_rate_market.dart'
|
||||
as _i19;
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart' as _i22;
|
||||
import 'package:stackwallet/models/exchange/response_objects/range.dart'
|
||||
as _i16;
|
||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart'
|
||||
as _i10;
|
||||
import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart'
|
||||
as _i5;
|
||||
import 'package:stackwallet/services/change_now/change_now.dart' as _i12;
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart'
|
||||
as _i12;
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart' as _i2;
|
||||
import 'package:stackwallet/services/trade_notes_service.dart' as _i11;
|
||||
import 'package:stackwallet/services/trade_service.dart' as _i9;
|
||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart' as _i6;
|
||||
|
@ -42,8 +46,8 @@ import 'package:stackwallet/utilities/prefs.dart' as _i3;
|
|||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
|
||||
class _FakeChangeNowResponse_0<T> extends _i1.Fake
|
||||
implements _i2.ChangeNowResponse<T> {}
|
||||
class _FakeExchangeResponse_0<T> extends _i1.Fake
|
||||
implements _i2.ExchangeResponse<T> {}
|
||||
|
||||
/// A class which mocks [Prefs].
|
||||
///
|
||||
|
@ -245,33 +249,28 @@ class MockTradesService extends _i1.Mock implements _i9.TradesService {
|
|||
}
|
||||
|
||||
@override
|
||||
List<_i10.ExchangeTransaction> get trades =>
|
||||
(super.noSuchMethod(Invocation.getter(#trades),
|
||||
returnValue: <_i10.ExchangeTransaction>[])
|
||||
as List<_i10.ExchangeTransaction>);
|
||||
List<_i10.Trade> get trades => (super.noSuchMethod(Invocation.getter(#trades),
|
||||
returnValue: <_i10.Trade>[]) as List<_i10.Trade>);
|
||||
@override
|
||||
bool get hasListeners =>
|
||||
(super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
|
||||
as bool);
|
||||
@override
|
||||
_i7.Future<void> add(
|
||||
{_i10.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
|
||||
_i7.Future<void> add({_i10.Trade? trade, bool? shouldNotifyListeners}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#add, [],
|
||||
{#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
|
||||
returnValue: Future<void>.value(),
|
||||
returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
|
||||
@override
|
||||
_i7.Future<void> edit(
|
||||
{_i10.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
|
||||
_i7.Future<void> edit({_i10.Trade? trade, bool? shouldNotifyListeners}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#edit, [],
|
||||
{#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
|
||||
returnValue: Future<void>.value(),
|
||||
returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
|
||||
@override
|
||||
_i7.Future<void> delete(
|
||||
{_i10.ExchangeTransaction? trade, bool? shouldNotifyListeners}) =>
|
||||
_i7.Future<void> delete({_i10.Trade? trade, bool? shouldNotifyListeners}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#delete, [],
|
||||
{#trade: trade, #shouldNotifyListeners: shouldNotifyListeners}),
|
||||
|
@ -347,11 +346,11 @@ class MockTradeNotesService extends _i1.Mock implements _i11.TradeNotesService {
|
|||
returnValueForMissingStub: null);
|
||||
}
|
||||
|
||||
/// A class which mocks [ChangeNow].
|
||||
/// A class which mocks [ChangeNowAPI].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
||||
MockChangeNow() {
|
||||
class MockChangeNowAPI extends _i1.Mock implements _i12.ChangeNowAPI {
|
||||
MockChangeNowAPI() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
|
@ -360,25 +359,25 @@ class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
|||
super.noSuchMethod(Invocation.setter(#client, _client),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<List<_i14.Currency>>> getAvailableCurrencies(
|
||||
_i7.Future<_i2.ExchangeResponse<List<_i14.Currency>>> getAvailableCurrencies(
|
||||
{bool? fixedRate, bool? active}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getAvailableCurrencies, [],
|
||||
{#fixedRate: fixedRate, #active: active}),
|
||||
returnValue: Future<_i2.ChangeNowResponse<List<_i14.Currency>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i14.Currency>>())) as _i7
|
||||
.Future<_i2.ChangeNowResponse<List<_i14.Currency>>>);
|
||||
returnValue: Future<_i2.ExchangeResponse<List<_i14.Currency>>>.value(
|
||||
_FakeExchangeResponse_0<List<_i14.Currency>>())) as _i7
|
||||
.Future<_i2.ExchangeResponse<List<_i14.Currency>>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<List<_i14.Currency>>> getPairedCurrencies(
|
||||
_i7.Future<_i2.ExchangeResponse<List<_i14.Currency>>> getPairedCurrencies(
|
||||
{String? ticker, bool? fixedRate}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getPairedCurrencies, [],
|
||||
{#ticker: ticker, #fixedRate: fixedRate}),
|
||||
returnValue: Future<_i2.ChangeNowResponse<List<_i14.Currency>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i14.Currency>>())) as _i7
|
||||
.Future<_i2.ChangeNowResponse<List<_i14.Currency>>>);
|
||||
returnValue: Future<_i2.ExchangeResponse<List<_i14.Currency>>>.value(
|
||||
_FakeExchangeResponse_0<List<_i14.Currency>>())) as _i7
|
||||
.Future<_i2.ExchangeResponse<List<_i14.Currency>>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<_i15.Decimal>> getMinimalExchangeAmount(
|
||||
_i7.Future<_i2.ExchangeResponse<_i15.Decimal>> getMinimalExchangeAmount(
|
||||
{String? fromTicker, String? toTicker, String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getMinimalExchangeAmount, [], {
|
||||
|
@ -386,12 +385,27 @@ class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
|||
#toTicker: toTicker,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<_i2.ChangeNowResponse<_i15.Decimal>>.value(
|
||||
_FakeChangeNowResponse_0<_i15.Decimal>()))
|
||||
as _i7.Future<_i2.ChangeNowResponse<_i15.Decimal>>);
|
||||
returnValue: Future<_i2.ExchangeResponse<_i15.Decimal>>.value(
|
||||
_FakeExchangeResponse_0<_i15.Decimal>()))
|
||||
as _i7.Future<_i2.ExchangeResponse<_i15.Decimal>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<_i16.EstimatedExchangeAmount>>
|
||||
getEstimatedExchangeAmount(
|
||||
_i7.Future<_i2.ExchangeResponse<_i16.Range>> getRange(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
bool? isFixedRate,
|
||||
String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getRange, [], {
|
||||
#fromTicker: fromTicker,
|
||||
#toTicker: toTicker,
|
||||
#isFixedRate: isFixedRate,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<_i2.ExchangeResponse<_i16.Range>>.value(
|
||||
_FakeExchangeResponse_0<_i16.Range>()))
|
||||
as _i7.Future<_i2.ExchangeResponse<_i16.Range>>);
|
||||
@override
|
||||
_i7.Future<_i2.ExchangeResponse<_i17.Estimate>> getEstimatedExchangeAmount(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
_i15.Decimal? fromAmount,
|
||||
|
@ -403,22 +417,40 @@ class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
|||
#fromAmount: fromAmount,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<
|
||||
_i16.EstimatedExchangeAmount>>.value(
|
||||
_FakeChangeNowResponse_0<_i16.EstimatedExchangeAmount>()))
|
||||
as _i7
|
||||
.Future<_i2.ChangeNowResponse<_i16.EstimatedExchangeAmount>>);
|
||||
returnValue: Future<_i2.ExchangeResponse<_i17.Estimate>>.value(
|
||||
_FakeExchangeResponse_0<_i17.Estimate>()))
|
||||
as _i7.Future<_i2.ExchangeResponse<_i17.Estimate>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<_i17.CNExchangeEstimate>>
|
||||
_i7.Future<_i2.ExchangeResponse<_i17.Estimate>>
|
||||
getEstimatedExchangeAmountFixedRate(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
_i15.Decimal? fromAmount,
|
||||
bool? reversed,
|
||||
bool? useRateId = true,
|
||||
String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getEstimatedExchangeAmountFixedRate, [], {
|
||||
#fromTicker: fromTicker,
|
||||
#toTicker: toTicker,
|
||||
#fromAmount: fromAmount,
|
||||
#reversed: reversed,
|
||||
#useRateId: useRateId,
|
||||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<_i2.ExchangeResponse<_i17.Estimate>>.value(
|
||||
_FakeExchangeResponse_0<_i17.Estimate>())) as _i7
|
||||
.Future<_i2.ExchangeResponse<_i17.Estimate>>);
|
||||
@override
|
||||
_i7.Future<_i2.ExchangeResponse<_i18.CNExchangeEstimate>>
|
||||
getEstimatedExchangeAmountV2(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
_i17.CNEstimateType? fromOrTo,
|
||||
_i18.CNEstimateType? fromOrTo,
|
||||
_i15.Decimal? amount,
|
||||
String? fromNetwork,
|
||||
String? toNetwork,
|
||||
_i17.CNFlowType? flow = _i17.CNFlowType.standard,
|
||||
_i18.CNFlowType? flow = _i18.CNFlowType.standard,
|
||||
String? apiKey}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getEstimatedExchangeAmountV2, [], {
|
||||
|
@ -432,20 +464,20 @@ class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
|||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<_i17.CNExchangeEstimate>>.value(
|
||||
_FakeChangeNowResponse_0<_i17.CNExchangeEstimate>()))
|
||||
as _i7.Future<_i2.ChangeNowResponse<_i17.CNExchangeEstimate>>);
|
||||
_i2.ExchangeResponse<_i18.CNExchangeEstimate>>.value(
|
||||
_FakeExchangeResponse_0<_i18.CNExchangeEstimate>()))
|
||||
as _i7.Future<_i2.ExchangeResponse<_i18.CNExchangeEstimate>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<List<_i18.FixedRateMarket>>>
|
||||
_i7.Future<_i2.ExchangeResponse<List<_i19.FixedRateMarket>>>
|
||||
getAvailableFixedRateMarkets({String? apiKey}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getAvailableFixedRateMarkets, [], {#apiKey: apiKey}),
|
||||
returnValue:
|
||||
Future<_i2.ChangeNowResponse<List<_i18.FixedRateMarket>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i18.FixedRateMarket>>())) as _i7
|
||||
.Future<_i2.ChangeNowResponse<List<_i18.FixedRateMarket>>>);
|
||||
Future<_i2.ExchangeResponse<List<_i19.FixedRateMarket>>>.value(
|
||||
_FakeExchangeResponse_0<List<_i19.FixedRateMarket>>())) as _i7
|
||||
.Future<_i2.ExchangeResponse<List<_i19.FixedRateMarket>>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>
|
||||
_i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>>
|
||||
createStandardExchangeTransaction(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
|
@ -471,17 +503,18 @@ class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
|||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<_i10.ExchangeTransaction>>.value(
|
||||
_FakeChangeNowResponse_0<_i10.ExchangeTransaction>())) as _i7
|
||||
.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>);
|
||||
_i2.ExchangeResponse<_i20.ExchangeTransaction>>.value(
|
||||
_FakeExchangeResponse_0<_i20.ExchangeTransaction>()))
|
||||
as _i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>
|
||||
_i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>>
|
||||
createFixedRateExchangeTransaction(
|
||||
{String? fromTicker,
|
||||
String? toTicker,
|
||||
String? receivingAddress,
|
||||
_i15.Decimal? amount,
|
||||
String? rateId,
|
||||
bool? reversed,
|
||||
String? extraId = r'',
|
||||
String? userId = r'',
|
||||
String? contactEmail = r'',
|
||||
|
@ -495,6 +528,7 @@ class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
|||
#receivingAddress: receivingAddress,
|
||||
#amount: amount,
|
||||
#rateId: rateId,
|
||||
#reversed: reversed,
|
||||
#extraId: extraId,
|
||||
#userId: userId,
|
||||
#contactEmail: contactEmail,
|
||||
|
@ -503,26 +537,25 @@ class MockChangeNow extends _i1.Mock implements _i12.ChangeNow {
|
|||
#apiKey: apiKey
|
||||
}),
|
||||
returnValue: Future<
|
||||
_i2.ChangeNowResponse<_i10.ExchangeTransaction>>.value(
|
||||
_FakeChangeNowResponse_0<_i10.ExchangeTransaction>())) as _i7
|
||||
.Future<_i2.ChangeNowResponse<_i10.ExchangeTransaction>>);
|
||||
_i2.ExchangeResponse<_i20.ExchangeTransaction>>.value(
|
||||
_FakeExchangeResponse_0<_i20.ExchangeTransaction>()))
|
||||
as _i7.Future<_i2.ExchangeResponse<_i20.ExchangeTransaction>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<_i19.ExchangeTransactionStatus>>
|
||||
_i7.Future<_i2.ExchangeResponse<_i21.ExchangeTransactionStatus>>
|
||||
getTransactionStatus({String? id, String? apiKey}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getTransactionStatus, [], {#id: id, #apiKey: apiKey}),
|
||||
returnValue:
|
||||
Future<_i2.ChangeNowResponse<_i19.ExchangeTransactionStatus>>.value(
|
||||
_FakeChangeNowResponse_0<_i19.ExchangeTransactionStatus>())) as _i7
|
||||
.Future<_i2.ChangeNowResponse<_i19.ExchangeTransactionStatus>>);
|
||||
Future<_i2.ExchangeResponse<_i21.ExchangeTransactionStatus>>.value(
|
||||
_FakeExchangeResponse_0<_i21.ExchangeTransactionStatus>())) as _i7
|
||||
.Future<_i2.ExchangeResponse<_i21.ExchangeTransactionStatus>>);
|
||||
@override
|
||||
_i7.Future<_i2.ChangeNowResponse<List<_i20.AvailableFloatingRatePair>>>
|
||||
getAvailableFloatingRatePairs({bool? includePartners = false}) => (super
|
||||
.noSuchMethod(
|
||||
_i7.Future<_i2.ExchangeResponse<List<_i22.Pair>>>
|
||||
getAvailableFloatingRatePairs({bool? includePartners = false}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getAvailableFloatingRatePairs, [],
|
||||
{#includePartners: includePartners}),
|
||||
returnValue:
|
||||
Future<_i2.ChangeNowResponse<List<_i20.AvailableFloatingRatePair>>>.value(
|
||||
_FakeChangeNowResponse_0<List<_i20.AvailableFloatingRatePair>>())) as _i7
|
||||
.Future<_i2.ChangeNowResponse<List<_i20.AvailableFloatingRatePair>>>);
|
||||
returnValue: Future<_i2.ExchangeResponse<List<_i22.Pair>>>.value(
|
||||
_FakeExchangeResponse_0<List<_i22.Pair>>())) as _i7
|
||||
.Future<_i2.ExchangeResponse<List<_i22.Pair>>>);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ import 'package:flutter_test/flutter_test.dart';
|
|||
import 'package:http/http.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/available_floating_rate_pair.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/change_now_response.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/estimated_exchange_amount.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
|
||||
import 'package:stackwallet/services/change_now/change_now.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/pair.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_api.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
|
||||
import 'change_now_sample_data.dart';
|
||||
import 'change_now_test.mocks.dart';
|
||||
|
@ -20,7 +20,7 @@ void main() {
|
|||
group("getAvailableCurrencies", () {
|
||||
test("getAvailableCurrencies succeeds without options", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||
|
@ -28,7 +28,7 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async =>
|
||||
Response(jsonEncode(availableCurrenciesJSON), 200));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableCurrencies();
|
||||
final result = await ChangeNowAPI.instance.getAvailableCurrencies();
|
||||
|
||||
expect(result.exception, null);
|
||||
expect(result.value == null, false);
|
||||
|
@ -37,7 +37,7 @@ void main() {
|
|||
|
||||
test("getAvailableCurrencies succeeds with active option", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies?active=true"),
|
||||
|
@ -46,7 +46,7 @@ void main() {
|
|||
Response(jsonEncode(availableCurrenciesJSONActive), 200));
|
||||
|
||||
final result =
|
||||
await ChangeNow.instance.getAvailableCurrencies(active: true);
|
||||
await ChangeNowAPI.instance.getAvailableCurrencies(active: true);
|
||||
|
||||
expect(result.exception, null);
|
||||
expect(result.value == null, false);
|
||||
|
@ -55,7 +55,7 @@ void main() {
|
|||
|
||||
test("getAvailableCurrencies succeeds with fixedRate option", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies?fixedRate=true"),
|
||||
|
@ -64,7 +64,7 @@ void main() {
|
|||
Response(jsonEncode(availableCurrenciesJSONFixedRate), 200));
|
||||
|
||||
final result =
|
||||
await ChangeNow.instance.getAvailableCurrencies(fixedRate: true);
|
||||
await ChangeNowAPI.instance.getAvailableCurrencies(fixedRate: true);
|
||||
|
||||
expect(result.exception, null);
|
||||
expect(result.value == null, false);
|
||||
|
@ -74,7 +74,7 @@ void main() {
|
|||
test("getAvailableCurrencies succeeds with fixedRate and active options",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -83,7 +83,7 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async =>
|
||||
Response(jsonEncode(availableCurrenciesJSONActiveFixedRate), 200));
|
||||
|
||||
final result = await ChangeNow.instance
|
||||
final result = await ChangeNowAPI.instance
|
||||
.getAvailableCurrencies(active: true, fixedRate: true);
|
||||
|
||||
expect(result.exception, null);
|
||||
|
@ -95,7 +95,7 @@ void main() {
|
|||
"getAvailableCurrencies fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||
|
@ -103,25 +103,25 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async =>
|
||||
Response('{"some unexpected": "but valid json data"}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableCurrencies();
|
||||
final result = await ChangeNowAPI.instance.getAvailableCurrencies();
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("getAvailableCurrencies fails for any other reason", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response("", 400));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableCurrencies();
|
||||
final result = await ChangeNowAPI.instance.getAvailableCurrencies();
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -129,7 +129,7 @@ void main() {
|
|||
group("getPairedCurrencies", () {
|
||||
test("getPairedCurrencies succeeds without fixedRate option", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"),
|
||||
|
@ -138,7 +138,7 @@ void main() {
|
|||
Response(jsonEncode(getPairedCurrenciesJSON), 200));
|
||||
|
||||
final result =
|
||||
await ChangeNow.instance.getPairedCurrencies(ticker: "XMR");
|
||||
await ChangeNowAPI.instance.getPairedCurrencies(ticker: "XMR");
|
||||
|
||||
expect(result.exception, null);
|
||||
expect(result.value == null, false);
|
||||
|
@ -147,7 +147,7 @@ void main() {
|
|||
|
||||
test("getPairedCurrencies succeeds with fixedRate option", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -156,7 +156,7 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async =>
|
||||
Response(jsonEncode(getPairedCurrenciesJSONFixedRate), 200));
|
||||
|
||||
final result = await ChangeNow.instance
|
||||
final result = await ChangeNowAPI.instance
|
||||
.getPairedCurrencies(ticker: "XMR", fixedRate: true);
|
||||
|
||||
expect(result.exception, null);
|
||||
|
@ -168,7 +168,7 @@ void main() {
|
|||
"getPairedCurrencies fails with ChangeNowExceptionType.serializeResponseError A",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"),
|
||||
|
@ -177,26 +177,26 @@ void main() {
|
|||
Response('[{"some unexpected": "but valid json data"}]', 200));
|
||||
|
||||
final result =
|
||||
await ChangeNow.instance.getPairedCurrencies(ticker: "XMR");
|
||||
await ChangeNowAPI.instance.getPairedCurrencies(ticker: "XMR");
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("getPairedCurrencies fails for any other reason", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/currencies"),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response("", 400));
|
||||
|
||||
final result = await ChangeNow.instance
|
||||
final result = await ChangeNowAPI.instance
|
||||
.getPairedCurrencies(ticker: "XMR", fixedRate: true);
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -204,7 +204,7 @@ void main() {
|
|||
group("getMinimalExchangeAmount", () {
|
||||
test("getMinimalExchangeAmount succeeds", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -213,7 +213,7 @@ void main() {
|
|||
)).thenAnswer(
|
||||
(realInvocation) async => Response('{"minAmount": 42}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getMinimalExchangeAmount(
|
||||
final result = await ChangeNowAPI.instance.getMinimalExchangeAmount(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
apiKey: "testAPIKEY",
|
||||
|
@ -228,7 +228,7 @@ void main() {
|
|||
"getMinimalExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -236,20 +236,20 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getMinimalExchangeAmount(
|
||||
final result = await ChangeNowAPI.instance.getMinimalExchangeAmount(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("getMinimalExchangeAmount fails for any other reason", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -257,13 +257,13 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||
|
||||
final result = await ChangeNow.instance.getMinimalExchangeAmount(
|
||||
final result = await ChangeNowAPI.instance.getMinimalExchangeAmount(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -271,7 +271,7 @@ void main() {
|
|||
group("getEstimatedExchangeAmount", () {
|
||||
test("getEstimatedExchangeAmount succeeds", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -281,7 +281,7 @@ void main() {
|
|||
'{"estimatedAmount": 58.4142873, "transactionSpeedForecast": "10-60", "warningMessage": null}',
|
||||
200));
|
||||
|
||||
final result = await ChangeNow.instance.getEstimatedExchangeAmount(
|
||||
final result = await ChangeNowAPI.instance.getEstimatedExchangeAmount(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
fromAmount: Decimal.fromInt(42),
|
||||
|
@ -297,7 +297,7 @@ void main() {
|
|||
"getEstimatedExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -305,21 +305,21 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getEstimatedExchangeAmount(
|
||||
final result = await ChangeNowAPI.instance.getEstimatedExchangeAmount(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
fromAmount: Decimal.fromInt(42),
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("getEstimatedExchangeAmount fails for any other reason", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -327,14 +327,14 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||
|
||||
final result = await ChangeNow.instance.getEstimatedExchangeAmount(
|
||||
final result = await ChangeNowAPI.instance.getEstimatedExchangeAmount(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
fromAmount: Decimal.fromInt(42),
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -417,7 +417,7 @@ void main() {
|
|||
group("getAvailableFixedRateMarkets", () {
|
||||
test("getAvailableFixedRateMarkets succeeds", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -426,7 +426,7 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async =>
|
||||
Response(jsonEncode(fixedRateMarketsJSON), 200));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableFixedRateMarkets(
|
||||
final result = await ChangeNowAPI.instance.getAvailableFixedRateMarkets(
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
|
@ -439,7 +439,7 @@ void main() {
|
|||
"getAvailableFixedRateMarkets fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -447,18 +447,18 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableFixedRateMarkets(
|
||||
final result = await ChangeNowAPI.instance.getAvailableFixedRateMarkets(
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("getAvailableFixedRateMarkets fails for any other reason", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -466,11 +466,11 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableFixedRateMarkets(
|
||||
final result = await ChangeNowAPI.instance.getAvailableFixedRateMarkets(
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -478,7 +478,7 @@ void main() {
|
|||
group("createStandardExchangeTransaction", () {
|
||||
test("createStandardExchangeTransaction succeeds", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.post(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
|
||||
|
@ -489,7 +489,8 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async =>
|
||||
Response(jsonEncode(createStandardTransactionResponse), 200));
|
||||
|
||||
final result = await ChangeNow.instance.createStandardExchangeTransaction(
|
||||
final result =
|
||||
await ChangeNowAPI.instance.createStandardExchangeTransaction(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||
|
@ -508,7 +509,7 @@ void main() {
|
|||
"createStandardExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.post(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
|
||||
|
@ -518,7 +519,8 @@ void main() {
|
|||
encoding: null,
|
||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.createStandardExchangeTransaction(
|
||||
final result =
|
||||
await ChangeNowAPI.instance.createStandardExchangeTransaction(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||
|
@ -528,15 +530,15 @@ void main() {
|
|||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("createStandardExchangeTransaction fails for any other reason",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.post(
|
||||
Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
|
||||
|
@ -546,7 +548,8 @@ void main() {
|
|||
encoding: null,
|
||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||
|
||||
final result = await ChangeNow.instance.createStandardExchangeTransaction(
|
||||
final result =
|
||||
await ChangeNowAPI.instance.createStandardExchangeTransaction(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||
|
@ -556,7 +559,7 @@ void main() {
|
|||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -564,7 +567,7 @@ void main() {
|
|||
group("createFixedRateExchangeTransaction", () {
|
||||
test("createFixedRateExchangeTransaction succeeds", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.post(
|
||||
Uri.parse(
|
||||
|
@ -578,7 +581,7 @@ void main() {
|
|||
200));
|
||||
|
||||
final result =
|
||||
await ChangeNow.instance.createFixedRateExchangeTransaction(
|
||||
await ChangeNowAPI.instance.createFixedRateExchangeTransaction(
|
||||
fromTicker: "btc",
|
||||
toTicker: "eth",
|
||||
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
|
||||
|
@ -586,6 +589,7 @@ void main() {
|
|||
refundAddress: "",
|
||||
apiKey: "testAPIKEY",
|
||||
rateId: '',
|
||||
reversed: false,
|
||||
);
|
||||
|
||||
expect(result.exception, null);
|
||||
|
@ -597,7 +601,7 @@ void main() {
|
|||
"createFixedRateExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.post(
|
||||
Uri.parse(
|
||||
|
@ -610,7 +614,7 @@ void main() {
|
|||
Response('{"id": "a5c73e2603f40d","amount": 62.9737711}', 200));
|
||||
|
||||
final result =
|
||||
await ChangeNow.instance.createFixedRateExchangeTransaction(
|
||||
await ChangeNowAPI.instance.createFixedRateExchangeTransaction(
|
||||
fromTicker: "btc",
|
||||
toTicker: "eth",
|
||||
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
|
||||
|
@ -618,17 +622,18 @@ void main() {
|
|||
refundAddress: "",
|
||||
apiKey: "testAPIKEY",
|
||||
rateId: '',
|
||||
reversed: false,
|
||||
);
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("createFixedRateExchangeTransaction fails for any other reason",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.post(
|
||||
Uri.parse(
|
||||
|
@ -640,7 +645,7 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||
|
||||
final result =
|
||||
await ChangeNow.instance.createFixedRateExchangeTransaction(
|
||||
await ChangeNowAPI.instance.createFixedRateExchangeTransaction(
|
||||
fromTicker: "xmr",
|
||||
toTicker: "btc",
|
||||
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
|
||||
|
@ -649,9 +654,10 @@ void main() {
|
|||
"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H",
|
||||
apiKey: "testAPIKEY",
|
||||
rateId: '',
|
||||
reversed: false,
|
||||
);
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -659,7 +665,7 @@ void main() {
|
|||
group("getTransactionStatus", () {
|
||||
test("getTransactionStatus succeeds", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -669,7 +675,7 @@ void main() {
|
|||
'{"status": "waiting", "payinAddress": "32Ge2ci26rj1sRGw2NjiQa9L7Xvxtgzhrj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "fromCurrency": "btc", "toCurrency": "eth", "id": "50727663e5d9a4", "updatedAt": "2019-08-22T14:47:49.943Z", "expectedSendAmount": 1, "expectedReceiveAmount": 52.31667, "createdAt": "2019-08-22T14:47:49.943Z", "isPartner": false}',
|
||||
200));
|
||||
|
||||
final result = await ChangeNow.instance.getTransactionStatus(
|
||||
final result = await ChangeNowAPI.instance.getTransactionStatus(
|
||||
id: "47F87eDB1675566DAfF5EC886",
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
@ -683,7 +689,7 @@ void main() {
|
|||
"getTransactionStatus fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -691,19 +697,19 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getTransactionStatus(
|
||||
final result = await ChangeNowAPI.instance.getTransactionStatus(
|
||||
id: "47F87eDB1675566DAfF5EC886",
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("getTransactionStatus fails for any other reason", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -711,12 +717,12 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||
|
||||
final result = await ChangeNow.instance.getTransactionStatus(
|
||||
final result = await ChangeNowAPI.instance.getTransactionStatus(
|
||||
id: "47F87eDB1675566DAfF5EC886",
|
||||
apiKey: "testAPIKEY",
|
||||
);
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
@ -724,7 +730,7 @@ void main() {
|
|||
group("getAvailableFloatingRatePairs", () {
|
||||
test("getAvailableFloatingRatePairs succeeds", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -733,18 +739,19 @@ void main() {
|
|||
)).thenAnswer((realInvocation) async =>
|
||||
Response('["btc_xmr","btc_firo","btc_doge","eth_ltc"]', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableFloatingRatePairs();
|
||||
final result =
|
||||
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
|
||||
|
||||
expect(result.exception, null);
|
||||
expect(result.value == null, false);
|
||||
expect(result.value, isA<List<AvailableFloatingRatePair>>());
|
||||
expect(result.value, isA<List<Pair>>());
|
||||
});
|
||||
|
||||
test(
|
||||
"getAvailableFloatingRatePairs fails with ChangeNowExceptionType.serializeResponseError",
|
||||
() async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -752,16 +759,17 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableFloatingRatePairs();
|
||||
final result =
|
||||
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
|
||||
|
||||
expect(result.exception!.type,
|
||||
ChangeNowExceptionType.serializeResponseError);
|
||||
expect(
|
||||
result.exception!.type, ExchangeExceptionType.serializeResponseError);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
|
||||
test("getAvailableFloatingRatePairs fails for any other reason", () async {
|
||||
final client = MockClient();
|
||||
ChangeNow.instance.client = client;
|
||||
ChangeNowAPI.instance.client = client;
|
||||
|
||||
when(client.get(
|
||||
Uri.parse(
|
||||
|
@ -769,9 +777,10 @@ void main() {
|
|||
headers: {'Content-Type': 'application/json'},
|
||||
)).thenAnswer((realInvocation) async => Response('', 400));
|
||||
|
||||
final result = await ChangeNow.instance.getAvailableFloatingRatePairs();
|
||||
final result =
|
||||
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
|
||||
|
||||
expect(result.exception!.type, ChangeNowExceptionType.generic);
|
||||
expect(result.exception!.type, ExchangeExceptionType.generic);
|
||||
expect(result.value == null, true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,18 +2,18 @@
|
|||
// in stackwallet/test/services/coins/bitcoincash/bitcoincash_wallet_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
import 'dart:async' as _i7;
|
||||
import 'dart:async' as _i6;
|
||||
|
||||
import 'package:decimal/decimal.dart' as _i4;
|
||||
import 'package:http/http.dart' as _i3;
|
||||
import 'package:decimal/decimal.dart' as _i2;
|
||||
import 'package:http/http.dart' as _i4;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i5;
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i6;
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart' as _i7;
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart' as _i5;
|
||||
import 'package:stackwallet/services/price.dart' as _i9;
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart'
|
||||
as _i11;
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart' as _i8;
|
||||
import 'package:stackwallet/utilities/prefs.dart' as _i2;
|
||||
import 'package:stackwallet/utilities/prefs.dart' as _i3;
|
||||
import 'package:tuple/tuple.dart' as _i10;
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
@ -26,16 +26,208 @@ import 'package:tuple/tuple.dart' as _i10;
|
|||
// ignore_for_file: unnecessary_parenthesis
|
||||
// ignore_for_file: camel_case_types
|
||||
|
||||
class _FakePrefs_0 extends _i1.Fake implements _i2.Prefs {}
|
||||
class _FakeDecimal_0 extends _i1.Fake implements _i2.Decimal {}
|
||||
|
||||
class _FakeClient_1 extends _i1.Fake implements _i3.Client {}
|
||||
class _FakePrefs_1 extends _i1.Fake implements _i3.Prefs {}
|
||||
|
||||
class _FakeDecimal_2 extends _i1.Fake implements _i4.Decimal {}
|
||||
class _FakeClient_2 extends _i1.Fake implements _i4.Client {}
|
||||
|
||||
/// A class which mocks [ElectrumX].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockElectrumX extends _i1.Mock implements _i5.ElectrumX {
|
||||
MockElectrumX() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
set failovers(List<_i5.ElectrumXNode>? _failovers) =>
|
||||
super.noSuchMethod(Invocation.setter(#failovers, _failovers),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
int get currentFailoverIndex =>
|
||||
(super.noSuchMethod(Invocation.getter(#currentFailoverIndex),
|
||||
returnValue: 0) as int);
|
||||
@override
|
||||
set currentFailoverIndex(int? _currentFailoverIndex) => super.noSuchMethod(
|
||||
Invocation.setter(#currentFailoverIndex, _currentFailoverIndex),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
String get host =>
|
||||
(super.noSuchMethod(Invocation.getter(#host), returnValue: '') as String);
|
||||
@override
|
||||
int get port =>
|
||||
(super.noSuchMethod(Invocation.getter(#port), returnValue: 0) as int);
|
||||
@override
|
||||
bool get useSSL =>
|
||||
(super.noSuchMethod(Invocation.getter(#useSSL), returnValue: false)
|
||||
as bool);
|
||||
@override
|
||||
_i6.Future<dynamic> request(
|
||||
{String? command,
|
||||
List<dynamic>? args = const [],
|
||||
Duration? connectionTimeout = const Duration(seconds: 60),
|
||||
String? requestID,
|
||||
int? retries = 2}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#request, [], {
|
||||
#command: command,
|
||||
#args: args,
|
||||
#connectionTimeout: connectionTimeout,
|
||||
#requestID: requestID,
|
||||
#retries: retries
|
||||
}),
|
||||
returnValue: Future<dynamic>.value()) as _i6.Future<dynamic>);
|
||||
@override
|
||||
_i6.Future<List<Map<String, dynamic>>> batchRequest(
|
||||
{String? command,
|
||||
Map<String, List<dynamic>>? args,
|
||||
Duration? connectionTimeout = const Duration(seconds: 60),
|
||||
int? retries = 2}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#batchRequest, [], {
|
||||
#command: command,
|
||||
#args: args,
|
||||
#connectionTimeout: connectionTimeout,
|
||||
#retries: retries
|
||||
}),
|
||||
returnValue: Future<List<Map<String, dynamic>>>.value(
|
||||
<Map<String, dynamic>>[]))
|
||||
as _i6.Future<List<Map<String, dynamic>>>);
|
||||
@override
|
||||
_i6.Future<bool> ping({String? requestID, int? retryCount = 1}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#ping, [], {#requestID: requestID, #retryCount: retryCount}),
|
||||
returnValue: Future<bool>.value(false)) as _i6.Future<bool>);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getBlockHeadTip({String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getBlockHeadTip, [], {#requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getServerFeatures({String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getServerFeatures, [], {#requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{})) as _i6
|
||||
.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i6.Future<String> broadcastTransaction({String? rawTx, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#broadcastTransaction, [],
|
||||
{#rawTx: rawTx, #requestID: requestID}),
|
||||
returnValue: Future<String>.value('')) as _i6.Future<String>);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getBalance(
|
||||
{String? scripthash, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getBalance, [],
|
||||
{#scripthash: scripthash, #requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i6.Future<List<Map<String, dynamic>>> getHistory(
|
||||
{String? scripthash, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getHistory, [],
|
||||
{#scripthash: scripthash, #requestID: requestID}),
|
||||
returnValue: Future<List<Map<String, dynamic>>>.value(
|
||||
<Map<String, dynamic>>[]))
|
||||
as _i6.Future<List<Map<String, dynamic>>>);
|
||||
@override
|
||||
_i6.Future<Map<String, List<Map<String, dynamic>>>> getBatchHistory(
|
||||
{Map<String, List<dynamic>>? args}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getBatchHistory, [], {#args: args}),
|
||||
returnValue: Future<Map<String, List<Map<String, dynamic>>>>.value(
|
||||
<String, List<Map<String, dynamic>>>{})) as _i6
|
||||
.Future<Map<String, List<Map<String, dynamic>>>>);
|
||||
@override
|
||||
_i6.Future<List<Map<String, dynamic>>> getUTXOs(
|
||||
{String? scripthash, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getUTXOs, [], {#scripthash: scripthash, #requestID: requestID}),
|
||||
returnValue: Future<List<Map<String, dynamic>>>.value(
|
||||
<Map<String, dynamic>>[])) as _i6
|
||||
.Future<List<Map<String, dynamic>>>);
|
||||
@override
|
||||
_i6.Future<Map<String, List<Map<String, dynamic>>>> getBatchUTXOs(
|
||||
{Map<String, List<dynamic>>? args}) =>
|
||||
(super.noSuchMethod(Invocation.method(#getBatchUTXOs, [], {#args: args}),
|
||||
returnValue: Future<Map<String, List<Map<String, dynamic>>>>.value(
|
||||
<String, List<Map<String, dynamic>>>{})) as _i6
|
||||
.Future<Map<String, List<Map<String, dynamic>>>>);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getTransaction(
|
||||
{String? txHash, bool? verbose = true, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getTransaction, [],
|
||||
{#txHash: txHash, #verbose: verbose, #requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getAnonymitySet(
|
||||
{String? groupId = r'1',
|
||||
String? blockhash = r'',
|
||||
String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getAnonymitySet, [], {
|
||||
#groupId: groupId,
|
||||
#blockhash: blockhash,
|
||||
#requestID: requestID
|
||||
}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i6.Future<dynamic> getMintData({dynamic mints, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getMintData, [], {#mints: mints, #requestID: requestID}),
|
||||
returnValue: Future<dynamic>.value()) as _i6.Future<dynamic>);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getUsedCoinSerials(
|
||||
{String? requestID, int? startNumber}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getUsedCoinSerials, [],
|
||||
{#requestID: requestID, #startNumber: startNumber}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i6.Future<int> getLatestCoinId({String? requestID}) => (super.noSuchMethod(
|
||||
Invocation.method(#getLatestCoinId, [], {#requestID: requestID}),
|
||||
returnValue: Future<int>.value(0)) as _i6.Future<int>);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getFeeRate({String? requestID}) => (super
|
||||
.noSuchMethod(Invocation.method(#getFeeRate, [], {#requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{})) as _i6
|
||||
.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i6.Future<_i2.Decimal> estimateFee({String? requestID, int? blocks}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#estimateFee, [], {#requestID: requestID, #blocks: blocks}),
|
||||
returnValue: Future<_i2.Decimal>.value(_FakeDecimal_0()))
|
||||
as _i6.Future<_i2.Decimal>);
|
||||
@override
|
||||
_i6.Future<_i2.Decimal> relayFee({String? requestID}) => (super.noSuchMethod(
|
||||
Invocation.method(#relayFee, [], {#requestID: requestID}),
|
||||
returnValue: Future<_i2.Decimal>.value(_FakeDecimal_0()))
|
||||
as _i6.Future<_i2.Decimal>);
|
||||
}
|
||||
|
||||
/// A class which mocks [CachedElectrumX].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockCachedElectrumX extends _i1.Mock implements _i5.CachedElectrumX {
|
||||
class MockCachedElectrumX extends _i1.Mock implements _i7.CachedElectrumX {
|
||||
MockCachedElectrumX() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
@ -52,44 +244,44 @@ class MockCachedElectrumX extends _i1.Mock implements _i5.CachedElectrumX {
|
|||
(super.noSuchMethod(Invocation.getter(#useSSL), returnValue: false)
|
||||
as bool);
|
||||
@override
|
||||
_i2.Prefs get prefs => (super.noSuchMethod(Invocation.getter(#prefs),
|
||||
returnValue: _FakePrefs_0()) as _i2.Prefs);
|
||||
_i3.Prefs get prefs => (super.noSuchMethod(Invocation.getter(#prefs),
|
||||
returnValue: _FakePrefs_1()) as _i3.Prefs);
|
||||
@override
|
||||
List<_i6.ElectrumXNode> get failovers =>
|
||||
List<_i5.ElectrumXNode> get failovers =>
|
||||
(super.noSuchMethod(Invocation.getter(#failovers),
|
||||
returnValue: <_i6.ElectrumXNode>[]) as List<_i6.ElectrumXNode>);
|
||||
returnValue: <_i5.ElectrumXNode>[]) as List<_i5.ElectrumXNode>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getAnonymitySet(
|
||||
_i6.Future<Map<String, dynamic>> getAnonymitySet(
|
||||
{String? groupId, String? blockhash = r'', _i8.Coin? coin}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getAnonymitySet, [],
|
||||
{#groupId: groupId, #blockhash: blockhash, #coin: coin}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i7.Future<Map<String, dynamic>>);
|
||||
as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getTransaction(
|
||||
_i6.Future<Map<String, dynamic>> getTransaction(
|
||||
{String? txHash, _i8.Coin? coin, bool? verbose = true}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getTransaction, [],
|
||||
{#txHash: txHash, #coin: coin, #verbose: verbose}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i7.Future<Map<String, dynamic>>);
|
||||
as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<List<dynamic>> getUsedCoinSerials(
|
||||
_i6.Future<List<dynamic>> getUsedCoinSerials(
|
||||
{_i8.Coin? coin, int? startNumber = 0}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getUsedCoinSerials, [],
|
||||
{#coin: coin, #startNumber: startNumber}),
|
||||
returnValue: Future<List<dynamic>>.value(<dynamic>[]))
|
||||
as _i7.Future<List<dynamic>>);
|
||||
as _i6.Future<List<dynamic>>);
|
||||
@override
|
||||
_i7.Future<void> clearSharedTransactionCache({_i8.Coin? coin}) =>
|
||||
_i6.Future<void> clearSharedTransactionCache({_i8.Coin? coin}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#clearSharedTransactionCache, [], {#coin: coin}),
|
||||
returnValue: Future<void>.value(),
|
||||
returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
|
||||
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||
}
|
||||
|
||||
/// A class which mocks [PriceAPI].
|
||||
|
@ -101,21 +293,21 @@ class MockPriceAPI extends _i1.Mock implements _i9.PriceAPI {
|
|||
}
|
||||
|
||||
@override
|
||||
_i3.Client get client => (super.noSuchMethod(Invocation.getter(#client),
|
||||
returnValue: _FakeClient_1()) as _i3.Client);
|
||||
_i4.Client get client => (super.noSuchMethod(Invocation.getter(#client),
|
||||
returnValue: _FakeClient_2()) as _i4.Client);
|
||||
@override
|
||||
void resetLastCalledToForceNextCallToUpdateCache() => super.noSuchMethod(
|
||||
Invocation.method(#resetLastCalledToForceNextCallToUpdateCache, []),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
_i7.Future<Map<_i8.Coin, _i10.Tuple2<_i4.Decimal, double>>>
|
||||
_i6.Future<Map<_i8.Coin, _i10.Tuple2<_i2.Decimal, double>>>
|
||||
getPricesAnd24hChange({String? baseCurrency}) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getPricesAnd24hChange, [], {#baseCurrency: baseCurrency}),
|
||||
returnValue:
|
||||
Future<Map<_i8.Coin, _i10.Tuple2<_i4.Decimal, double>>>.value(
|
||||
<_i8.Coin, _i10.Tuple2<_i4.Decimal, double>>{}))
|
||||
as _i7.Future<Map<_i8.Coin, _i10.Tuple2<_i4.Decimal, double>>>);
|
||||
Future<Map<_i8.Coin, _i10.Tuple2<_i2.Decimal, double>>>.value(
|
||||
<_i8.Coin, _i10.Tuple2<_i2.Decimal, double>>{}))
|
||||
as _i6.Future<Map<_i8.Coin, _i10.Tuple2<_i2.Decimal, double>>>);
|
||||
}
|
||||
|
||||
/// A class which mocks [TransactionNotificationTracker].
|
||||
|
@ -144,205 +336,17 @@ class MockTransactionNotificationTracker extends _i1.Mock
|
|||
(super.noSuchMethod(Invocation.method(#wasNotifiedPending, [txid]),
|
||||
returnValue: false) as bool);
|
||||
@override
|
||||
_i7.Future<void> addNotifiedPending(String? txid) =>
|
||||
_i6.Future<void> addNotifiedPending(String? txid) =>
|
||||
(super.noSuchMethod(Invocation.method(#addNotifiedPending, [txid]),
|
||||
returnValue: Future<void>.value(),
|
||||
returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
|
||||
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||
@override
|
||||
bool wasNotifiedConfirmed(String? txid) =>
|
||||
(super.noSuchMethod(Invocation.method(#wasNotifiedConfirmed, [txid]),
|
||||
returnValue: false) as bool);
|
||||
@override
|
||||
_i7.Future<void> addNotifiedConfirmed(String? txid) =>
|
||||
_i6.Future<void> addNotifiedConfirmed(String? txid) =>
|
||||
(super.noSuchMethod(Invocation.method(#addNotifiedConfirmed, [txid]),
|
||||
returnValue: Future<void>.value(),
|
||||
returnValueForMissingStub: Future<void>.value()) as _i7.Future<void>);
|
||||
}
|
||||
|
||||
/// A class which mocks [ElectrumX].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockElectrumX extends _i1.Mock implements _i6.ElectrumX {
|
||||
@override
|
||||
set failovers(List<_i6.ElectrumXNode>? _failovers) =>
|
||||
super.noSuchMethod(Invocation.setter(#failovers, _failovers),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
int get currentFailoverIndex =>
|
||||
(super.noSuchMethod(Invocation.getter(#currentFailoverIndex),
|
||||
returnValue: 0) as int);
|
||||
@override
|
||||
set currentFailoverIndex(int? _currentFailoverIndex) => super.noSuchMethod(
|
||||
Invocation.setter(#currentFailoverIndex, _currentFailoverIndex),
|
||||
returnValueForMissingStub: null);
|
||||
@override
|
||||
String get host =>
|
||||
(super.noSuchMethod(Invocation.getter(#host), returnValue: '') as String);
|
||||
@override
|
||||
int get port =>
|
||||
(super.noSuchMethod(Invocation.getter(#port), returnValue: 0) as int);
|
||||
@override
|
||||
bool get useSSL =>
|
||||
(super.noSuchMethod(Invocation.getter(#useSSL), returnValue: false)
|
||||
as bool);
|
||||
@override
|
||||
_i7.Future<dynamic> request(
|
||||
{String? command,
|
||||
List<dynamic>? args = const [],
|
||||
Duration? connectionTimeout = const Duration(seconds: 60),
|
||||
String? requestID,
|
||||
int? retries = 2}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#request, [], {
|
||||
#command: command,
|
||||
#args: args,
|
||||
#connectionTimeout: connectionTimeout,
|
||||
#requestID: requestID,
|
||||
#retries: retries
|
||||
}),
|
||||
returnValue: Future<dynamic>.value()) as _i7.Future<dynamic>);
|
||||
@override
|
||||
_i7.Future<List<Map<String, dynamic>>> batchRequest(
|
||||
{String? command,
|
||||
Map<String, List<dynamic>>? args,
|
||||
Duration? connectionTimeout = const Duration(seconds: 60),
|
||||
int? retries = 2}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#batchRequest, [], {
|
||||
#command: command,
|
||||
#args: args,
|
||||
#connectionTimeout: connectionTimeout,
|
||||
#retries: retries
|
||||
}),
|
||||
returnValue: Future<List<Map<String, dynamic>>>.value(
|
||||
<Map<String, dynamic>>[]))
|
||||
as _i7.Future<List<Map<String, dynamic>>>);
|
||||
@override
|
||||
_i7.Future<bool> ping({String? requestID, int? retryCount = 1}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#ping, [], {#requestID: requestID, #retryCount: retryCount}),
|
||||
returnValue: Future<bool>.value(false)) as _i7.Future<bool>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getBlockHeadTip({String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getBlockHeadTip, [], {#requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i7.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getServerFeatures({String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getServerFeatures, [], {#requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{})) as _i7
|
||||
.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<String> broadcastTransaction({String? rawTx, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#broadcastTransaction, [],
|
||||
{#rawTx: rawTx, #requestID: requestID}),
|
||||
returnValue: Future<String>.value('')) as _i7.Future<String>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getBalance(
|
||||
{String? scripthash, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getBalance, [],
|
||||
{#scripthash: scripthash, #requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i7.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<List<Map<String, dynamic>>> getHistory(
|
||||
{String? scripthash, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getHistory, [],
|
||||
{#scripthash: scripthash, #requestID: requestID}),
|
||||
returnValue: Future<List<Map<String, dynamic>>>.value(
|
||||
<Map<String, dynamic>>[]))
|
||||
as _i7.Future<List<Map<String, dynamic>>>);
|
||||
@override
|
||||
_i7.Future<Map<String, List<Map<String, dynamic>>>> getBatchHistory(
|
||||
{Map<String, List<dynamic>>? args}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getBatchHistory, [], {#args: args}),
|
||||
returnValue: Future<Map<String, List<Map<String, dynamic>>>>.value(
|
||||
<String, List<Map<String, dynamic>>>{})) as _i7
|
||||
.Future<Map<String, List<Map<String, dynamic>>>>);
|
||||
@override
|
||||
_i7.Future<List<Map<String, dynamic>>> getUTXOs(
|
||||
{String? scripthash, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getUTXOs, [], {#scripthash: scripthash, #requestID: requestID}),
|
||||
returnValue: Future<List<Map<String, dynamic>>>.value(
|
||||
<Map<String, dynamic>>[])) as _i7
|
||||
.Future<List<Map<String, dynamic>>>);
|
||||
@override
|
||||
_i7.Future<Map<String, List<Map<String, dynamic>>>> getBatchUTXOs(
|
||||
{Map<String, List<dynamic>>? args}) =>
|
||||
(super.noSuchMethod(Invocation.method(#getBatchUTXOs, [], {#args: args}),
|
||||
returnValue: Future<Map<String, List<Map<String, dynamic>>>>.value(
|
||||
<String, List<Map<String, dynamic>>>{})) as _i7
|
||||
.Future<Map<String, List<Map<String, dynamic>>>>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getTransaction(
|
||||
{String? txHash, bool? verbose = true, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getTransaction, [],
|
||||
{#txHash: txHash, #verbose: verbose, #requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i7.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getAnonymitySet(
|
||||
{String? groupId = r'1',
|
||||
String? blockhash = r'',
|
||||
String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getAnonymitySet, [], {
|
||||
#groupId: groupId,
|
||||
#blockhash: blockhash,
|
||||
#requestID: requestID
|
||||
}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i7.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<dynamic> getMintData({dynamic mints, String? requestID}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#getMintData, [], {#mints: mints, #requestID: requestID}),
|
||||
returnValue: Future<dynamic>.value()) as _i7.Future<dynamic>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getUsedCoinSerials(
|
||||
{String? requestID, int? startNumber}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(#getUsedCoinSerials, [],
|
||||
{#requestID: requestID, #startNumber: startNumber}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
|
||||
as _i7.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<int> getLatestCoinId({String? requestID}) => (super.noSuchMethod(
|
||||
Invocation.method(#getLatestCoinId, [], {#requestID: requestID}),
|
||||
returnValue: Future<int>.value(0)) as _i7.Future<int>);
|
||||
@override
|
||||
_i7.Future<Map<String, dynamic>> getFeeRate({String? requestID}) => (super
|
||||
.noSuchMethod(Invocation.method(#getFeeRate, [], {#requestID: requestID}),
|
||||
returnValue:
|
||||
Future<Map<String, dynamic>>.value(<String, dynamic>{})) as _i7
|
||||
.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
_i7.Future<_i4.Decimal> estimateFee({String? requestID, int? blocks}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#estimateFee, [], {#requestID: requestID, #blocks: blocks}),
|
||||
returnValue: Future<_i4.Decimal>.value(_FakeDecimal_2()))
|
||||
as _i7.Future<_i4.Decimal>);
|
||||
@override
|
||||
_i7.Future<_i4.Decimal> relayFee({String? requestID}) => (super.noSuchMethod(
|
||||
Invocation.method(#relayFee, [], {#requestID: requestID}),
|
||||
returnValue: Future<_i4.Decimal>.value(_FakeDecimal_2()))
|
||||
as _i7.Future<_i4.Decimal>);
|
||||
returnValueForMissingStub: Future<void>.value()) as _i6.Future<void>);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue