Merge pull request #14 from Instadapp/reflexer

Add Reflexer
This commit is contained in:
Thrilok kumar 2021-09-16 23:51:41 +05:30 committed by GitHub
commit 2ae25c1f7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 2108 additions and 16 deletions

View File

@ -1,5 +1,5 @@
<svg viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<g clip-path="url(#clip0123)">
<path d="M28.6212 428.148L21.8137 413.517C19.2469 406.633 16.6833 399.75 14.1227 392.866C11.8043 383.976 9.48508 375.088 7.16513 366.201C5.90907 358.137 3.15326 350.343 2.84393 342.108C2.01281 336.083 1.18402 330.057 0.357582 324.03C0.340397 321.163 0.322479 318.297 0.303732 315.431C0.512293 302.816 -0.507069 290.196 0.345925 277.581C1.81054 273.096 1.30196 268.373 2.0331 263.792C2.99857 257.79 3.77195 251.758 4.62729 245.733C7.15815 234.819 9.10083 223.769 12.3863 213.036L21.0006 188.098C24.2813 182.272 26.4771 175.952 29.2844 169.915C31.5599 165.017 34.0766 160.232 36.4903 155.385C42.1145 146.381 47.6144 137.284 53.4542 128.416C56.7813 122.993 60.6083 117.893 64.8852 113.183C72.3723 104.364 80.3516 95.9933 88.1809 87.5027C97.5193 77.3787 108.411 69.1249 118.614 60.0461C121.206 58.0608 123.949 56.2799 126.816 54.7192C141.424 44.4141 156.955 35.4831 173.208 28.0406C173.563 27.806 173.88 27.5174 174.146 27.1852C195.727 17.2495 218.449 10.0083 241.799 5.62482C245.993 5.22173 250.131 4.37247 254.144 3.09147C260.237 3.19224 266.096 0.958864 272.221 1.34789C273.52 0.372984 275.24 1.55412 276.529 0.520624L284.262 0.497193C294.858 -0.165731 305.486 -0.165731 316.083 0.497193C325.018 0.807342 333.926 1.66826 342.755 3.07506L367.696 7.43167L400.384 16.9112L430.503 29.7584C441.241 34.7618 451.125 41.3119 461.464 47.0114L485.561 64.2011L502.759 78.8528C509.357 86.0396 516.236 92.9335 523.398 99.5344C527.641 105.27 532.233 110.739 537.149 115.911C539.82 120.513 542.974 124.818 546.557 128.753C549.887 134.772 553.636 140.549 557.775 146.042C560.149 151.429 563.013 156.587 566.331 161.45L574.926 179.509L584.483 204.494L592.242 231.997C593.71 240.023 595.177 248.049 596.643 256.075C598.414 268.839 599.334 281.706 599.396 294.593C599.396 294.956 599.785 295.321 599.991 295.687C600.123 302.856 598.719 309.983 599.288 317.151C599.19 322.04 597.882 326.849 598.309 331.773L594.962 354.139L589.662 378.226L583.754 397.162C580.786 404.886 577.817 412.608 574.849 420.33L559.526 450.498L546.452 471.093C534.32 487.64 520.905 503.207 506.331 517.649C496.599 526.292 486.796 534.827 476.26 542.49C453.347 559.217 428.161 572.583 401.466 582.182C400.803 582.436 400.168 582.778 399.524 583.078C384.306 588.103 368.79 592.173 353.066 595.264C341.626 597.008 330.185 598.599 318.651 599.482C306.318 599.208 293.991 600.774 281.654 599.482L260.19 597.608L239.505 594.106L221.492 589.855L199.183 582.937L177.574 574.243L160.287 565.806C154.093 562.277 147.893 558.764 141.732 555.202C139.89 554.145 138.111 552.971 136.3 551.85L111.46 533.871L92.3263 516.763L74.2307 497.842L58.7174 478.899L46.7896 461.676C43.9046 456.352 40.7413 451.184 37.3129 446.193C35.3351 439.76 30.6764 434.583 28.6212 428.148Z" fill="url(#paint0_radial)"/>
<path d="M230.095 371.643C227.687 373.331 224.841 374.286 221.902 374.392C218.963 374.499 216.056 373.753 213.531 372.243C209.692 359.623 206.833 346.748 203.355 334.039C194.537 301.73 186.052 269.331 177.373 236.984C176.773 235.249 176.612 233.394 176.904 231.582C177.001 230.534 177.768 229.998 178.516 229.421C186.743 225.418 195.902 224.791 204.532 222.272C206.291 221.762 208.082 221.371 209.893 221.101C211.618 222.021 213.017 223.45 213.902 225.193C214.786 226.936 215.113 228.91 214.836 230.845C217.598 225.636 218.118 218.89 225.305 217.389C227.518 217.106 229.711 216.687 231.873 216.135C232.521 216.089 233.166 216.26 233.705 216.621C234.725 217.675 235.369 219.035 235.538 220.491C243.039 252.393 250.618 284.278 258.274 316.146C258.578 317.159 258.755 318.205 258.802 319.262C258.423 323.523 255.673 326.725 253.737 330.26C246.924 342.716 240.205 355.224 233.17 367.559C232.329 369.05 231.295 370.423 230.095 371.643Z" fill="#1FC8A7"/>
<path d="M423.55 368.329C422.922 369.682 421.856 370.785 420.525 371.46C414.229 374.394 407.356 375.264 400.701 376.837C373.196 383.33 345.71 389.914 318.194 396.361C304.692 399.522 291.225 402.817 277.701 405.89C276.328 406.383 274.84 406.458 273.425 406.106C271.48 404.688 272.874 403.275 273.537 401.981C278.708 391.882 284.412 382.071 289.881 372.134C299.474 354.684 308.974 337.178 318.713 319.817C320.53 316.576 321.439 312.594 325.16 310.652C328.868 311.581 332.384 313.155 335.546 315.304C352.778 324.711 370.041 334.056 387.264 343.488C398.698 349.753 410.349 355.622 421.48 362.428C422.446 364.287 423.143 366.274 423.55 368.329Z" fill="#1FC8A7"/>
@ -28,7 +28,7 @@
<stop stop-color="#3F5D65"/>
<stop offset="1" stop-color="#192123"/>
</radialGradient>
<clipPath id="clip0">
<clipPath id="clip0123">
<rect width="600" height="600" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

29
assets/icons/reflexer.svg Normal file
View File

@ -0,0 +1,29 @@
<svg viewBox="0 0 18 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M16.2422 1.73483e-05H13.2187L10.5612 12.5593L10.6137 12.5837C11.0051 12.7867 11.3525 13.0614 11.6369 13.3926C11.7077 13.4737 11.774 13.5588 11.8356 13.648C12.1202 14.0498 12.31 14.5079 12.3914 14.9895C12.4729 15.471 12.4439 15.9642 12.3066 16.4336C12.3066 16.447 12.3004 16.4616 12.2966 16.4737C12.2411 16.6553 12.1696 16.832 12.083 17.0016C12.073 17.0211 12.0642 17.0418 12.0542 17.0612C11.9685 17.2221 11.8695 17.3759 11.7581 17.521L11.7107 17.5843C11.5985 17.7233 11.4753 17.8534 11.3421 17.9735L11.2784 18.0307C11.1434 18.1473 10.9993 18.2534 10.8473 18.3482L10.7736 18.392C10.6177 18.4856 10.4543 18.567 10.2851 18.6353L10.2102 18.6632C10.0348 18.7283 9.85432 18.7792 9.67042 18.8153L9.60295 18.8262C9.47869 18.8438 9.35359 18.8551 9.22814 18.8603L7.27411 28.0891H12.4515L17.9625 2.04965C18.0156 1.80126 18.011 1.54448 17.949 1.29805C17.8871 1.05163 17.7693 0.821795 17.6044 0.625349C17.4396 0.428903 17.2317 0.270807 16.996 0.162616C16.7603 0.0544251 16.5027 -0.00112771 16.2422 1.73483e-05Z"
fill="currentColor" />
<path
d="M7.09295 18.3166C6.90879 18.1975 6.73683 18.0615 6.57946 17.9103C6.50116 17.8357 6.4262 17.757 6.35457 17.6743C6.21257 17.51 6.08706 17.3328 5.97976 17.1452C5.92645 17.0511 5.87772 16.9546 5.83358 16.8557C5.65397 16.4494 5.55967 16.0122 5.55622 15.5699C5.55065 15.2519 5.59274 14.9347 5.68115 14.6285C5.68115 14.6151 5.6874 14.6017 5.69115 14.5883C5.74668 14.4067 5.81816 14.2301 5.90479 14.0604C5.91479 14.0409 5.92353 14.0203 5.93353 14.002C6.01929 13.8416 6.11831 13.6882 6.22963 13.5434L6.27711 13.4802C6.38919 13.3408 6.51243 13.2102 6.64567 13.0897L6.70939 13.0325C6.8443 12.9159 6.98843 12.8097 7.14043 12.7151L7.21414 12.6713C7.37006 12.5776 7.53341 12.4963 7.70265 12.428L7.77886 12.4C7.95416 12.3349 8.13469 12.2841 8.31859 12.248L8.38606 12.237C8.51524 12.2182 8.64536 12.206 8.77587 12.2005L10.7461 2.91939H5.56996L0.0576997 28.9503C0.00467314 29.1986 0.00927131 29.4553 0.0711583 29.7017C0.133045 29.948 0.250659 30.1778 0.41541 30.3742C0.580162 30.5706 0.787892 30.7287 1.02343 30.837C1.25897 30.9453 1.51637 31.0009 1.77684 31H4.80034L7.44653 18.51C7.42529 18.499 7.4003 18.4942 7.37906 18.4832C7.27911 18.4321 7.18374 18.3766 7.09295 18.3166Z"
fill="currentColor" />
<path
d="M5.7886 14.6601C5.7886 14.6479 5.7886 14.6345 5.79859 14.6223C5.79485 14.6345 5.79235 14.6479 5.7886 14.6601Z"
fill="currentColor" />
<path
d="M6.00599 14.1103C6.01599 14.092 6.02473 14.0726 6.03473 14.0531C6.02348 14.0726 6.01474 14.092 6.00599 14.1103Z"
fill="currentColor" />
<path
d="M9.00075 18.7691H9.01325C8.9083 18.7691 8.80335 18.7691 8.69715 18.7581C8.80127 18.7654 8.90247 18.7691 9.00075 18.7691Z"
fill="currentColor" />
<path
d="M12.2029 16.4044C12.2029 16.4166 12.2029 16.4299 12.1929 16.4421C12.1979 16.4299 12.1992 16.4214 12.2029 16.4044Z"
fill="currentColor" />
<path
d="M8.99201 12.2954H8.97827C9.08321 12.2954 9.18816 12.2954 9.29436 12.3064C9.19274 12.2991 9.09196 12.2954 8.99201 12.2954Z"
fill="currentColor" />
<path
d="M11.988 16.9554C11.978 16.9737 11.9693 16.9931 11.9593 17.0126C11.9693 16.9931 11.9768 16.9737 11.988 16.9554Z"
fill="currentColor" />
<path
d="M15.9061 9.92828C15.1497 9.04376 14.2207 8.31391 13.173 7.78089C12.1252 7.24787 10.9794 6.92224 9.80161 6.82281C9.53299 6.7997 9.26062 6.78754 8.99201 6.78754C6.67763 6.78498 4.45155 7.65231 2.77795 9.20869C1.10436 10.7651 0.112422 12.8904 0.00898338 15.1414C-0.0944557 17.3924 0.698585 19.5955 2.22275 21.2911C3.74691 22.9868 5.88453 24.0442 8.18991 24.2429C8.45852 24.266 8.73089 24.2782 8.9995 24.2782C10.7097 24.2823 12.3856 23.8108 13.8299 22.9191C15.2742 22.0274 16.4269 20.7527 17.1523 19.2448C17.8777 17.7369 18.1457 16.0587 17.9247 14.4076C17.7037 12.7565 17.0029 11.2011 15.9048 9.92463L15.9061 9.92828ZM12.3154 15.823C12.2965 16.0197 12.2593 16.2143 12.2042 16.4044C12.2042 16.4178 12.2042 16.4312 12.1942 16.4433C12.1406 16.6191 12.0716 16.79 11.988 16.9542C11.978 16.9737 11.9705 16.9931 11.9605 17.0114C11.8773 17.1671 11.7812 17.316 11.6732 17.4566L11.6269 17.5174C11.5183 17.6525 11.3988 17.779 11.2696 17.8957L11.2084 17.9504C11.0774 18.0635 10.9374 18.1664 10.7899 18.2582L10.7186 18.3008C10.5678 18.3899 10.4099 18.4672 10.2464 18.5319L10.1727 18.5586C10.0026 18.6216 9.82752 18.6708 9.64918 18.7058L9.58421 18.7156C9.3958 18.749 9.20476 18.7665 9.01325 18.7679H9.00075C8.9008 18.7679 8.80002 18.7634 8.6984 18.7545C8.47362 18.7358 8.25135 18.695 8.03498 18.6329C7.82524 18.5715 7.62227 18.49 7.42903 18.3896C7.33325 18.3401 7.24079 18.2866 7.15167 18.229C6.97249 18.114 6.80513 17.9824 6.65192 17.8361C6.57613 17.7631 6.50408 17.6869 6.43578 17.6074C6.29892 17.4483 6.17802 17.2768 6.07471 17.0953C6.02307 17.0045 5.97601 16.9108 5.93353 16.8143C5.75893 16.4225 5.66633 16.0007 5.66116 15.5736C5.65702 15.2652 5.69911 14.9579 5.7861 14.6613C5.7861 14.6479 5.7861 14.6345 5.7961 14.6224C5.85039 14.4461 5.92019 14.2748 6.00474 14.1103C6.01474 14.0908 6.02223 14.0713 6.03223 14.0531C6.11537 13.8973 6.21148 13.7484 6.31959 13.6079L6.36581 13.5471C6.47444 13.412 6.59392 13.2855 6.72314 13.1688L6.78436 13.114C6.91537 13.0009 7.05531 12.898 7.2029 12.8063L7.27411 12.7637C7.42501 12.6746 7.58293 12.5974 7.74638 12.5326L7.82009 12.5058C7.99013 12.4428 8.16522 12.3936 8.34358 12.3587L8.40855 12.3477C8.59697 12.3143 8.788 12.2968 8.97951 12.2954L8.99201 12.2954C9.09196 12.2954 9.19274 12.2999 9.29436 12.3088C9.40753 12.3187 9.52012 12.3341 9.63169 12.355C9.84947 12.3959 10.0625 12.4578 10.2676 12.5399C10.3684 12.5804 10.4667 12.6255 10.5625 12.6749C10.9415 12.8715 11.2779 13.1375 11.5532 13.4583C11.6215 13.5394 11.6861 13.6205 11.7469 13.7016C12.1842 14.3209 12.3853 15.0696 12.3154 15.8181V15.823Z"
fill="currentColor" />
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,5 +1,5 @@
<svg viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<g clip-path="url(#clip0123)">
<path d="M28.6212 428.148L21.8137 413.517C19.2469 406.633 16.6833 399.75 14.1227 392.866C11.8043 383.976 9.48508 375.088 7.16513 366.201C5.90907 358.137 3.15326 350.343 2.84393 342.108C2.01281 336.083 1.18402 330.057 0.357582 324.03C0.340397 321.163 0.322479 318.297 0.303732 315.431C0.512293 302.816 -0.507069 290.196 0.345925 277.581C1.81054 273.096 1.30196 268.373 2.0331 263.792C2.99857 257.79 3.77195 251.758 4.62729 245.733C7.15815 234.819 9.10083 223.769 12.3863 213.036L21.0006 188.098C24.2813 182.272 26.4771 175.952 29.2844 169.915C31.5599 165.017 34.0766 160.232 36.4903 155.385C42.1145 146.381 47.6144 137.284 53.4542 128.416C56.7813 122.993 60.6083 117.893 64.8852 113.183C72.3723 104.364 80.3516 95.9933 88.1809 87.5027C97.5193 77.3787 108.411 69.1249 118.614 60.0461C121.206 58.0608 123.949 56.2799 126.816 54.7192C141.424 44.4141 156.955 35.4831 173.208 28.0406C173.563 27.806 173.88 27.5174 174.146 27.1852C195.727 17.2495 218.449 10.0083 241.799 5.62482C245.993 5.22173 250.131 4.37247 254.144 3.09147C260.237 3.19224 266.096 0.958864 272.221 1.34789C273.52 0.372984 275.24 1.55412 276.529 0.520624L284.262 0.497193C294.858 -0.165731 305.486 -0.165731 316.083 0.497193C325.018 0.807342 333.926 1.66826 342.755 3.07506L367.696 7.43167L400.384 16.9112L430.503 29.7584C441.241 34.7618 451.125 41.3119 461.464 47.0114L485.561 64.2011L502.759 78.8528C509.357 86.0396 516.236 92.9335 523.398 99.5344C527.641 105.27 532.233 110.739 537.149 115.911C539.82 120.513 542.974 124.818 546.557 128.753C549.887 134.772 553.636 140.549 557.775 146.042C560.149 151.429 563.013 156.587 566.331 161.45L574.926 179.509L584.483 204.494L592.242 231.997C593.71 240.023 595.177 248.049 596.643 256.075C598.414 268.839 599.334 281.706 599.396 294.593C599.396 294.956 599.785 295.321 599.991 295.687C600.123 302.856 598.719 309.983 599.288 317.151C599.19 322.04 597.882 326.849 598.309 331.773L594.962 354.139L589.662 378.226L583.754 397.162C580.786 404.886 577.817 412.608 574.849 420.33L559.526 450.498L546.452 471.093C534.32 487.64 520.905 503.207 506.331 517.649C496.599 526.292 486.796 534.827 476.26 542.49C453.347 559.217 428.161 572.583 401.466 582.182C400.803 582.436 400.168 582.778 399.524 583.078C384.306 588.103 368.79 592.173 353.066 595.264C341.626 597.008 330.185 598.599 318.651 599.482C306.318 599.208 293.991 600.774 281.654 599.482L260.19 597.608L239.505 594.106L221.492 589.855L199.183 582.937L177.574 574.243L160.287 565.806C154.093 562.277 147.893 558.764 141.732 555.202C139.89 554.145 138.111 552.971 136.3 551.85L111.46 533.871L92.3263 516.763L74.2307 497.842L58.7174 478.899L46.7896 461.676C43.9046 456.352 40.7413 451.184 37.3129 446.193C35.3351 439.76 30.6764 434.583 28.6212 428.148Z" fill="url(#paint0_radial)"/>
<path d="M230.095 371.643C227.687 373.331 224.841 374.286 221.902 374.392C218.963 374.499 216.056 373.753 213.531 372.243C209.692 359.623 206.833 346.748 203.355 334.039C194.537 301.73 186.052 269.331 177.373 236.984C176.773 235.249 176.612 233.394 176.904 231.582C177.001 230.534 177.768 229.998 178.516 229.421C186.743 225.418 195.902 224.791 204.532 222.272C206.291 221.762 208.082 221.371 209.893 221.101C211.618 222.021 213.017 223.45 213.902 225.193C214.786 226.936 215.113 228.91 214.836 230.845C217.598 225.636 218.118 218.89 225.305 217.389C227.518 217.106 229.711 216.687 231.873 216.135C232.521 216.089 233.166 216.26 233.705 216.621C234.725 217.675 235.369 219.035 235.538 220.491C243.039 252.393 250.618 284.278 258.274 316.146C258.578 317.159 258.755 318.205 258.802 319.262C258.423 323.523 255.673 326.725 253.737 330.26C246.924 342.716 240.205 355.224 233.17 367.559C232.329 369.05 231.295 370.423 230.095 371.643Z" fill="#1FC8A7"/>
<path d="M423.55 368.329C422.922 369.682 421.856 370.785 420.525 371.46C414.229 374.394 407.356 375.264 400.701 376.837C373.196 383.33 345.71 389.914 318.194 396.361C304.692 399.522 291.225 402.817 277.701 405.89C276.328 406.383 274.84 406.458 273.425 406.106C271.48 404.688 272.874 403.275 273.537 401.981C278.708 391.882 284.412 382.071 289.881 372.134C299.474 354.684 308.974 337.178 318.713 319.817C320.53 316.576 321.439 312.594 325.16 310.652C328.868 311.581 332.384 313.155 335.546 315.304C352.778 324.711 370.041 334.056 387.264 343.488C398.698 349.753 410.349 355.622 421.48 362.428C422.446 364.287 423.143 366.274 423.55 368.329Z" fill="#1FC8A7"/>
@ -28,7 +28,7 @@
<stop stop-color="#3F5D65"/>
<stop offset="1" stop-color="#192123"/>
</radialGradient>
<clipPath id="clip0">
<clipPath id="clip0123">
<rect width="600" height="600" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,66 @@
<template>
<div
class="flex-shrink-0 bg-white rounded-lg relative flex flex-col flex-1 px-4 pt-4 pb-6 dark:bg-dark-500"
style="box-shadow: -1px -3px 10px rgba(12, 25, 91, 0.03), 2px 4px 12px rgba(12, 25, 91, 0.05)"
>
<div class="flex items-center">
<IconCurrency :currency="tokenKey" class="w-12 h-12" no-height />
<div class="flex flex-col flex-grow mx-4">
<div class="mb-1 font-medium leading-none whitespace-no-wrap text-19">{{ formatUsd(amountUsd) }}</div>
<div class="flex leading-none whitespace-no-wrap">
<span class="text-grey-pure text-14">{{ formatDecimal(amount) }} {{ symbol }}</span>
<Info :text="`${formatUsd(priceInUsd, 2)}/${symbol}`" icon="price" class="ml-1" />
</div>
</div>
<div class="self-start">
<Badge :color="positionType === 'supply' ? 'green' : 'yellow'" class="w-16">{{ badge }}</Badge>
</div>
</div>
<hr class="mt-4" />
<div class="flex items-center justify-around px-4 mt-6">
<button class="mr-4 h-10 w-full bg-primary-blue-dark shadow text-white rounded-[4px] hover:bg-primary-blue-hover" @click="supplyOrBorrow">{{ buttonOne }}</button>
<button class="h-10 w-full text-primary-blue-dark shadow border border-primary-blue-dark hover:border-primary-blue-hover rounded-[4px] hover:text-primary-blue-hover" color="ocean-blue" @click="withdrawOrPayback">{{ buttonTwo }}</button>
</div>
</div>
</template>
<script>
import { computed, defineComponent } from '@nuxtjs/composition-api'
import { useFormatting } from '@/composables/useFormatting'
import { useToken } from '~/composables/useToken'
export default defineComponent({
props: {
amount: { type: String, default: '0' },
amountUsd: { type: String, default: '0' },
positionType: { type: String, default: 'supply' },
tokenKey: { type: String, required: true },
safeTokenType: { type: String, default: 'token' },
supplyOrBorrow: { type: Function, required: true },
withdrawOrPayback: { type: Function, required: true },
priceInUsd: { type: String, default: '0' },
},
setup(props) {
const { formatUsd, formatDecimal } = useFormatting()
const { getTokenByKey } = useToken()
const symbol = computed(() => getTokenByKey(props.tokenKey)?.symbol || props.tokenKey)
const buttonOne = computed(() => (props.positionType === 'supply' ? 'Supply' : 'Borrow'))
const buttonTwo = computed(() => (props.positionType === 'supply' ? 'Withdraw' : 'Payback'))
const badge = computed(() => (props.positionType === 'supply' ? 'Collateral' : 'Debt'))
return {
formatUsd,
formatDecimal,
buttonOne,
buttonTwo,
badge,
symbol,
}
},
})
</script>

View File

@ -0,0 +1,104 @@
<template>
<dropdown>
<template #trigger="{ toggle, isShown }">
<Button
:class="{
'bg-grey-light': isShown
}"
:large="true"
color="grey"
class="w-20 px-3 xxl:w-23"
aria-label="Reflexer Dropdown"
aria-haspopup="true"
@click="toggle()"
>
<span class="mr-2">#{{ safeId }}</span>
<SVGChevronUp
class="ml-auto"
:class="{ 'transform rotate-180': !isShown }"
/>
</Button>
</template>
<template #menu="{ close }">
<dropdown-menu style="width: 240px; max-height: 440px">
<div
class="flex flex-col overflow-x-hidden overflow-y-auto scrollbar-hover scrollbar"
>
<button
v-for="safe in safes"
:key="safe.id"
class="flex items-center w-full px-4 py-2 hover:bg-opacity-50 focus:bg-opacity-50 hover:bg-grey-light dark:hover:bg-dark-300 dark:focus:bg-dark-300 focus:outline-none focus:bg-grey-light"
@click="setSafe(safe.id, close)"
>
<div class="mr-2 font-semibold whitespace-no-wrap">
#{{ safe.id }}
</div>
<IconCurrency
:currency="safe.tokenKey"
class="w-6 h-6 ml-auto"
no-height
/>
</button>
</div>
<hr v-if="!!safes.length" class="w-full my-2" />
<button
class="flex items-center w-full px-4 py-2 font-medium hover:bg-opacity-75 focus:bg-opacity-75 text-ocean-blue-pure hover:bg-ocean-blue-light focus:bg-ocean-blue-light focus:outline-none dark:hover:bg-opacity-17 dark:focus:bg-opacity-17"
@click="openNewSafe(close)"
>
New Safe
</button>
</dropdown-menu>
</template>
</dropdown>
</template>
<script>
import { defineComponent, useRouter } from '@nuxtjs/composition-api'
import SVGChevronUp from '@/assets/img/icons/chevron-up.svg?inline'
import { useReflexerPosition } from '~/composables/protocols/useReflexerPosition'
import { useSidebar } from '~/composables/useSidebar'
import Dropdown from '../../common/input/Dropdown.vue'
import DropdownMenu from '../DropdownMenu.vue'
export default defineComponent({
components: {
SVGChevronUp,
Dropdown,
DropdownMenu,
},
setup() {
const router = useRouter()
const { safeId, safes, selectSafe, isNewSafe, safeType, safeTypes } = useReflexerPosition()
const { back } = useSidebar()
function openNewSafe(cb) {
if (safeTypes.value.length === 1) {
safeType.value = safeTypes.value[0].type;
isNewSafe.value = true;
router.push({ hash: "supply" });
} else {
router.push({ hash: "collateral" });
}
cb();
}
function setSafe(safeId, cb) {
selectSafe(safeId)
if (isNewSafe.value) {
back()
}
cb()
}
return { safeId, safes, openNewSafe, setSafe }
},
})
</script>

View File

@ -104,7 +104,7 @@ export default defineComponent({
const amount = ref('')
const amountParsed = computed(() => parseSafeFloat(amount.value))
const { tokenKey, token, debt, collateral, liquidation, liquidationMaxPrice, isNewVault, vaultId, vaultType, fetchPosition} = useMakerdaoPosition()
const { tokenKey, token, debt, collateral, liquidation, liquidationMaxPrice, isNewVault, vaultId, vaultType, fetchPosition } = useMakerdaoPosition()
const symbol = computed(() => token.value?.symbol)
const decimals = computed(() => token.value?.decimals)
@ -163,6 +163,8 @@ export default defineComponent({
from: account.value,
onReceipt: async receipt => {
showConfirmedTransaction(receipt.transactionHash);
isNewVault.value = false;
await fetchBalances(true);
await fetchPosition();

View File

@ -0,0 +1,196 @@
<template>
<SidebarContextRootContainer>
<template #title>Borrow {{ symbol }}</template>
<SidebarSectionValueWithIcon class="mt-6" label="Borrowed" center>
<template #icon
><IconCurrency :currency="raiTokenKey" class="w-20 h-20" noHeight
/></template>
<template #value>{{ formatNumber(debt) }} {{ symbol }}</template>
</SidebarSectionValueWithIcon>
<div class="bg-[#C5CCE1] bg-opacity-[0.15] mt-10 p-8">
<h3 class="text-primary-gray text-xs font-semibold mb-2.5">
Amount to borrow
</h3>
<input-numeric
v-model="amount"
placeholder="Amount to borrow"
:error="errors.amount.message"
>
</input-numeric>
<SidebarContextHeading class="mt-5">
Projected Debt Position
</SidebarContextHeading>
<SidebarSectionStatus
class="mt-8"
:liquidation="liquidation"
:status="status"
/>
<SidebarSectionValueWithIcon
class="mt-8"
:label="`Liquidation Price (${tokenSymbol})`"
>
<template #value>
{{ formatUsdMax(liquidationPrice, liquidationMaxPrice) }}
<span class="text-primary-gray"
>/ {{ formatUsd(liquidationMaxPrice) }}</span
>
</template>
</SidebarSectionValueWithIcon>
<div class="flex flex-shrink-0 mt-10">
<ButtonCTA
class="w-full"
:disabled="!isValid || pending"
:loading="pending"
@click="cast"
>
Borrow
</ButtonCTA>
</div>
<ValidationErrors :error-messages="errorMessages" class="mt-6" />
</div>
</SidebarContextRootContainer>
</template>
<script>
import { computed, defineComponent, ref } from '@nuxtjs/composition-api'
import InputNumeric from '~/components/common/input/InputNumeric.vue'
import { useBigNumber } from '~/composables/useBigNumber'
import { useFormatting } from '~/composables/useFormatting'
import { useValidators } from '~/composables/useValidators'
import { useValidation } from '~/composables/useValidation'
import { useToken } from '~/composables/useToken'
import { useParsing } from '~/composables/useParsing'
import { useMaxAmountActive } from '~/composables/useMaxAmountActive'
import { useWeb3 } from '@instadapp/vue-web3'
import ToggleButton from '~/components/common/input/ToggleButton.vue'
import { useDSA } from '~/composables/useDSA'
import ButtonCTA from '~/components/common/input/ButtonCTA.vue'
import { useNotification } from '~/composables/useNotification'
import Button from '~/components/Button.vue'
import { useSidebar } from '~/composables/useSidebar'
import ctokens from '~/constant/ctokens'
import { useReflexerPosition } from '~/composables/protocols/useReflexerPosition'
import { useBalances } from '~/composables/useBalances'
export default defineComponent({
components: { InputNumeric, ToggleButton, ButtonCTA, Button },
props: {
tokenKey: { type: String, required: true },
},
setup(props) {
const { close } = useSidebar()
const { account } = useWeb3()
const { dsa } = useDSA()
const { getTokenByKey, valInt } = useToken()
const { fetchBalances } = useBalances()
const { formatNumber, formatUsdMax, formatUsd } = useFormatting()
const { isZero, gt, div, plus } = useBigNumber()
const { parseSafeFloat } = useParsing()
const { showPendingTransaction, showConfirmedTransaction , showWarning } = useNotification()
const amount = ref('')
const amountParsed = computed(() => parseSafeFloat(amount.value))
const { debt, collateral, liquidation, liquidationMaxPrice, safe, safeId, symbol: tokenSymbol, fetchPosition } = useReflexerPosition({
overridePosition: (position) => {
return position;
},
})
const changedDebt = computed(() => plus(debt.value, amountParsed.value).toFixed())
const { liquidationPrice, status } = useReflexerPosition(collateral, changedDebt)
const raiTokenKey = ref('rai')
const raiToken = computed(() => getTokenByKey(raiTokenKey.value))
const symbol = computed(() => raiToken.value?.symbol)
const decimals = computed(() => raiToken.value?.decimals)
const {
validateAmount,
validateLiquidation,
validateIsLoggedIn,
validateReflexerDebt,
validateReflexerDebtCeiling,
} = useValidators()
const errors = computed(() => {
const hasAmountValue = !isZero(amount.value)
return {
amount: { message: validateAmount(amountParsed.value), show: hasAmountValue },
liquidation: { message: validateLiquidation(status.value, liquidation.value), show: hasAmountValue },
auth: { message: validateIsLoggedIn(!!account.value), show: true },
minDebt: { message: validateReflexerDebt(changedDebt.value), show: hasAmountValue },
debtCeiling: { message: validateReflexerDebtCeiling(safe.value.type, amountParsed.value), show: true },
}
})
const { errorMessages, isValid } = useValidation(errors)
const pending = ref(false)
async function cast() {
pending.value = true
const amount = valInt(amountParsed.value, decimals.value)
const spells = dsa.value.Spell()
spells.add({
connector: 'REFLEXER-A',
method: 'borrow',
args: [safeId.value, amount, 0, 0],
})
try {
const txHash = await dsa.value.cast({
spells,
from: account.value,
onReceipt: async receipt => {
showConfirmedTransaction(receipt.transactionHash);
await fetchBalances(true);
await fetchPosition();
}
})
showPendingTransaction(txHash)
} catch (error) {
showWarning(error.message)
}
pending.value = false
close()
}
return {
raiTokenKey,
symbol,
debt,
amount,
status,
liquidation,
liquidationPrice,
liquidationMaxPrice,
formatUsd,
formatUsdMax,
formatNumber,
errors,
errorMessages,
isValid,
cast,
pending,
tokenSymbol,
}
},
})
</script>

View File

@ -0,0 +1,83 @@
<template>
<SidebarContextRootContainer>
<template #title>Select Collateral</template>
<div>
<div class="px-8 pb-6 -mt-4">
<SearchInput
v-model.trim="search"
class="mt-1"
placeholder="Search Collateral"
/>
</div>
<div class="bg-[#C5CCE1] bg-opacity-[0.15] px-8 py-6 min-h-screen">
<div
v-for="(safeType, index) in filteredSafes"
:key="index"
class="flex items-center justify-between px-4 py-4 mt-4 cursor-pointer first:mt-0 group bg-white rounded-lg border border-grey-dark/[0.15] hover:bg-selection"
@click="select(safeType.type)"
>
<div class="flex flex-col mr-4">
<div class="mb-1 font-semibold whitespace-no-wrap text-12">
{{ safeType.type }}
</div>
<div
class="mb-1 font-medium whitespace-no-wrap text-12 text-grey-pure"
>
Stability Fee: {{ formatPercent(safeType.rate) }}
</div>
<div
class="mb-1 font-medium whitespace-no-wrap text-12 text-grey-pure"
>
Liquidation: {{ formatPercent(safeType.liquidation) }}
</div>
</div>
<IconCurrency :currency="safeType.tokenKey" />
</div>
</div>
</div>
</SidebarContextRootContainer>
</template>
<script>
import { defineComponent, useContext, computed } from '@nuxtjs/composition-api'
import { useFormatting } from '~/composables/useFormatting'
import { useReflexerPosition } from '~/composables/protocols/useReflexerPosition'
import { useSearchFilter } from '~/composables/useSearchFilter'
import { useSidebar } from '~/composables/useSidebar'
export default defineComponent({
props: {
safeType: { type: String, default: null },
},
setup(props) {
const { store, app, route } = useContext()
const { formatPercent } = useFormatting()
const { back } = useSidebar()
const { safeTypes: reflexerSafeTypes, safeType, isNewSafe } = useReflexerPosition()
const safeTypes = computed(() => {
const shouldFilter = !!props.safeType && (props.safeType === 'token' || props.safeType === 'uniLPT')
const filtered = reflexerSafeTypes.value.filter((safe) => !safe.disabled)
const final = shouldFilter ? filtered.filter((safe) => safe.safeTokenType === props.safeType) : filtered
if (route.value.hash.startsWith('#collateral')) return final
return filtered.filter((safe) => safe.safeTokenType === 'token')
})
const { filtered: filteredSafes, search } = useSearchFilter(safeTypes, 'type', 'token')
function select(vt, tokenKey) {
safeType.value = vt;
isNewSafe.value = true
app.router.push({ hash: 'supply' })
}
return {
filteredSafes,
search,
formatPercent,
select,
}
},
})
</script>

View File

@ -0,0 +1,220 @@
<template>
<SidebarContextRootContainer>
<template #title>Payback {{ symbol }}</template>
<div class="mt-6 flex justify-around items-center w-full">
<SidebarSectionValueWithIcon class="" label="Borrowed" center>
<template #icon
><IconCurrency :currency="raiTokenKey" class="w-20 h-20" noHeight
/></template>
<template #value>{{ formatNumber(debt) }} {{ symbol }}</template>
</SidebarSectionValueWithIcon>
<SidebarSectionValueWithIcon class="" label="Token Balance" center>
<template #icon
><IconCurrency :currency="raiTokenKey" class="w-20 h-20" noHeight
/></template>
<template #value>{{ formatNumber(balance) }} {{ symbol }}</template>
</SidebarSectionValueWithIcon>
</div>
<div class="bg-[#C5CCE1] bg-opacity-[0.15] mt-10 p-8">
<h3 class="text-primary-gray text-xs font-semibold mb-2.5">
Amount to supply
</h3>
<input-numeric
v-model="amount"
placeholder="Amount to supply"
:error="errors.amount.message"
>
<template v-if="!isMaxAmount" #suffix>
<div class="absolute mt-2 top-0 right-0 mr-4">
<button
type="button"
class="text-primary-blue-dark font-semibold text-sm hover:text-primary-blue-hover"
@click="toggle"
>
Max
</button>
</div>
</template>
</input-numeric>
<SidebarContextHeading class="mt-5">
Projected Debt Position
</SidebarContextHeading>
<SidebarSectionStatus
class="mt-8"
:liquidation="liquidation"
:status="status"
/>
<SidebarSectionValueWithIcon
class="mt-8"
:label="`Liquidation Price (${tokenSymbol})`"
>
<template #value>
{{ formatUsdMax(liquidationPrice, liquidationMaxPrice) }}
<span class="text-primary-gray"
>/ {{ formatUsd(liquidationMaxPrice) }}</span
>
</template>
</SidebarSectionValueWithIcon>
<div class="flex flex-shrink-0 mt-10">
<ButtonCTA
class="w-full"
:disabled="!isValid || pending"
:loading="pending"
@click="cast"
>
Payback
</ButtonCTA>
</div>
<ValidationErrors :error-messages="errorMessages" class="mt-6" />
</div>
</SidebarContextRootContainer>
</template>
<script>
import { computed, defineComponent, ref } from '@nuxtjs/composition-api'
import InputNumeric from '~/components/common/input/InputNumeric.vue'
import { useBalances } from '~/composables/useBalances'
import { useBigNumber } from '~/composables/useBigNumber'
import { useFormatting } from '~/composables/useFormatting'
import { useValidators } from '~/composables/useValidators'
import { useValidation } from '~/composables/useValidation'
import { useToken } from '~/composables/useToken'
import { useParsing } from '~/composables/useParsing'
import { useMaxAmountActive } from '~/composables/useMaxAmountActive'
import { useWeb3 } from '@instadapp/vue-web3'
import ToggleButton from '~/components/common/input/ToggleButton.vue'
import { useDSA } from '~/composables/useDSA'
import ButtonCTA from '~/components/common/input/ButtonCTA.vue'
import { useNotification } from '~/composables/useNotification'
import Button from '~/components/Button.vue'
import { useSidebar } from '~/composables/useSidebar'
import { useReflexerPosition } from '~/composables/protocols/useReflexerPosition'
export default defineComponent({
components: { InputNumeric, ToggleButton, ButtonCTA, Button },
props: {
tokenKey: { type: String, required: true },
},
setup(props) {
const { close } = useSidebar()
const { account } = useWeb3()
const { dsa } = useDSA()
const { getTokenByKey, valInt } = useToken()
const { getBalanceByKey, getBalanceRawByKey, fetchBalances } = useBalances()
const { formatNumber, formatUsdMax, formatUsd } = useFormatting()
const { isZero, gte, plus, max, minus, min } = useBigNumber()
const { parseSafeFloat } = useParsing()
const { showPendingTransaction, showConfirmedTransaction, showWarning } = useNotification()
const { debt, collateral, liquidation, liquidationMaxPrice, safeId, symbol: tokenSymbol, fetchPosition, minDebt } = useReflexerPosition()
const amount = ref('')
const amountParsed = computed(() => parseSafeFloat(amount.value))
const raiTokenKey = ref('rai')
const tokenKey = computed(() => props.tokenKey)
const token = computed(() => getTokenByKey(tokenKey.value))
const symbol = computed(() => token.value?.symbol)
const decimals = computed(() => token.value?.decimals)
const balance = computed(() => getBalanceByKey(tokenKey.value))
const balanceRaw = computed(() => getBalanceRawByKey(tokenKey.value))
const changedDebt = computed(() => max(minus(debt.value, amountParsed.value), '0').toFixed())
const { liquidationPrice, status } = useReflexerPosition(collateral, changedDebt)
const maxBalance = computed(() => min(balance.value, debt.value).toFixed(6))
const { toggle, isMaxAmount } = useMaxAmountActive(amount, maxBalance)
const { validateAmount, validateLiquidation, validateIsLoggedIn, validateReflexerPaybackDebt } = useValidators()
const errors = computed(() => {
const hasAmountValue = !isZero(amount.value)
return {
amount: { message: validateAmount(amountParsed.value, maxBalance.value), show: hasAmountValue },
liquidation: { message: validateLiquidation(status.value, liquidation.value), show: hasAmountValue },
auth: { message: validateIsLoggedIn(!!account.value), show: true },
minDebt: { message: validateReflexerPaybackDebt(changedDebt.value), show: hasAmountValue },
}
})
const { errorMessages, isValid } = useValidation(errors)
const pending = ref(false)
async function cast() {
pending.value = true
const amount = isMaxAmount.value
? gte(balance.value, debt.value)
? dsa.value.maxValue
: balanceRaw.value
: valInt(amountParsed.value, decimals.value)
const spells = dsa.value.Spell()
spells.add({
connector: 'REFLEXER-A',
method: 'payback',
args: [safeId.value, amount, 0, 0],
})
try {
const txHash = await dsa.value.cast({
spells,
from: account.value,
onReceipt: async receipt => {
showConfirmedTransaction(receipt.transactionHash);
await fetchBalances(true);
await fetchPosition();
}
})
showPendingTransaction(txHash)
} catch (error) {
console.log(error);
showWarning(error.message)
}
pending.value = false
close()
}
return {
raiTokenKey,
symbol,
debt,
balance,
amount,
status,
liquidation,
liquidationPrice,
liquidationMaxPrice,
formatUsd,
formatUsdMax,
formatNumber,
errors,
errorMessages,
isMaxAmount,
isValid,
cast,
pending,
toggle,
tokenSymbol,
minDebt,
}
},
})
</script>

View File

@ -0,0 +1,204 @@
<template>
<SidebarContextRootContainer>
<template #title>Supply {{ symbol }}</template>
<SidebarSectionValueWithIcon label="Token Balance" center>
<template #icon
><IconCurrency :currency="tokenKey" class="w-20 h-20" noHeight
/></template>
<template #value>{{ formatDecimal(balance) }} {{ symbol }}</template>
</SidebarSectionValueWithIcon>
<div class="bg-[#C5CCE1] bg-opacity-[0.15] mt-10 p-8">
<h3 class="text-primary-gray text-xs font-semibold mb-2.5">
Amount to supply
</h3>
<input-numeric
v-model="amount"
placeholder="Amount to supply"
:error="errors.amount.message"
>
<template v-if="!isMaxAmount" #suffix>
<div class="absolute mt-2 top-0 right-0 mr-4">
<button
type="button"
class="text-primary-blue-dark font-semibold text-sm hover:text-primary-blue-hover"
@click="toggle"
>
Max
</button>
</div>
</template>
</input-numeric>
<SidebarContextHeading class="mt-5">
Projected Debt Position
</SidebarContextHeading>
<SidebarSectionStatus
class="mt-8"
:liquidation="liquidation"
:status="status"
/>
<SidebarSectionValueWithIcon class="mt-8" label="Liquidation Price (ETH)">
<template #value>
{{ formatUsdMax(liquidationPrice, liquidationMaxPrice) }}
<span class="text-primary-gray"
>/ {{ formatUsd(liquidationMaxPrice) }}</span
>
</template>
</SidebarSectionValueWithIcon>
<div class="flex flex-shrink-0 mt-10">
<ButtonCTA
class="w-full"
:disabled="!isValid || pending"
:loading="pending"
@click="cast"
>
Supply
</ButtonCTA>
</div>
<ValidationErrors :error-messages="errorMessages" class="mt-6" />
</div>
</SidebarContextRootContainer>
</template>
<script>
import { computed, defineComponent, ref } from '@nuxtjs/composition-api'
import InputNumeric from '~/components/common/input/InputNumeric.vue'
import { useBalances } from '~/composables/useBalances'
import { useNotification } from '~/composables/useNotification'
import { useBigNumber } from '~/composables/useBigNumber'
import { useFormatting } from '~/composables/useFormatting'
import { useValidators } from '~/composables/useValidators'
import { useValidation } from '~/composables/useValidation'
import { useToken } from '~/composables/useToken'
import { useParsing } from '~/composables/useParsing'
import { useMaxAmountActive } from '~/composables/useMaxAmountActive'
import { useWeb3 } from '@instadapp/vue-web3'
import ToggleButton from '~/components/common/input/ToggleButton.vue'
import { useDSA } from '~/composables/useDSA'
import ButtonCTA from '~/components/common/input/ButtonCTA.vue'
import Button from '~/components/Button.vue'
import { useSidebar } from '~/composables/useSidebar'
import { useReflexerPosition } from '~/composables/protocols/useReflexerPosition'
export default defineComponent({
components: { InputNumeric, ToggleButton, ButtonCTA, Button },
setup(props) {
const { close } = useSidebar()
const { account } = useWeb3()
const { dsa } = useDSA()
const { valInt } = useToken()
const { getBalanceByKey, fetchBalances } = useBalances()
const { formatUsdMax, formatUsd, formatDecimal } = useFormatting()
const { plus, isZero } = useBigNumber()
const { parseSafeFloat } = useParsing()
const { showPendingTransaction, showConfirmedTransaction, showWarning } = useNotification()
const amount = ref('')
const amountParsed = computed(() => parseSafeFloat(amount.value))
const { tokenKey, token, debt, collateral, liquidation, liquidationMaxPrice, isNewSafe, safeId, safeType, fetchPosition } = useReflexerPosition()
const symbol = computed(() => token.value?.symbol)
const decimals = computed(() => token.value?.decimals)
const balance = computed(() => getBalanceByKey(tokenKey.value))
const changedCollateral = computed(() => plus(collateral.value, amountParsed.value).toFixed())
const { liquidationPrice, status } = useReflexerPosition(changedCollateral, debt)
const { toggle, isMaxAmount } = useMaxAmountActive(amount, balance)
const { validateAmount, validateLiquidation, validateIsLoggedIn } = useValidators()
const errors = computed(() => {
const hasAmountValue = !isZero(amount.value)
return {
amount: { message: validateAmount(amountParsed.value, balance.value), show: hasAmountValue },
liquidation: { message: validateLiquidation(status.value, liquidation.value), show: hasAmountValue },
auth: { message: validateIsLoggedIn(!!account.value), show: true },
}
})
const { errorMessages, isValid } = useValidation(errors)
const pending = ref(false)
async function cast() {
pending.value = true
const amount = isMaxAmount.value ? dsa.value.maxValue : valInt(amountParsed.value, decimals.value)
const spells = dsa.value.Spell()
if (isNewSafe.value) {
spells.add({
connector: 'REFLEXER-A',
method: 'open',
args: [safeType.value],
})
spells.add({
connector: 'REFLEXER-A',
method: 'deposit',
args: [0, amount, 0, 0],
})
} else {
spells.add({
connector: 'REFLEXER-A',
method: 'deposit',
args: [safeId.value, amount, 0, 0],
})
}
try {
const txHash = await dsa.value.cast({
spells,
from: account.value,
onReceipt: async receipt => {
showConfirmedTransaction(receipt.transactionHash);
isNewSafe.value = false
await fetchBalances(true);
await fetchPosition();
}
})
showPendingTransaction(txHash)
} catch (error) {
showWarning(error.message)
}
pending.value = false
close()
}
return {
tokenKey,
symbol,
balance,
amount,
status,
liquidation,
liquidationPrice,
liquidationMaxPrice,
formatUsd,
formatUsdMax,
formatDecimal,
errors,
errorMessages,
isMaxAmount,
isValid,
cast,
pending,
toggle,
}
},
})
</script>

View File

@ -0,0 +1,192 @@
<template>
<SidebarContextRootContainer>
<template #title>Withdraw {{ symbol }}</template>
<SidebarSectionValueWithIcon label="Supplied" center>
<template #icon
><IconCurrency :currency="tokenKey" class="w-20 h-20" noHeight
/></template>
<template #value>{{ formatNumber(collateral) }} {{ symbol }}</template>
</SidebarSectionValueWithIcon>
<div class="bg-[#C5CCE1] bg-opacity-[0.15] mt-10 p-8">
<h3 class="text-primary-gray text-xs font-semibold mb-2.5">
Amount to withdraw
</h3>
<input-numeric
v-model="amount"
placeholder="Amount to withdraw"
:error="errors.amount.message"
>
<template v-if="!isMaxAmount" #suffix>
<div class="absolute mt-2 top-0 right-0 mr-4">
<button
type="button"
class="text-primary-blue-dark font-semibold text-sm hover:text-primary-blue-hover"
@click="toggle"
>
Max
</button>
</div>
</template>
</input-numeric>
<SidebarContextHeading class="mt-5">
Projected Debt Position
</SidebarContextHeading>
<SidebarSectionStatus
class="mt-8"
:liquidation="liquidation"
:status="status"
/>
<SidebarSectionValueWithIcon class="mt-8" label="Liquidation Price (ETH)">
<template #value>
{{ formatUsdMax(liquidationPrice, liquidationMaxPrice) }}
<span class="text-primary-gray"
>/ {{ formatUsd(liquidationMaxPrice) }}</span
>
</template>
</SidebarSectionValueWithIcon>
<div class="flex flex-shrink-0 mt-10">
<ButtonCTA
class="w-full"
:disabled="!isValid || pending"
:loading="pending"
@click="cast"
>
Withdraw
</ButtonCTA>
</div>
<ValidationErrors :error-messages="errorMessages" class="mt-6" />
</div>
</SidebarContextRootContainer>
</template>
<script>
import { computed, defineComponent, ref } from '@nuxtjs/composition-api'
import InputNumeric from '~/components/common/input/InputNumeric.vue'
import { useBigNumber } from '~/composables/useBigNumber'
import { useFormatting } from '~/composables/useFormatting'
import { useValidators } from '~/composables/useValidators'
import { useValidation } from '~/composables/useValidation'
import { useToken } from '~/composables/useToken'
import { useParsing } from '~/composables/useParsing'
import { useMaxAmountActive } from '~/composables/useMaxAmountActive'
import { useWeb3 } from '@instadapp/vue-web3'
import ToggleButton from '~/components/common/input/ToggleButton.vue'
import { useDSA } from '~/composables/useDSA'
import ButtonCTA from '~/components/common/input/ButtonCTA.vue'
import { useNotification } from '~/composables/useNotification'
import Button from '~/components/Button.vue'
import { useSidebar } from '~/composables/useSidebar'
import { useReflexerPosition } from '~/composables/protocols/useReflexerPosition'
import { useBalances } from '~/composables/useBalances'
export default defineComponent({
components: { InputNumeric, ToggleButton, ButtonCTA, Button },
setup(props) {
const { close } = useSidebar()
const { account } = useWeb3()
const { dsa } = useDSA()
const { valInt } = useToken()
const { fetchBalances } = useBalances()
const { formatNumber, formatUsdMax, formatUsd } = useFormatting()
const { isZero, gt, plus, max, minus } = useBigNumber()
const { parseSafeFloat } = useParsing()
const { showPendingTransaction, showConfirmedTransaction, showWarning } = useNotification()
const amount = ref('')
const amountParsed = computed(() => parseSafeFloat(amount.value))
const { tokenKey, token, debt, collateral, liquidation, liquidationMaxPrice, safeId, fetchPosition } = useReflexerPosition()
const symbol = computed(() => token.value?.symbol)
const decimals = computed(() => token.value?.decimals)
const changedCollateral = computed(() => max(minus(collateral.value, amountParsed.value), '0').toFixed())
const { liquidationPrice, status } = useReflexerPosition(changedCollateral, debt)
const { toggle, isMaxAmount } = useMaxAmountActive(amount, collateral)
const { validateAmount, validateLiquidation, validateIsLoggedIn } = useValidators()
const errors = computed(() => {
const hasAmountValue = !isZero(amount.value)
return {
amount: { message: validateAmount(amountParsed.value, collateral.value), show: hasAmountValue },
liquidation: {
message: validateLiquidation(status.value, liquidation.value, isZero(debt.value)),
show: hasAmountValue,
},
auth: { message: validateIsLoggedIn(!!account.value), show: true },
}
})
const { errorMessages, isValid } = useValidation(errors)
const pending = ref(false)
async function cast() {
pending.value = true
const amount = isMaxAmount.value ? dsa.value.maxValue : valInt(amountParsed.value, decimals.value)
const spells = dsa.value.Spell()
spells.add({
connector: 'REFLEXER-A',
method: 'withdraw',
args: [safeId.value, amount, 0, 0],
})
try {
const txHash = await dsa.value.cast({
spells,
from: account.value,
onReceipt: async receipt => {
showConfirmedTransaction(receipt.transactionHash);
await fetchBalances(true);
await fetchPosition();
}
})
showPendingTransaction(txHash)
} catch (error) {
showWarning(error.message)
}
pending.value = false
close()
}
return {
tokenKey,
symbol,
collateral,
debt,
amount,
status,
liquidation,
liquidationPrice,
liquidationMaxPrice,
formatUsd,
formatUsdMax,
formatNumber,
errors,
errorMessages,
isMaxAmount,
isValid,
cast,
pending,
toggle,
}
},
})
</script>

View File

@ -0,0 +1,346 @@
import { computed, Ref, ref, watch } from "@nuxtjs/composition-api";
import BigNumber from "bignumber.js";
BigNumber.config({ POW_PRECISION: 200 });
import abis from "~/constant/abis";
import addresses from "~/constant/addresses";
import reflexerSafes from "~/constant/tokens/safes";
import { useBigNumber } from "~/composables/useBigNumber";
import { useDSA } from "~/composables/useDSA";
import { useToken } from "~/composables/useToken";
import { useWeb3 } from "@instadapp/vue-web3";
import { AbiItem } from "web3-utils";
import { useBalances } from "../useBalances";
const defaultSafe = {
id: null,
tokenKey: "eth",
token: "ETH",
collateralName: "ETH-A",
collateral: "0",
debt: "0",
liquidatedCollateral: "0",
status: "0",
rate: "0",
liquidation: "0",
price: "0",
netvalue: "0"
};
const oracleRelayerAddress = "0x4ed9C0dCa0479bC64d8f4EB3007126D5791f7851";
const safeId = ref(null);
const safes = ref([]);
const isNewSafe = ref(false);
const safeTypes = ref([]);
const safeType = ref("");
const safe = computed(() => {
const vlt = safes.value.find(v => v.id === safeId.value);
if (!isNewSafe.value && !!vlt) {
return vlt;
}
const vt = safeTypes.value.find(vt => vt.type === safeType.value);
if (vt) {
return { ...defaultSafe, ...vt };
}
const defaultSafeType = safeTypes.value[0];
if (defaultSafeType) {
return { ...defaultSafe, ...defaultSafeType };
}
return defaultSafe;
});
export function useReflexerPosition(
collateralAmountRef: Ref = null,
debtAmountRef: Ref = null
) {
const { library } = useWeb3();
const { activeAccount } = useDSA();
const { isZero, ensureValue, times, div, max, gt, toBN } = useBigNumber();
const { getTokenByKey } = useToken();
const { prices } = useBalances();
const raiToken = computed(() => getTokenByKey("rai"));
const raiInUsd = computed(() =>
raiToken.value ? prices.mainnet[raiToken.value.address] || "0" : "0"
);
const safeTokenType = computed(() => safe.value.safeTokenType);
const price = computed(() => ensureValue(safe.value.price).toFixed());
const spotPrice = computed(() => ensureValue(safe.value.spotPrice).toFixed());
const collateralUsd = computed(() =>
times(collateral.value, price.value).toFixed()
);
const collateral = computed(() =>
ensureValue(safe.value.collateral).toFixed()
);
const liquidation = computed(() =>
ensureValue(safe.value.liquidation).toFixed()
);
const tokenKey = computed(() => safe.value.tokenKey);
const token = computed(() => getTokenByKey(tokenKey.value));
const symbol = computed(() => token.value.symbol ?? "ETH");
const rate = computed(() => ensureValue(safe.value.rate).toFixed());
const netValue = computed(() => ensureValue(safe.value.netValue).toFixed());
const status = computed(() => {
if (!collateralAmountRef || !debtAmountRef)
return ensureValue(safe.value.status).toFixed();
return isZero(collateralAmountRef.value) && !isZero(debtAmountRef.value)
? "1.1"
: div(
debtAmountRef.value,
times(collateralAmountRef.value, spotPrice.value)
).toFixed();
});
const liquidationPrice = computed(() => {
if (!collateralAmountRef || !debtAmountRef)
return max(
div(div(debt.value, collateral.value), liquidation.value),
"0"
).toFixed();
return isZero(collateralAmountRef.value) && !isZero(debtAmountRef.value)
? times(price.value, "1.1").toFixed()
: max(
div(
div(debtAmountRef.value, collateralAmountRef.value),
toBN(liquidation.value)
.multipliedBy(spotPrice.value)
.dividedBy(price.value)
),
"0"
).toFixed();
});
const debt = computed(() => ensureValue(safe.value.debt).toFixed());
const debtUsd = computed(() =>
times(debt.value, raiInUsd.value).toFixed()
);
const minDebt = computed(
() => safeTypes.value[0]?.totalDebt?.toString() || "699"
);
const debtCeilingReached = computed(() =>
safeTypes.value?.some(v =>
gt(v.overallTotalDebt, v.overallTotalDebtCeiling)
)
);
const fetchPosition = async () => {
if (!library.value) {
return;
}
safeTypes.value = await getSafeTypes(library.value);
if (!activeAccount.value) {
return;
}
safes.value = await getSafes(activeAccount.value.address, library.value);
if (safes.value.length > 0 && !safeId.value) {
safeId.value = safes.value[0].id;
}
};
watch(
library,
async val => {
if (val) {
fetchPosition();
}
},
{ immediate: true }
);
watch(
activeAccount,
async val => {
if (val) {
fetchPosition();
}
},
{ immediate: true }
);
const selectSafe = vid => {
if (vid === safeId.value && !isNewSafe.value) return;
safeId.value = vid;
isNewSafe.value = false;
};
return {
fetchPosition,
safeId: computed(() => (isNewSafe.value ? "0" : safeId.value || "0")),
selectSafe,
safeTokenType,
safe,
safes,
safeType,
safeTypes,
isNewSafe,
collateralUsd,
collateral,
price,
raiInUsd,
liquidation,
tokenKey,
token,
symbol,
rate,
netValue,
status,
liquidationPrice,
liquidationMaxPrice: price,
debt,
debtUsd,
minDebt,
debtCeilingReached
};
}
async function getSafeTypes(web3) {
const reflexerResolveABI = abis.resolver.reflexer;
const reflexerResolveAddr = addresses.mainnet.resolver.reflexer;
const reflexerResolverInstance = new web3.eth.Contract(
reflexerResolveABI as AbiItem[],
reflexerResolveAddr
);
try {
const rawData: any[] = await reflexerResolverInstance.methods
.getColInfo(reflexerSafes.types)
.call();
const rawRedemptionPrice = await web3.eth.getStorageAt(
oracleRelayerAddress,
4
);
return reflexerSafes.allSafes.map(
({ type, token, key: tokenKey, disabled, safeTokenType }, i) => {
const [rate, price, ratioCbyD, debtCeiling, totalDebt] = rawData[i];
return {
type,
token,
tokenKey,
disabled,
safeTokenType,
rate: calRate(rate),
redemptionPrice: new BigNumber(rawRedemptionPrice)
.dividedBy(1e27)
.toFixed(),
spotPrice: new BigNumber(price).dividedBy(1e27).toFixed(),
price: new BigNumber(price)
.times(rawRedemptionPrice)
.dividedBy(1e54)
.toFixed(),
liquidation: new BigNumber(1)
.dividedBy(new BigNumber(ratioCbyD).dividedBy(1e27))
.toFixed(),
debtCeiling: debtCeiling,
totalDebt: new BigNumber(totalDebt).multipliedBy(1.00002).toFixed()
};
}
);
} catch (error) {
console.error(error);
return [];
}
}
async function getSafes(user, web3) {
try {
const reflexerResolveABI = abis.resolver.reflexer;
const reflexerResolveAddr = addresses.mainnet.resolver.reflexer;
const reflexerResolverInstance = new web3.eth.Contract(
reflexerResolveABI as AbiItem[],
reflexerResolveAddr
);
const rawData: any[] = await reflexerResolverInstance.methods
.getSafes(user)
.call();
const rawRedemptionPrice = await web3.eth.getStorageAt(
oracleRelayerAddress,
4
);
return rawData.map(
([
id,
owner,
type,
collInWei,
,
debtInWei,
liquidatedColInWei,
ratePerBlock,
priceInWei,
liquidationRatioCbyD,
urn
]) => {
const collateral = new BigNumber(collInWei).dividedBy(1e18);
const debt = new BigNumber(debtInWei).dividedBy(1e18);
const spotPrice = new BigNumber(priceInWei).dividedBy(1e27);
const price = new BigNumber(priceInWei)
.times(rawRedemptionPrice)
.dividedBy(1e54);
const safe = reflexerSafes.getSafeByType(type);
return {
id,
owner,
type,
tokenKey: safe.key,
token: safe.token,
safeTokenType: safe.safeTokenType,
collateral: collateral.toFixed(),
debt: debt.toFixed(),
liquidatedCollateral: new BigNumber(liquidatedColInWei)
.dividedBy(1e18)
.toFixed(),
rate: calRate(ratePerBlock),
price: price.toFixed(),
spotPrice,
liquidation: new BigNumber(1)
.dividedBy(new BigNumber(liquidationRatioCbyD).dividedBy(1e27))
.toFixed(),
urn,
netValue: collateral
.multipliedBy(price)
.minus(debt)
.toFixed(),
status: collateral.isZero()
? "0"
: debt.dividedBy(collateral.multipliedBy(spotPrice)).toFixed()
};
}
);
} catch (error) {
console.error(error);
return [];
}
}
function calRate(ilkRate) {
try {
return new BigNumber(ilkRate)
.dividedBy(1e27)
.pow(31545000)
.minus(1)
.toFixed(18);
} catch (error) {
console.log("error", error);
}
}

View File

@ -35,6 +35,12 @@ import SidebarLiquityTroveWithdraw from '~/components/sidebar/context/liquity/Si
import SidebarLiquityTroveBorrow from '~/components/sidebar/context/liquity/SidebarLiquityTroveBorrow.vue'
import SidebarLiquityTrovePayback from '~/components/sidebar/context/liquity/SidebarLiquityTrovePayback.vue'
import SidebarReflexerCollateral from '~/components/sidebar/context/reflexer/SidebarReflexerCollateral.vue'
import SidebarReflexerSupply from '~/components/sidebar/context/reflexer/SidebarReflexerSupply.vue'
import SidebarReflexerWithdraw from '~/components/sidebar/context/reflexer/SidebarReflexerWithdraw.vue'
import SidebarReflexerBorrow from '~/components/sidebar/context/reflexer/SidebarReflexerBorrow.vue'
import SidebarReflexerPayback from '~/components/sidebar/context/reflexer/SidebarReflexerPayback.vue'
import SidebarStrategySelection from '~/components/sidebar/context/strategy/SidebarStrategySelection.vue'
import SidebarStrategy from '~/components/sidebar/context/strategy/SidebarStrategy.vue'
@ -69,6 +75,13 @@ const sidebars = {
'/mainnet/liquity#trove-withdraw': { component: SidebarLiquityTroveWithdraw },
'/mainnet/liquity#trove-borrow': { component: SidebarLiquityTroveBorrow },
'/mainnet/liquity#trove-payback': { component: SidebarLiquityTrovePayback },
"/mainnet/reflexer": { component: null },
'/mainnet/reflexer#collateral': { component: SidebarReflexerCollateral },
"/mainnet/reflexer#supply": { component: SidebarReflexerSupply },
"/mainnet/reflexer#withdraw": { component: SidebarReflexerWithdraw },
"/mainnet/reflexer#borrow": { component: SidebarReflexerBorrow },
"/mainnet/reflexer#payback": { component: SidebarReflexerPayback },
};
const sidebar = ref(null);

View File

@ -2,17 +2,19 @@ import { useBigNumber } from "./useBigNumber";
import { useFormatting } from "./useFormatting";
import { useMakerdaoPosition } from "~/composables/protocols/useMakerdaoPosition";
import { useLiquityPosition } from "./protocols/useLiquityPosition";
import { useReflexerPosition } from "./protocols/useReflexerPosition";
export function useValidators() {
const { formatNumber } = useFormatting();
const { isZero, minus, eq, gt, lt, gte, plus } = useBigNumber();
const { minDebt: makerMinDebt, vaultTypes } = useMakerdaoPosition();
const { minDebt: reflexerMinDebt, safeTypes } = useReflexerPosition();
const {
minDebt: liquityMinDebt,
liquidationReserve: liquityLiquidationReserve,
troveOpened: liquityTroveOpened
} = useLiquityPosition();
function validateAmount(amountParsed, balance = null, options = null) {
const mergedOptions = Object.assign(
{ msg: "Your amount exceeds your maximum limit." },
@ -96,6 +98,50 @@ export function useValidators() {
return null;
}
function validateReflexerDebtCeiling(safeType, debtParsed = 0) {
const safe = safeTypes.value.find(v => v.type === safeType);
const { debtCeiling, totalDebt } = safe || {};
if (!isZero(debtCeiling) && !isZero(totalDebt)) {
const total = plus(totalDebt, debtParsed);
return gte(total, debtCeiling)
? `${safeType} Collateral reached debt ceiling`
: null;
}
return null;
}
function validateReflexerDebt(
debtParsed,
minDebt = reflexerMinDebt.value,
vaultId,
) {
if (lt(debtParsed, minDebt) && gt(debtParsed, "0")) {
const vaultText = vaultId
? vaultId !== "0"
? `on vault #${vaultId}`
: `on new vault`
: "";
return `Minimum debt requirement is ${minDebt} RAI ${vaultText}` ;
}
return null;
}
function validateReflexerPaybackDebt(
debtParsed,
minDebt = reflexerMinDebt.value,
vaultId,
) {
if (lt(debtParsed, minDebt) && gt(debtParsed, "0")) {
return `Minimum debt requirement is ${minDebt} RAI. Payback additional ${debtParsed} RAI`;
}
return null;
}
function validateLiquityDebt(
debtParsed,
minDebt = liquityMinDebt.value,
@ -129,6 +175,9 @@ export function useValidators() {
validateMakerDebt,
validateMakerDebtCeiling,
validateLiquityDebt,
validateLiquityTroveExists
validateLiquityTroveExists,
validateReflexerDebtCeiling,
validateReflexerDebt,
validateReflexerPaybackDebt,
};
}

View File

@ -0,0 +1,271 @@
[
{
"inputs": [
{
"internalType": "string[]",
"name": "name",
"type": "string[]"
}
],
"name": "getColInfo",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "borrowRate",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "price",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "liquidationRatio",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "debtCeiling",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "debtFloor",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalDebt",
"type": "uint256"
}
],
"internalType": "struct Helpers.ColInfo[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getRedemptionRate",
"outputs": [
{
"internalType": "uint256",
"name": "redemptionRate",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getReflexerAddresses",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "manager",
"type": "address"
},
{
"internalType": "address",
"name": "safeEngine",
"type": "address"
},
{
"internalType": "address",
"name": "taxCollector",
"type": "address"
},
{
"internalType": "address",
"name": "oracleRelayer",
"type": "address"
},
{
"internalType": "address",
"name": "getSafes",
"type": "address"
}
],
"internalType": "struct Helpers.ReflexerAddresses",
"name": "",
"type": "tuple"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "getSafeById",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "string",
"name": "colType",
"type": "string"
},
{
"internalType": "uint256",
"name": "collateral",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "debt",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "adjustedDebt",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "liquidatedCol",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "borrowRate",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "colPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "liquidationRatio",
"type": "uint256"
},
{
"internalType": "address",
"name": "safeAddress",
"type": "address"
}
],
"internalType": "struct Helpers.SafeData",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "getSafes",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "id",
"type": "uint256"
},
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "string",
"name": "colType",
"type": "string"
},
{
"internalType": "uint256",
"name": "collateral",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "debt",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "adjustedDebt",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "liquidatedCol",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "borrowRate",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "colPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "liquidationRatio",
"type": "uint256"
},
{
"internalType": "address",
"name": "safeAddress",
"type": "address"
}
],
"internalType": "struct Helpers.SafeData[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@ -7,7 +7,7 @@ import makerABI from "./abi/read/maker.json";
import makerProxyRegistryABI from "./abi/makerProxyRegistry.json";
import unipoolABI from "./abi/read/unipool.json";
import liquityABI from "./abi/read/liquity.json";
import reflexerABI from './abi/read/reflexer.json'
const abis = {
makerProxyRegistry: makerProxyRegistryABI,
resolver: {
@ -19,6 +19,7 @@ const abis = {
maker: makerABI,
unipool: unipoolABI,
liquity: liquityABI,
reflexer: reflexerABI
}
};

View File

@ -9,25 +9,26 @@ const addresses = {
compound: "0xcCAa4b1b3931749b8b6EF19C6b0B2c496703321b",
maker: "0x84addce4fac0b6ee4b0cd132120d6d4b700e35c0",
unipool: "0x22bddA39D14eD0aafeee36B6e784602fdDE64723",
liquity: '0xDAf2A39503463B0F41f899EDD82213b3c96b6Cf8',
},
liquity: "0xDAf2A39503463B0F41f899EDD82213b3c96b6Cf8",
reflexer: "0x016ca8d0993d1a7073b01802a2e22fd0df7e633a"
}
},
polygon: {
core: {
instaIndex: "0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad",
instaConnectorsV2: "0x2A00684bFAb9717C21271E0751BCcb7d2D763c88",
instaConnectorsV2: "0x2A00684bFAb9717C21271E0751BCcb7d2D763c88"
},
resolver: {
aave_v2: "0xD6E0803d0eB34af8Ea135835512D7E77960b28F1",
accounts: "0xdF19Da523DA64bBE82eE0E4DFf00d676A8386474",
balance: "0x04F8a41be023f839E709eeEaA0725FD766139A4d",
merkleResolver: {
aave_v2: "0x2a26228e607ffD2aB2bD3aA49cBae0eDC6469Bf8",
aave_v2: "0x2a26228e607ffD2aB2bD3aA49cBae0eDC6469Bf8"
},
weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
},
},
weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
}
}
};
export default addresses;

10
constant/tokens/safes.ts Normal file
View File

@ -0,0 +1,10 @@
// prettier-ignore
const safes = [
{ type: 'ETH-A', token: 'ETH', key: 'eth', ratio: 0.6666666666666666, joinAddr: '0x2D3cD7b81c93f188F3CB8aD87c8Acc73d6226e3A', addr: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', stabiltyRate: 0, price: 0, typeBytes: '0x4554482d41000000000000000000000000000000000000000000000000000000', disabled: false, safeTokenType: 'token' },
]
export default {
allSafes: safes,
types: safes.map(safe => safe.type),
getSafeByType: type => safes.find(safe => safe.type === type)
};

View File

@ -37,6 +37,7 @@ import CompoundIcon from "~/assets/icons/compound.svg?inline";
import MakerIcon from "~/assets/icons/makerdao.svg?inline";
import OneInchIcon from "~/assets/icons/1inch.svg?inline";
import LiquityIcon from "~/assets/icons/liquity.svg?inline";
import ReflexerIcon from "~/assets/icons/reflexer.svg?inline";
const appsPerNetwork = {
mainnet: [
@ -68,12 +69,19 @@ const appsPerNetwork = {
url: "/1inch",
description: "DEX Aggregator"
},
{
{
id: "liquity",
icon: LiquityIcon,
name: "Liquity",
url: "/mainnet/liquity",
description: "Collateralized LUSD Debt"
},
{
id: "reflexer",
icon: ReflexerIcon,
name: "Reflexer Finance",
url: "/mainnet/reflexer",
description: "Collateralized RAI Debt"
}
],
polygon: [

297
pages/mainnet/reflexer.vue Normal file
View File

@ -0,0 +1,297 @@
<template>
<div>
<div>
<nuxt-link
to="/"
class="text-[#C0C5D7] text-lg font-semibold flex items-center"
>
<BackIcon class="w-4 h-4 mr-3" />
Apps
</nuxt-link>
</div>
<div class="mt-10 flex items-center">
<div class="flex items-center">
<div
style="background: radial-gradient(42.15% 42.15% at 48.94% 48.94%, #D6DAE0 75.67%, #F0F3F9 100%), #C4C4C4;"
class="w-16 h-16 rounded-full flex items-center justify-center border border-[#CCDCF3]"
>
<div
class="w-12 h-12 rounded-full flex items-center justify-center bg-[#1874FF]"
>
<ReflexerIcon Icon class="w-8 h-8 text-white" />
</div>
</div>
<h1 class="ml-4 text-primary-black text-2xl font-semibold">Reflexer</h1>
</div>
<dropdown-reflexer class="ml-auto" />
</div>
<div class="mt-10">
<h2 class="text-primary-gray text-lg font-semibold">Overview</h2>
<div
class="px-1 mt-6 grid w-full grid-cols-1 gap-4 sm:grid-cols-3 xl:gap-[18px]"
>
<div class="shadow rounded-lg py-8 px-6 flex">
<div class="flex-1">
<h3 class="text-2xl text-primary-black font-medium">
# {{ safeId }}
</h3>
<p class="mt-4 text-primary-gray font-medium">Safe ID</p>
</div>
<div class="flex items-center">
<IconBackground
name="cube"
class="bg-blue-pure text-blue-pure"
icon-class="h-7"
/>
</div>
</div>
<div class="shadow rounded-lg py-8 px-6 flex">
<div class="flex-1">
<h3 class="text-2xl text-primary-black font-medium">
{{ formatUsd(netValue) }}
</h3>
<p class="mt-4 text-primary-gray font-medium">Net Value</p>
</div>
<div class="flex items-center">
<SVGBalance />
</div>
</div>
<div class="shadow rounded-lg py-8 px-6 flex">
<div class="flex-1">
<h3 class="text-2xl text-primary-black font-medium">
{{ formatPercent(rate) }}
</h3>
<p class="mt-4 text-primary-gray font-medium">Borrow Rate</p>
</div>
<div class="flex items-center">
<SVGPercent class="h-12" />
</div>
</div>
<div class="shadow rounded-lg py-8 px-6 flex">
<div class="flex-1">
<div class="flex justify-between items-center">
<h3 class="text-2xl text-primary-black font-medium">
{{ formatPercent(status) }}
</h3>
<Badge class="w-18 xxl:w-23" :color="color">{{ text }}</Badge>
</div>
<div
class="mt-4 flex justify-between items-center text-primary-gray font-medium"
>
<div class="flex items-center whitespace-no-wrap">
<div>D/C (%)</div>
<div class="ml-2"><Info text="Debt/Collateral ratio" /></div>
</div>
<span>Max - {{ formatPercent(liquidation) }}</span>
</div>
</div>
</div>
<div class="shadow rounded-lg py-8 px-6 flex">
<div class="flex-1">
<h3 class="text-2xl text-primary-black font-medium">
{{ formatUsdMax(liquidationPrice, liquidationMaxPrice) }} /
{{ formatUsd(liquidationMaxPrice) }}
</h3>
<p class="mt-4 text-primary-gray font-medium">Liquidation (ETH)</p>
</div>
<div class="flex items-center">
<IconBackground
name="receipt-tax"
class="bg-light-brown-pure text-light-brown-pure"
/>
</div>
</div>
</div>
</div>
<div class="mt-[60px]">
<div
class="w-full flex flex-col mt-6 sm:flex-row sm:items-center sm:justify-between xl:mt-4"
>
<h2 class="text-primary-gray text-lg font-semibold">Your Positions</h2>
</div>
<div
class="mt-3 grid w-full grid-cols-1 gap-4 sm:grid-cols-2 xxl:gap-6 min-w-max-content px-1"
>
<CardReflexer
:amount="collateral"
:amount-usd="collateralUsd"
position-type="supply"
:token-key="tokenKey"
:safe-token-type="safeTokenType"
:supply-or-borrow="showSupply"
:withdraw-or-payback="showWithdraw"
:price-in-usd="liquidationMaxPrice"
/>
<CardReflexer
:amount="debt"
:amount-usd="debtUsd"
position-type="borrow"
token-key="rai"
:safe-token-type="safeTokenType"
:supply-or-borrow="showBorrow"
:withdraw-or-payback="showPayback"
:price-in-usd="raiInUsd"
/>
</div>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, useRouter } from "@nuxtjs/composition-api";
import BackIcon from "~/assets/icons/back.svg?inline";
import SVGIncoming from "@/assets/img/icons/incoming.svg?inline";
import SVGBalance from "@/assets/img/icons/balance.svg?inline";
import SVGEarnings from "@/assets/img/icons/earnings.svg?inline";
import SVGArrowRight from "@/assets/img/icons/arrow-right.svg?inline";
import SVGPercent from "@/assets/img/icons/percent.svg?inline";
import CardReflexer from "~/components/protocols/reflexer/CardReflexer.vue";
import { useBigNumber } from "~/composables/useBigNumber";
import { useFormatting } from "~/composables/useFormatting";
import { useReflexerPosition } from "~/composables/protocols/useReflexerPosition";
import { useStatus } from "~/composables/useStatus";
import { useNotification } from "~/composables/useNotification";
import DropdownReflexer from "~/components/protocols/reflexer/DropdownReflexer.vue";
import ReflexerIcon from "~/assets/icons/reflexer.svg?inline";
export default defineComponent({
components: {
BackIcon,
CardReflexer,
SVGIncoming,
SVGBalance,
SVGEarnings,
SVGArrowRight,
SVGPercent,
DropdownReflexer,
ReflexerIcon
},
setup() {
const router = useRouter();
const { div, isZero, gt, lt } = useBigNumber();
const {
formatUsd,
formatUsdMax,
formatPercent,
formatDecimal
} = useFormatting();
const { showWarning } = useNotification();
const {
status,
safes,
safeTokenType,
collateral,
collateralUsd,
safeId,
liquidation,
tokenKey,
symbol,
rate,
netValue,
liquidationPrice,
liquidationMaxPrice,
debt,
debtUsd,
minDebt,
debtCeilingReached,
raiInUsd,
isNewSafe,
safeType,
safeTypes
} = useReflexerPosition();
const statusLiquidationRatio = computed(() =>
div(status.value, liquidation.value).toFixed()
);
const { color, text } = useStatus(statusLiquidationRatio);
function showSupply() {
if (gt(debt.value, "0") && lt(debt.value, minDebt.value)) {
// select("depositAndBorrow");
} else if (safes.value.length === 0) {
if (safeTypes.value.length === 0) {
} else if (safeTypes.value.length === 1) {
safeType.value = safeTypes.value[0].type;
isNewSafe.value = true;
router.push({ hash: "supply" });
} else {
router.push({ hash: "collateral" });
}
} else {
router.push({ hash: "supply" });
}
}
function showWithdraw() {
if (isZero(collateral.value)) {
showWarning("ReflexerDAO", "No collateral supplied!!");
} else if (gt(debt.value, "0") && lt(debt.value, minDebt.value)) {
// select("paybackAndWithdraw");
} else {
router.push({ hash: "withdraw" });
}
}
function showPayback() {
if (isZero(collateral.value)) {
showWarning("ReflexerDAO", "No collateral supplied!!");
} else {
router.push({ hash: "payback?tokenKey=rai" });
}
}
function showBorrow() {
if (isZero(collateral.value)) {
showWarning("ReflexerDAO", "Deposit collateral before borrowing!!");
} else {
router.push({ hash: "borrow?tokenKey=rai" });
}
}
return {
formatUsd,
formatUsdMax,
formatPercent,
formatDecimal,
color,
text,
safeTokenType,
collateral,
collateralUsd,
safeId,
liquidation,
tokenKey,
netValue,
rate,
symbol,
status,
liquidationPrice,
liquidationMaxPrice,
showWithdraw,
showPayback,
showBorrow,
showSupply,
debt,
debtUsd,
minDebt,
debtCeilingReached,
raiInUsd
};
}
});
</script>