Merge pull request #61 from liftlearning/develop

V2
This commit is contained in:
Ronyell Henrique authored and GitHub committed 2023-03-01 18:54:36 -03:00
commit b956c8ec2b
63 files changed
+2385 -735

No files matched your search

-3
View File
@@ -1,3 +0,0 @@
VITE_API_URL=http://localhost:8000/
VITE_GOERLI_API_URL={GOERLI_API_URL_ALCHEMY}
VITE_MUMBAI_API_URL={MUMBAI_API_URL_ALCHEMY}
+2
View File
@@ -14,8 +14,10 @@
"lint:fix": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
},
"dependencies": {
"@floating-ui/vue": "^0.2.1",
"@headlessui/vue": "^1.7.3",
"@heroicons/vue": "^2.0.12",
"@vueuse/core": "^9.12.0",
"alchemy-sdk": "^2.3.0",
"axios": "^1.2.1",
"crc": "^3.8.0",
+7 -1
View File
@@ -1,5 +1,6 @@
<script setup lang="ts">
import TopBar from "./components/TopBar/TopBar.vue";
import TopBar from "@/components/TopBar/TopBar.vue";
import SpinnerComponent from "@/components/SpinnerComponent.vue";
</script>
<template>
@@ -8,6 +9,11 @@ import TopBar from "./components/TopBar/TopBar.vue";
<template v-if="Component">
<Suspense>
<component :is="Component"></component>
<template #fallback>
<div class="flex w-full h-full justify-center items-center">
<SpinnerComponent :width="'16'" :height="'16'"></SpinnerComponent>
</div>
</template>
</Suspense>
</template>
</RouterView>
+20 -20
View File
@@ -1,34 +1,34 @@
<svg width="1440" height="1024" viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g clip-path="url(#clip0_847_732)">
<rect width="1440" height="1024" fill="#111827"/>
<rect width="1440" height="1024" fill="url(#pattern0)" style="mix-blend-mode:overlay"/>
<g opacity="0.95" filter="url(#filter0_f_847_732)">
<path d="M1367.83 552.44C1379.11 529.54 1262.11 485.261 1202.2 465.985C1146.53 442.342 1021.37 394.67 966.096 393.127C897.008 391.198 842.513 402.615 726.299 403.143C610.086 403.671 535.439 425.792 299.367 461.43C63.2953 497.068 190.378 484.263 64.1408 579.89C-62.0961 675.517 39.591 662.202 84.1295 746.443C128.668 830.684 150.957 767.426 226.733 787.188C302.508 806.95 239.996 767.481 354.257 773.476C375.949 774.614 401.683 767.919 401.683 767.919C401.683 767.919 512.832 794.344 405.989 835.062C299.146 875.779 466.967 891.673 436.369 956.064C405.771 1020.46 392.204 1020.91 592.857 1079.86C793.511 1138.81 751.424 1048.76 856.456 992.952C961.488 937.144 866.361 996.221 960.994 956.602C1055.63 916.984 982.798 819.165 1090.19 853.356C1197.58 887.548 1156.14 867.074 1287.63 853.099C1419.12 839.124 1326.26 817.718 1346.46 769.516C1366.66 721.313 1316.51 698.62 1330.49 636.497C1344.47 574.374 1353.72 581.064 1367.83 552.44Z" fill="#059669"/>
<path d="M1235.57 657.249C1203.31 684.536 1121.94 723.971 1022.6 742.63L1006.49 756.787C941.094 753.271 795.807 746.487 737.846 747.473L643.49 749.078C609.792 749.651 554.189 750.597 217.256 600.01C153.678 546.586 175.842 566.777 109.411 475.865C42.9808 384.952 95.3741 418.513 100.844 316.093C106.315 213.674 124.624 240.615 193.565 158.199C262.507 75.7822 224.41 120.137 345.399 80.5427C466.387 40.9481 455.336 55.0195 605.944 48.8584C756.551 42.6973 745.859 63.4473 841.608 72.1027C937.357 80.7582 909.264 91.52 988.522 107.141C1067.78 122.761 1073.39 132.95 1153.36 161.928C1233.33 190.905 1210.61 191.806 1314.34 254.831C1418.06 317.856 1317.62 315.966 1376.5 376.154C1435.38 436.343 1380.13 443.967 1383.8 512.294C1387.46 580.62 1353.31 557.034 1331.83 581.052C1310.35 605.071 1267.84 629.962 1235.57 657.249Z" fill="#60A5FA"/>
<g clip-path="url(#clip0_1163_1577)">
<rect width="1440" height="1024" transform="translate(1440 1024) rotate(-180)" fill="#111827"/>
<rect width="1440" height="1024" transform="translate(1440 1024) rotate(-180)" fill="url(#pattern0)" style="mix-blend-mode:overlay"/>
<g filter="url(#filter0_f_1163_1577)">
<path d="M307.642 94.7582C329.492 66.5307 387.168 22.494 460.177 -4.02267L471.036 -18.6085C520.484 -21.466 630.246 -28.7616 673.711 -35.0842L744.468 -45.3768C769.738 -49.0528 811.434 -55.118 1077.82 52.5739C1130.28 96.0046 1111.85 79.4162 1169.75 157.222C1227.64 235.027 1185.33 208.907 1190.2 304.059C1195.08 399.211 1178.96 376.025 1134.39 458.619C1089.82 541.213 1114.55 496.67 1027.12 544.553C939.684 592.437 946.753 578.403 834.129 598.157C721.504 617.912 727.718 597.74 655.013 598.681C582.309 599.623 602.473 587.055 541.549 580.021C480.625 572.987 475.518 564.095 412.883 544.785C350.249 525.475 367.241 522.522 283.773 473.967C200.305 425.413 275.945 417.782 226.421 367.662C176.897 317.542 217.738 305.339 208.989 242.544C200.24 179.748 227.97 198.355 242.001 174.155C256.033 149.955 285.793 122.986 307.642 94.7582Z" fill="#1E40AF"/>
<path d="M190.775 -149.087C224.733 -176.041 310.524 -217.148 415.43 -240.372L432.377 -254.317C501.523 -255.158 655.128 -257.966 716.388 -262.462L816.114 -269.782C851.73 -272.396 910.497 -276.709 1267.45 -159.904C1334.94 -114.994 1311.4 -132.083 1382.11 -53.069C1452.82 25.9449 1397.26 -1.49464 1392.03 92.5012C1386.8 186.497 1367.3 162.996 1294.87 242.637C1222.44 322.279 1262.47 279.355 1134.8 323.066C1007.13 366.777 1018.73 353.225 859.573 368.2C700.413 383.175 711.603 363.537 610.349 361.56C509.095 359.584 538.732 348.001 454.872 338.632C371.012 329.264 365.031 320.295 280.342 298.756C195.653 277.218 219.662 274.985 109.686 223.786C-0.289922 172.586 105.892 168.085 43.3306 116.698C-19.2306 65.311 39.1219 54.9127 34.8812 -7.34079C30.6406 -69.5943 66.8651 -50.1438 89.4394 -73.4396C112.014 -96.7355 156.816 -122.133 190.775 -149.087Z" fill="#312E81"/>
</g>
<g style="mix-blend-mode:color-burn" opacity="0.4" filter="url(#filter1_f_847_732)">
<path d="M238.125 432.859C214.047 414.357 179.782 368.564 164.502 313.519L152 304.269C156.167 268.498 164.502 189 164.502 157.176L164.502 105.37C164.502 86.8673 164.502 56.3386 305.266 -124.058C354.348 -157.362 335.826 -145.798 418.71 -179.565C501.594 -213.331 470.571 -185.578 562.715 -179.565C654.86 -173.552 630.319 -164.3 703.479 -124.058C776.639 -83.8157 737.281 -106.018 771.083 -38.4853C804.885 29.0479 792.383 22.5721 795.624 105.37C798.865 188.167 780.344 181.691 771.083 233.96C761.822 286.229 752.561 270.502 737.281 313.519C722.001 356.537 712.74 359.313 685.421 402.33C658.101 445.348 657.638 432.859 599.296 487.903C540.953 542.947 544.194 487.903 489.092 518.432C433.991 548.96 427.971 518.432 366.387 518.432C304.803 518.432 326.566 500.392 305.266 487.903C283.966 475.414 262.203 451.361 238.125 432.859Z" fill="#93C5FD"/>
<path d="M1004.22 1306.57C985.424 1317.37 932.391 1231.4 908.224 1187.07C880.724 1146.4 823.724 1054.47 815.724 1012.07C805.724 959.071 809.224 916.071 795.724 826.571C782.224 737.071 792.724 677.571 795.724 492.571C798.724 307.571 802.724 406.571 871.724 300.571C940.724 194.571 941.224 274.071 1020.72 300.571C1100.22 327.071 1047.22 350.071 1073.72 406.571C1100.22 463.071 908.224 519.071 941.224 598.071C974.224 677.071 958.224 648.071 1123.22 677.571C1146.22 614.571 1126.72 648.071 1149.72 562.071C1172.72 476.071 1163.22 522.071 1216.22 492.571C1269.22 463.071 1292.22 499.071 1368.22 648.071C1444.22 797.071 1328.72 704.071 1292.22 790.071C1255.72 876.071 1259.22 849.571 1235.72 926.071C1212.22 1002.57 1192.72 985.571 1235.72 1065.07C1278.72 1144.57 1255.72 1114.57 1259.22 1217.07C1262.72 1319.57 1232.72 1250.07 1192.72 1270.07C1152.72 1290.07 1126.72 1253.57 1073.72 1270.07C1020.72 1286.57 1027.72 1293.07 1004.22 1306.57Z" fill="#34D399"/>
<path d="M130.673 446.681C131.953 420.203 280.592 417.975 354.751 420.17L384.725 418.9C441.682 408.812 565.682 392.815 606.026 409.521C656.455 430.405 649.707 424.685 714.747 471.474C779.786 518.262 790.53 464.759 873.456 461.245L1081.27 452.438C1183.68 448.098 1187.87 464.435 1281.36 556.559C1374.84 648.684 1204.6 622.869 1088.7 627.78C972.804 632.692 1055.73 629.178 971.776 679.277C887.822 729.377 909.531 698.43 708.635 716.953C507.739 735.475 514.965 681.621 444.278 655.09C373.592 628.559 413.183 629.884 363.579 628.483C313.975 627.082 266.84 613.065 176.649 586.86C86.4589 560.656 129.073 479.779 130.673 446.681Z" fill="#FB923C"/>
<g style="mix-blend-mode:color-burn" opacity="0.35" filter="url(#filter1_f_1163_1577)">
<path d="M1331.87 698.139C1355.95 716.641 1390.22 762.434 1405.5 817.478L1418 826.729C1413.83 862.5 1405.5 941.998 1405.5 973.822L1405.5 1025.63C1405.5 1044.13 1405.5 1074.66 1264.73 1255.06C1215.65 1288.36 1234.17 1276.8 1151.29 1310.56C1068.41 1344.33 1099.43 1316.58 1007.28 1310.56C915.14 1304.55 939.681 1295.3 866.521 1255.06C793.361 1214.81 832.719 1237.02 798.917 1169.48C765.115 1101.95 777.617 1108.43 774.376 1025.63C771.135 942.831 789.656 949.307 798.917 897.038C808.178 844.769 817.439 860.496 832.719 817.478C847.999 774.461 857.26 771.685 884.579 728.668C911.899 685.65 912.362 698.139 970.704 643.095C1029.05 588.051 1025.81 643.095 1080.91 612.566C1136.01 582.038 1142.03 612.566 1203.61 612.566C1265.2 612.566 1243.43 630.606 1264.73 643.095C1286.03 655.584 1307.8 679.637 1331.87 698.139Z" fill="#93C5FD"/>
<path d="M89.9274 452.392C84.5615 433.093 173.645 405.29 218.857 393.802C261.551 378.49 356.883 348.502 396.666 351.042C446.395 354.217 484.084 367.188 567.285 375.581C650.486 383.974 701.343 406.986 866.253 451.998C1031.16 497.01 941.631 477.94 1020.73 563.955C1099.82 649.97 1062.64 612.744 1020.73 677.843C978.817 742.941 990.104 746.666 966.604 746.666C947.104 746.666 886.901 761.818 866.253 764.843C845.604 767.867 889.105 784.219 857.604 796.843C812.105 808.719 821.104 797.843 798.104 807.343C787.465 811.737 755.766 774.203 770.045 828.393C784.325 882.583 746.839 894.934 596.079 928.873C445.319 962.811 554.99 880.704 486.361 828.356C417.732 776.008 440.652 785.204 377.552 746.666C314.453 708.128 334.131 694.563 253.132 714.864C172.132 735.165 204.248 721.441 111.698 701.123C19.148 680.804 88.2222 669.852 79.4716 629.472C70.7211 589.091 109.341 574.169 106.698 522.953C104.055 471.737 96.6348 476.516 89.9274 452.392Z" fill="#34D399"/>
<path d="M109.89 387.022C111.529 360.564 260.184 360.352 334.307 363.553L364.295 362.69C421.384 353.376 545.59 339.062 585.703 356.315C635.845 377.881 629.175 372.07 693.573 419.737C757.972 467.403 769.441 414.051 852.407 411.662L1060.32 405.675C1162.78 402.725 1166.75 419.118 1258.98 512.502C1351.2 605.886 1181.32 577.764 1065.37 581.103C949.42 584.441 1032.39 582.052 947.759 631.008C863.133 679.964 885.26 649.315 684.132 665.11C483.003 680.905 490.959 627.154 420.639 599.666C350.319 572.179 389.889 574.041 340.308 571.967C290.728 569.893 243.787 555.238 153.96 527.812C64.1335 500.386 107.841 420.095 109.89 387.022Z" fill="#FB923C"/>
</g>
</g>
<defs>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="0.355556" height="0.5">
<use xlink:href="#image0_847_732" transform="scale(0.000347222 0.000488281)"/>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="0.177778" height="0.25">
<use xlink:href="#image0_1163_1577" transform="scale(0.000173611 0.000244141)"/>
</pattern>
<filter id="filter0_f_847_732" x="-286.884" y="-242.267" width="1980.68" height="1631.39" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<filter id="filter0_f_1163_1577" x="-275.793" y="-560.664" width="1983.5" height="1457.53" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="145" result="effect1_foregroundBlur_847_732"/>
<feGaussianBlur stdDeviation="145" result="effect1_foregroundBlur_1163_1577"/>
</filter>
<filter id="filter1_f_847_732" x="-170.772" y="-486" width="1854.36" height="2083.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<filter id="filter1_f_1163_1577" x="-227.136" y="58.2273" width="1935.14" height="1558.77" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="145" result="effect1_foregroundBlur_847_732"/>
<feGaussianBlur stdDeviation="145" result="effect1_foregroundBlur_1163_1577"/>
</filter>
<clipPath id="clip0_847_732">
<rect width="1440" height="1024" fill="white"/>
<clipPath id="clip0_1163_1577">
<rect width="1440" height="1024" fill="white" transform="translate(1440 1024) rotate(-180)"/>
</clipPath>
<image id="image0_847_732" width="1024" height="1024" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAYAAAB/HSuDAAAAAXNSR0IArs4c6QAAIABJREFUeF7s3WW8Nd2yHfQ5cHfXECB4cHe9uAd3d4IEDQRIcHcJ7hLcnQAJ7u7u7s7Ib1f3/5zZnf2859wP957zYb5f1rufvfZa3TVr1qweY1RV2v6j6/rvL7lff5/79Te7X3/Z+/VfuV9/jI/XJP/Ax2vb3+T+9//rfv0r7t//ePfvf6/75z/j/vkPvd/3292vf+r9+z/r/v0fd//7P3K//jz36199v/7a9+uvcb/+W/frz3G//t/36w+4X3/R+/P/gvvzf8L73//A+/U3vV+/x/2+3D/PS9t/7P75R7tff/z79U+6X//V++/+2fv9P//987/w+pyf5f73f/d+n+v9++/3/dv36y90v+8nuN/3S9z//nPdr+wx97XW+svu13/5fv0T7tf/4361fvP7JL/A/bl/6f3zb3P//GffP//u98/zPUlm3dv+WPfnWYe/+/7557xff+z71Xp8z/vnf32/r7XW/3D//APv1z/mfv2l7tdf6379l+7v/4nv7/8j7n//7e/Xv/J+/fXu1//2fv98Ttsf5XVdP9X98+9wv/7g+5V9/4377/+5++9/vvv3f+79+pffr9/3fv1d7tff8X79H++//93uv/d+/jT7K8k/dL9/XtqO36y1fvr79S+6X//P+/Vvvv/OOrieH3L/nv3///vnv/N+/QXv11/xfv1B9+v/dr/+0/er9fpP7p9/q/v1x71f/6P7dfxxrfVz368/zv36G9yvP/V9nRM/2vr7P/3+vXWf9Uwy69DW9f1M9/t+/fvV/vf57PH73r8f/11rzT5LMtfd9s9/3e/3u3/mL7/C/f6JM21nnyQZ/23769w//633z/zRfv1V7s/7/V+vf9X9s3j3q91/b91/2/tnce+3uL9nrqftxKe11p93v/6U9+9nn7X9ne5/t26/+ste4ydrrT/g/jtxbv6x7R9///7fv1/tO/uK//yG9+//3vtVPPuN75993h99//w/36+9X/+++/v/xc/en2Tif9vvc//+H75f+f+cK2stcfA/eH3OX3j//Dfdr/Nzkp/m/lx+xz72CT/8p+6/sw//hvvn/+X+HOv2s93/Puu51vpT7lf78Xu/rkscH/uvtf7E+3X8NcnE37a/9/2z65m3tf0Z7/eL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 truncated
<image id="image0_1163_1577" width="1024" height="1024" xlink:href="data:image/png;base64,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 truncated
</defs>
</svg>
</svg>

Before

Width:  |  Height:  |  Size: 744 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.0105 1.69682C13.2058 1.50155 13.2058 1.18497 13.0105 0.989708C12.8153 0.794446 12.4987 0.794446 12.3034 0.989708L7.00016 6.29297L1.6969 0.989708C1.50163 0.794446 1.18505 0.794446 0.989788 0.989708C0.794526 1.18497 0.794526 1.50155 0.989788 1.69682L6.29305 7.00008L0.989708 12.3034C0.794446 12.4987 0.794446 12.8153 0.989708 13.0105C1.18497 13.2058 1.50155 13.2058 1.69681 13.0105L7.00016 7.70718L12.3035 13.0105C12.4988 13.2058 12.8153 13.2058 13.0106 13.0105C13.2059 12.8153 13.2059 12.4987 13.0106 12.3034L7.70726 7.00008L13.0105 1.69682Z" fill="#1F2937"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.636235 0.636155C1.02676 0.245631 1.65992 0.245631 2.05045 0.636155L7.00016 5.58586L11.9499 0.636155C12.3404 0.245631 12.9736 0.245631 13.3641 0.636155C13.7546 1.02668 13.7546 1.65984 13.3641 2.05037L8.41437 7.00008L13.3642 11.9499C13.7547 12.3404 13.7547 12.9736 13.3642 13.3641C12.9736 13.7546 12.3405 13.7546 11.9499 13.3641L7.00016 8.41429L2.05037 13.3641C1.65984 13.7546 1.02668 13.7546 0.636155 13.3641C0.245632 12.9736 0.24563 12.3404 0.636154 11.9499L5.58594 7.00008L0.636235 2.05037C0.245711 1.65984 0.245711 1.02668 0.636235 0.636155Z" fill="#1F2937"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="16" height="13" viewBox="0 0 16 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.5501 1.03713C12.513 0.549805 11.4071 0.199929 10.2451 0C10.1014 0.256159 9.93891 0.599787 9.8202 0.874689C8.58939 0.687256 7.37107 0.687256 6.16525 0.874689C6.05279 0.599787 5.87785 0.256159 5.7404 0C4.58456 0.199929 3.47246 0.556053 2.43533 1.03713C0.348566 4.19226 -0.213734 7.27242 0.0674159 10.3088C1.45442 11.346 2.7977 11.9707 4.11598 12.3831C4.44086 11.9333 4.73451 11.4584 4.98442 10.9586C4.50959 10.7774 4.0535 10.5525 3.6224 10.2963C3.73486 10.2089 3.84732 10.1214 3.95978 10.0339C6.5901 11.2648 9.45158 11.2648 12.0507 10.0339C12.1631 10.1277 12.2693 10.2151 12.388 10.2963C11.9569 10.5588 11.4946 10.7837 11.0198 10.9649C11.2697 11.4647 11.5571 11.9458 11.8882 12.3894C13.2065 11.977 14.5498 11.3522 15.9368 10.3151C16.2554 6.79134 15.3557 3.74242 13.5501 1.03713ZM5.34054 8.44075C4.55332 8.44075 3.90355 7.70351 3.90355 6.80383C3.90355 5.90415 4.53458 5.16692 5.34054 5.16692C6.14651 5.16692 6.79003 5.90415 6.77753 6.80383C6.77753 7.70351 6.14026 8.44075 5.34054 8.44075ZM10.6512 8.44075C9.86394 8.44075 9.21417 7.70351 9.21417 6.80383C9.21417 5.90415 9.84519 5.16692 10.6512 5.16692C11.4571 5.16692 12.1006 5.90415 12.0881 6.80383C12.0881 7.70351 11.4571 8.44075 10.6512 8.44075Z" fill="#1F2937"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.00016 0.333496C3.31816 0.333496 0.333496 3.32283 0.333496 7.0115C0.333496 9.9615 2.2435 12.4648 4.89283 13.3475C5.22616 13.4088 5.3475 13.2028 5.3475 13.0255C5.3475 12.8675 5.34216 12.4468 5.33883 11.8902C3.48416 12.2935 3.09283 10.9948 3.09283 10.9948C2.79016 10.2228 2.35283 10.0175 2.35283 10.0175C1.7475 9.60416 2.39883 9.61216 2.39883 9.61216C3.0675 9.65883 3.4195 10.3002 3.4195 10.3002C4.01416 11.3202 4.98016 11.0255 5.3595 10.8548C5.42083 10.4235 5.59283 10.1295 5.7835 9.96283C4.3035 9.79416 2.74683 9.22083 2.74683 6.66216C2.74683 5.9335 3.00683 5.33683 3.43283 4.87016C3.36416 4.7015 3.1355 4.02216 3.49816 3.1035C3.49816 3.1035 4.05816 2.9235 5.3315 3.7875C5.87534 3.63917 6.43645 3.56362 7.00016 3.56283C7.56683 3.5655 8.13683 3.6395 8.6695 3.7875C9.94216 2.9235 10.5008 3.10283 10.5008 3.10283C10.8648 4.02216 10.6355 4.7015 10.5675 4.87016C10.9942 5.33683 11.2528 5.9335 11.2528 6.66216C11.2528 9.2275 9.6935 9.79216 8.20883 9.9575C8.44816 10.1635 8.66083 10.5708 8.66083 11.1942C8.66083 12.0862 8.65283 12.8068 8.65283 13.0255C8.65283 13.2042 8.77283 13.4122 9.1115 13.3468C10.439 12.9016 11.5931 12.0504 12.4105 10.9135C13.2279 9.77669 13.6674 8.41171 13.6668 7.0115C13.6668 3.32283 10.6815 0.333496 7.00016 0.333496Z" fill="#1F2937"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 13.125C3.61726 13.125 0.875 10.3827 0.875 7C0.875 3.61726 3.61726 0.875 7 0.875C10.3827 0.875 13.125 3.61726 13.125 7C13.125 10.3827 10.3827 13.125 7 13.125ZM7 14C10.866 14 14 10.866 14 7C14 3.13401 10.866 0 7 0C3.13401 0 0 3.13401 0 7C0 10.866 3.13401 14 7 14Z" fill="#6B7280"/>
<path d="M7.81437 5.7644L5.80973 6.01562L5.73795 6.34888L6.13272 6.42065C6.38907 6.48218 6.44034 6.57446 6.38395 6.83081L5.73795 9.86597C5.56876 10.6504 5.83023 11.0195 6.44547 11.0195C6.92228 11.0195 7.47599 10.7991 7.72721 10.4966L7.80411 10.1326C7.6298 10.2864 7.37345 10.3479 7.20426 10.3479C6.96329 10.3479 6.87613 10.1787 6.93766 9.88135L7.81437 5.7644Z" fill="#6B7280"/>
<path d="M7.875 3.9375C7.875 4.42075 7.48325 4.8125 7 4.8125C6.51675 4.8125 6.125 4.42075 6.125 3.9375C6.125 3.45425 6.51675 3.0625 7 3.0625C7.48325 3.0625 7.875 3.45425 7.875 3.9375Z" fill="#6B7280"/>
</svg>

After

Width:  |  Height:  |  Size: 975 B

+5
View File
@@ -0,0 +1,5 @@
<svg width="24" height="16" viewBox="0 0 24 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.32352 0C3.37332 0 4.26027 0.697928 4.54816 1.65467C5.65322 1.73319 6.71174 2.21301 7.494 3.00109L11.7165 7.22065C11.731 7.23519 11.7485 7.24973 11.763 7.26718L16.3926 11.8939C16.9567 12.4609 17.7361 12.7837 18.5329 12.7837C18.5358 12.7837 18.5387 12.7837 18.5416 12.7837H18.7975C19.1465 11.9433 19.9753 11.353 20.9437 11.353C22.2261 11.353 23.2672 12.394 23.2672 13.6765C23.2672 14.9589 22.2261 16 20.9437 16C19.9084 16 19.036 15.3253 18.7336 14.3889H18.5445C18.5416 14.3889 18.5358 14.3889 18.5329 14.3889C17.3144 14.3889 16.1221 13.8946 15.2643 13.0309L11.0244 8.79099C11.0069 8.77644 10.9866 8.7619 10.9691 8.74446L6.35405 4.12941C5.84806 3.6205 5.16467 3.30934 4.44929 3.25118C4.0916 4.07125 3.27445 4.64413 2.32061 4.64413C1.04108 4.64413 0 3.60596 0 2.32352C0 1.04108 1.04108 0 2.32352 0Z" fill="#F9FAFB"/>
<path d="M2.32352 11.3531C3.29189 11.3531 4.11778 11.9434 4.46965 12.7838H4.72555C4.72846 12.7838 4.73137 12.7838 4.73428 12.7838C5.53399 12.7838 6.31334 12.461 6.87459 11.894L9.63722 9.13135L10.7684 10.2626L8.00291 13.0281C7.14213 13.8918 5.95274 14.3862 4.73428 14.3862C4.73137 14.3862 4.72555 14.3862 4.72265 14.3862H4.53362C4.2341 15.3196 3.35878 15.9972 2.32352 15.9972C1.04108 15.9972 0 14.9561 0 13.6737C0 12.3913 1.04108 11.3531 2.32352 11.3531Z" fill="#F9FAFB"/>
<path d="M20.9405 4.64413C19.9722 4.64413 19.1463 4.0538 18.7944 3.21338H18.5385C18.5356 3.21338 18.5327 3.21338 18.5298 3.21338C17.7301 3.21338 16.9507 3.53617 16.3895 4.10324L13.6268 6.86587L12.4956 5.73464L15.2611 2.9691C16.1219 2.10542 17.3113 1.61105 18.5298 1.61105C18.5327 1.61105 18.5385 1.61105 18.5414 1.61105H18.7304C19.0329 0.674664 19.9082 0 20.9405 0C22.223 0 23.2641 1.04108 23.2641 2.32352C23.2641 3.60596 22.223 4.64413 20.9405 4.64413Z" fill="#F9FAFB"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+2 -1
View File
@@ -4,8 +4,9 @@
@tailwind utilities;
#app {
width: 100%;
margin: 0 auto;
padding: 2rem 4rem;
padding: 2rem;
height: fit-content;
min-height: 100vh;
background-image: url( './bg.svg' );
+3
View File
@@ -0,0 +1,3 @@
<svg width="14" height="12" viewBox="0 0 14 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.52683 11.5021C9.55816 11.5021 12.3102 7.33344 12.3102 3.71877C12.3102 3.6001 12.3102 3.4821 12.3022 3.36544C12.8376 2.97779 13.2997 2.49784 13.6668 1.9481C13.1675 2.16944 12.6379 2.31461 12.0955 2.37877C12.6666 2.03681 13.094 1.499 13.2982 0.865436C12.7613 1.18403 12.174 1.40859 11.5615 1.52944C11.1491 1.09061 10.6035 0.799992 10.0092 0.702573C9.41498 0.605153 8.80517 0.706369 8.27424 0.990549C7.74331 1.27473 7.32088 1.72602 7.07236 2.27454C6.82383 2.82307 6.76307 3.43823 6.8995 4.02477C5.81189 3.97026 4.7479 3.68765 3.77659 3.19528C2.80529 2.70291 1.94838 2.01179 1.2615 1.16677C0.911708 1.7689 0.804555 2.48172 0.961853 3.16008C1.11915 3.83844 1.52907 4.43135 2.10816 4.8181C1.673 4.80551 1.24725 4.68844 0.866829 4.47677V4.51144C0.867089 5.14297 1.08576 5.75497 1.48576 6.24367C1.88576 6.73238 2.44247 7.06769 3.0615 7.19277C2.6587 7.30258 2.23609 7.31854 1.82616 7.23944C2.00094 7.78309 2.34128 8.2585 2.79958 8.59918C3.25788 8.93986 3.81121 9.12875 4.38216 9.13944C3.81491 9.58515 3.16535 9.91466 2.47065 10.1091C1.77594 10.3036 1.04971 10.3592 0.333496 10.2728C1.58457 11.0757 3.04029 11.5015 4.52683 11.4994" fill="#1F2937"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+6 -12
View File
@@ -33,7 +33,7 @@ describe("addresses.ts functions", () => {
const etherStore = useEtherStore();
etherStore.setNetworkName(NetworkEnum.ethereum);
expect(getTokenAddress()).toBe(
"0x294003F602c321627152c6b7DED3EAb5bEa853Ee"
"0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00"
);
});
@@ -41,13 +41,13 @@ describe("addresses.ts functions", () => {
const etherStore = useEtherStore();
etherStore.setNetworkName(NetworkEnum.polygon);
expect(getTokenAddress()).toBe(
"0x294003F602c321627152c6b7DED3EAb5bEa853Ee"
"0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29"
);
});
it("getTokenAddress Default", () => {
expect(getTokenAddress()).toBe(
"0x294003F602c321627152c6b7DED3EAb5bEa853Ee"
"0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00"
);
});
@@ -55,7 +55,7 @@ describe("addresses.ts functions", () => {
const etherStore = useEtherStore();
etherStore.setNetworkName(NetworkEnum.ethereum);
expect(getP2PixAddress()).toBe(
"0x5f3EFA9A90532914545CEf527C530658af87e196"
"0x2414817FF64A114d91eCFA16a834d3fCf69103d4"
);
});
@@ -63,13 +63,13 @@ describe("addresses.ts functions", () => {
const etherStore = useEtherStore();
etherStore.setNetworkName(NetworkEnum.polygon);
expect(getP2PixAddress()).toBe(
"0x5f3EFA9A90532914545CEf527C530658af87e196"
"0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00"
);
});
it("getP2PixAddress Default", () => {
expect(getP2PixAddress()).toBe(
"0x5f3EFA9A90532914545CEf527C530658af87e196"
"0x2414817FF64A114d91eCFA16a834d3fCf69103d4"
);
});
@@ -102,9 +102,3 @@ describe("addresses.ts functions", () => {
expect(isPossibleNetwork("0x55")).toBe(false);
});
});
describe("addresses.ts Unset Store", () => {
it("getProviderUrl Unset", () => {
expect(getProviderUrl()).toBe(undefined);
});
});
+8 -8
View File
@@ -1,26 +1,26 @@
import { useEtherStore } from "@/store/ether";
import { NetworkEnum } from "@/model/NetworkEnum";
const getTokenAddress = (): string => {
const getTokenAddress = (network?: NetworkEnum): string => {
const etherStore = useEtherStore();
const possibleTokenAddresses: { [key: string]: string } = {
Ethereum: "0x294003F602c321627152c6b7DED3EAb5bEa853Ee",
Polygon: "0x294003F602c321627152c6b7DED3EAb5bEa853Ee",
Ethereum: "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00",
Polygon: "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29",
};
return possibleTokenAddresses[etherStore.networkName];
return possibleTokenAddresses[network ? network : etherStore.networkName];
};
const getP2PixAddress = (): string => {
const getP2PixAddress = (network?: NetworkEnum): string => {
const etherStore = useEtherStore();
const possibleP2PixAddresses: { [key: string]: string } = {
Ethereum: "0x5f3EFA9A90532914545CEf527C530658af87e196",
Polygon: "0x5f3EFA9A90532914545CEf527C530658af87e196",
Ethereum: "0x2414817FF64A114d91eCFA16a834d3fCf69103d4",
Polygon: "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00",
};
return possibleP2PixAddresses[etherStore.networkName];
return possibleP2PixAddresses[network ? network : etherStore.networkName];
};
const getProviderUrl = (): string => {
+16 -10
View File
@@ -1,15 +1,16 @@
import { useEtherStore } from "@/store/ether";
import { getContract, getProvider } from "./provider";
import { getP2PixAddress } from "./addresses";
import { getP2PixAddress, getTokenAddress } from "./addresses";
import p2pix from "../utils/smart_contract_files/P2PIX.json";
import p2pix from "@/utils/smart_contract_files/P2PIX.json";
import { BigNumber, ethers } from "ethers";
import { parseEther } from "ethers/lib/utils";
const addLock = async (
depositId: BigNumber,
seller: string,
token: string,
amount: number
): Promise<string> => {
const etherStore = useEtherStore();
@@ -17,7 +18,8 @@ const addLock = async (
const p2pContract = getContract();
const lock = await p2pContract.lock(
depositId, // BigNumber
seller,
token,
etherStore.walletAddress, // String "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (Example)
ethers.constants.AddressZero, // String "0x0000000000000000000000000000000000000000"
0,
@@ -29,11 +31,11 @@ const addLock = async (
const lock_rec = await lock.wait();
const [t] = lock_rec.events;
return t.args.lockID;
return String(t.args.lockID);
};
const releaseLock = async (
pixKey: string,
pixKey: number,
amount: number,
e2eId: string,
lockId: string
@@ -43,7 +45,7 @@ const releaseLock = async (
);
const messageToSign = ethers.utils.solidityKeccak256(
["string", "uint256", "bytes32"],
["uint160", "uint256", "bytes32"],
[
pixKey,
parseEther(String(amount)),
@@ -61,7 +63,7 @@ const releaseLock = async (
const p2pContract = new ethers.Contract(getP2PixAddress(), p2pix.abi, signer);
const release = await p2pContract.release(
lockId,
BigNumber.from(lockId),
ethers.constants.AddressZero,
ethers.utils.formatBytes32String(e2eId),
sig.r,
@@ -82,10 +84,14 @@ const cancelDeposit = async (depositId: BigNumber): Promise<any> => {
return cancel;
};
const withdrawDeposit = async (depositId: BigNumber): Promise<any> => {
const withdrawDeposit = async (amount: string): Promise<any> => {
const contract = getContract();
const withdraw = await contract.withdraw(depositId, []);
const withdraw = await contract.withdraw(
getTokenAddress(),
parseEther(String(amount)),
[]
);
await withdraw.wait();
return withdraw;
+62 -20
View File
@@ -1,14 +1,17 @@
import { useEtherStore } from "@/store/ether";
import { Contract, ethers } from "ethers";
import p2pix from "../utils/smart_contract_files/P2PIX.json";
import p2pix from "@/utils/smart_contract_files/P2PIX.json";
import { formatEther } from "ethers/lib/utils";
import { getContract } from "./provider";
import type { ValidDeposit } from "@/model/ValidDeposit";
import { getP2PixAddress, getTokenAddress } from "./addresses";
import { NetworkEnum } from "@/model/NetworkEnum";
import type { UnreleasedLock } from "@/model/UnreleasedLock";
import type { Pix } from "@/model/Pix";
const getNetworksLiquidity = async (): Promise<void> => {
const etherStore = useEtherStore();
console.log("Loading events");
const goerliProvider = new ethers.providers.JsonRpcProvider(
import.meta.env.VITE_GOERLI_API_URL,
@@ -20,28 +23,34 @@ const getNetworksLiquidity = async (): Promise<void> => {
); // mumbai provider
const p2pContractGoerli = new ethers.Contract(
"0x5f3EFA9A90532914545CEf527C530658af87e196",
getP2PixAddress(NetworkEnum.ethereum),
p2pix.abi,
goerliProvider
);
const p2pContractMumbai = new ethers.Contract(
"0x5f3EFA9A90532914545CEf527C530658af87e196",
getP2PixAddress(NetworkEnum.polygon),
p2pix.abi,
mumbaiProvider
);
const depositListGoerli = await getValidDeposits(p2pContractGoerli);
etherStore.setLoadingNetworkLiquidity(true);
const depositListGoerli = await getValidDeposits(
getTokenAddress(NetworkEnum.ethereum),
p2pContractGoerli
);
const depositListMumbai = await getValidDeposits(p2pContractMumbai);
const depositListMumbai = await getValidDeposits(
getTokenAddress(NetworkEnum.polygon),
p2pContractMumbai
);
etherStore.setDepositsValidListGoerli(depositListGoerli);
console.log(depositListGoerli);
etherStore.setDepositsValidListMumbai(depositListMumbai);
console.log(depositListMumbai);
etherStore.setLoadingNetworkLiquidity(false);
};
const getValidDeposits = async (
token: string,
contract?: Contract
): Promise<ValidDeposit[]> => {
let p2pContract: Contract;
@@ -56,29 +65,62 @@ const getValidDeposits = async (
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
if (!contract) p2pContract = getContract(); // get metamask provider contract
const depositList: { [key: string]: ValidDeposit } = {};
const depositList = await Promise.all(
await Promise.all(
eventsDeposits.map(async (deposit) => {
const mappedDeposit = await p2pContract.mapDeposits(
deposit.args?.depositID
// Get liquidity only for the selected token
if (deposit.args?.token != token) return null;
const mappedBalance = await p2pContract.getBalance(
deposit.args?.seller,
token
);
const mappedPixTarget = await p2pContract.getPixTarget(
deposit.args?.seller,
token
);
let validDeposit: ValidDeposit | null = null;
if (mappedDeposit.valid) {
if (mappedBalance._hex) {
validDeposit = {
token: token,
blockNumber: deposit.blockNumber,
depositID: deposit.args?.depositID,
remaining: Number(formatEther(mappedDeposit.remaining)),
seller: mappedDeposit.seller,
pixKey: mappedDeposit.pixTarget,
remaining: Number(formatEther(mappedBalance._hex)),
seller: deposit.args?.seller,
pixKey: Number(mappedPixTarget._hex),
};
}
return validDeposit;
if (validDeposit)
depositList[deposit.args?.seller + token] = validDeposit;
})
);
return depositList.filter((deposit) => deposit) as ValidDeposit[];
return Object.values(depositList);
};
export { getValidDeposits, getNetworksLiquidity };
const getUnreleasedLockById = async (
lockID: string
): Promise<UnreleasedLock> => {
const p2pContract = getContract();
const pixData: Pix = {
pixKey: "",
};
const lock = await p2pContract.mapLocks(lockID);
const pixTarget = lock.pixTarget;
const amount = formatEther(lock?.amount);
pixData.pixKey = String(Number(pixTarget));
pixData.value = Number(amount);
return {
lockID: lockID,
pix: pixData,
};
};
export { getValidDeposits, getNetworksLiquidity, getUnreleasedLockById };
+1 -1
View File
@@ -1,6 +1,6 @@
import { useEtherStore } from "@/store/ether";
import p2pix from "../utils/smart_contract_files/P2PIX.json";
import p2pix from "@/utils/smart_contract_files/P2PIX.json";
import { updateWalletStatus } from "./wallet";
import {
+1 -1
View File
@@ -22,7 +22,6 @@ const approveTokens = async (tokenQty: string): Promise<any> => {
);
await apprv.wait();
console.log(apprv);
return apprv;
};
@@ -33,6 +32,7 @@ const addDeposit = async (tokenQty: string, pixKey: string): Promise<any> => {
getTokenAddress(),
parseEther(tokenQty),
pixKey,
true,
ethers.utils.formatBytes32String("")
);
+156 -9
View File
@@ -3,12 +3,16 @@ import { useEtherStore } from "@/store/ether";
import { getContract, getProvider } from "./provider";
import { getTokenAddress, possibleChains } from "./addresses";
import mockToken from "../utils/smart_contract_files/MockToken.json";
import mockToken from "@/utils/smart_contract_files/MockToken.json";
import { ethers, type Event } from "ethers";
import { ethers, type Event, type BigNumber } from "ethers";
import { formatEther } from "ethers/lib/utils";
import { getValidDeposits } from "./events";
import type { ValidDeposit } from "@/model/ValidDeposit";
import type { WalletTransaction } from "@/model/WalletTransaction";
import type { UnreleasedLock } from "@/model/UnreleasedLock";
import type { Pix } from "@/model/Pix";
const updateWalletStatus = async (): Promise<void> => {
const etherStore = useEtherStore();
@@ -35,7 +39,7 @@ const updateWalletStatus = async (): Promise<void> => {
const listValidDepositTransactionsByWalletAddress = async (
walletAddress: string
): Promise<ValidDeposit[]> => {
const walletDeposits = await getValidDeposits();
const walletDeposits = await getValidDeposits(getTokenAddress());
if (walletDeposits) {
return walletDeposits
@@ -48,10 +52,50 @@ const listValidDepositTransactionsByWalletAddress = async (
return [];
};
const getLockStatus = async (id: [BigNumber]): Promise<number> => {
const p2pContract = getContract();
const res = await p2pContract.getLocksStatus([id]);
return res[1][0];
};
const filterLockStatus = async (
transactions: Event[]
): Promise<WalletTransaction[]> => {
const txs = await Promise.all(
transactions.map(async (transaction) => {
const tx: WalletTransaction = {
token: transaction.args?.token ? transaction.args?.token : "",
blockNumber: transaction.blockNumber ? transaction.blockNumber : -1,
amount: transaction.args?.amount
? Number(formatEther(transaction.args?.amount))
: -1,
seller: transaction.args?.seller ? transaction.args?.seller : "",
buyer: transaction.args?.buyer ? transaction.args?.buyer : "",
event: transaction.event ? transaction.event : "",
lockStatus:
transaction.event == "LockAdded"
? await getLockStatus(transaction.args?.lockID)
: -1,
transactionHash: transaction.transactionHash
? transaction.transactionHash
: "",
transactionID: transaction.args?.lockID
? String(transaction.args?.lockID)
: "",
};
return tx;
})
);
return txs;
};
const listAllTransactionByWalletAddress = async (
walletAddress: string
): Promise<Event[]> => {
const p2pContract = getContract();
): Promise<WalletTransaction[]> => {
const p2pContract = getContract(true);
const filterDeposits = p2pContract.filters.DepositAdded([walletAddress]);
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
@@ -64,11 +108,25 @@ const listAllTransactionByWalletAddress = async (
filterReleasedLocks
);
return [...eventsDeposits, ...eventsAddedLocks, ...eventsReleasedLocks].sort(
(a, b) => {
return b.blockNumber - a.blockNumber;
}
const filterWithdrawnDeposits = p2pContract.filters.DepositWithdrawn([
walletAddress,
]);
const eventsWithdrawnDeposits = await p2pContract.queryFilter(
filterWithdrawnDeposits
);
const lockStatusFiltered = await filterLockStatus(
[
...eventsDeposits,
...eventsAddedLocks,
...eventsReleasedLocks,
...eventsWithdrawnDeposits,
].sort((a, b) => {
return b.blockNumber - a.blockNumber;
})
);
return lockStatusFiltered;
};
// get wallet's release transactions
@@ -87,9 +145,98 @@ const listReleaseTransactionByWalletAddress = async (
});
};
const listLockTransactionByWalletAddress = async (
walletAddress: string
): Promise<Event[]> => {
const p2pContract = getContract(true);
const filterAddedLocks = p2pContract.filters.LockAdded([walletAddress]);
const eventsReleasedLocks = await p2pContract.queryFilter(filterAddedLocks);
return eventsReleasedLocks.sort((a, b) => {
return b.blockNumber - a.blockNumber;
});
};
const listLockTransactionBySellerAddress = async (
sellerAddress: string
): Promise<Event[]> => {
const p2pContract = getContract(true);
const filterAddedLocks = p2pContract.filters.LockAdded();
const eventsReleasedLocks = await p2pContract.queryFilter(filterAddedLocks);
return eventsReleasedLocks.filter((lock) =>
lock.args?.seller
.toHexString()
.substring(3)
.includes(sellerAddress.substring(2).toLowerCase())
);
};
const checkUnreleasedLock = async (
walletAddress: string
): Promise<UnreleasedLock | undefined> => {
const p2pContract = getContract();
const pixData: Pix = {
pixKey: "",
};
const addedLocks = await listLockTransactionByWalletAddress(walletAddress);
const lockStatus = await p2pContract.getLocksStatus(
addedLocks.map((lock) => lock.args?.lockID)
);
const unreleasedLockId = lockStatus[1].findIndex(
(lockStatus: number) => lockStatus == 1
);
if (unreleasedLockId != -1) {
const _lockID = lockStatus[0][unreleasedLockId];
const lock = await p2pContract.mapLocks(_lockID);
const pixTarget = lock.pixTarget;
const amount = formatEther(lock?.amount);
pixData.pixKey = String(Number(pixTarget));
pixData.value = Number(amount);
return {
lockID: _lockID,
pix: pixData,
};
}
};
const getActiveLockAmount = async (walletAddress: string): Promise<number> => {
const p2pContract = getContract();
const lockSeller = await listLockTransactionBySellerAddress(walletAddress);
const lockStatus = await p2pContract.getLocksStatus(
lockSeller.map((lock) => lock.args?.lockID)
);
const activeLockAmount = await lockStatus[1].reduce(
async (sumValue: Promise<number>, currentStatus: number, index: number) => {
const currValue = await sumValue;
let valueToSum = 0;
if (currentStatus == 1) {
const lock = await p2pContract.mapLocks(lockStatus[0][index]);
valueToSum = Number(formatEther(lock?.amount));
}
return currValue + valueToSum;
},
Promise.resolve(0)
);
return activeLockAmount;
};
export {
updateWalletStatus,
listValidDepositTransactionsByWalletAddress,
listAllTransactionByWalletAddress,
listReleaseTransactionByWalletAddress,
checkUnreleasedLock,
getActiveLockAmount,
};
@@ -1,22 +1,87 @@
<script setup lang="ts">
import { withdrawDeposit } from "@/blockchain/buyerMethods";
import {
getActiveLockAmount,
listAllTransactionByWalletAddress,
listValidDepositTransactionsByWalletAddress,
} from "@/blockchain/wallet";
import CustomButton from "@/components/CustomButton/CustomButton.vue";
import ListingComponent from "@/components/ListingComponent/ListingComponent.vue";
import type { Event } from "ethers";
import type { ValidDeposit } from "@/model/ValidDeposit";
import type { WalletTransaction } from "@/model/WalletTransaction";
import { useEtherStore } from "@/store/ether";
import { storeToRefs } from "pinia";
import { onMounted, ref, watch } from "vue";
import ListingComponent from "../ListingComponent/ListingComponent.vue";
// props
const props = defineProps<{
lastWalletReleaseTransactions: Event[];
tokenAmount: number | undefined;
isCurrentStep: boolean;
}>();
const etherStore = useEtherStore();
const { walletAddress } = storeToRefs(etherStore);
const lastWalletTransactions = ref<WalletTransaction[]>([]);
const depositList = ref<ValidDeposit[]>([]);
const activeLockAmount = ref<number>(0);
// methods
const getWalletTransactions = async () => {
etherStore.setLoadingWalletTransactions(true);
if (walletAddress.value) {
const walletDeposits = await listValidDepositTransactionsByWalletAddress(
walletAddress.value
);
const allUserTransactions = await listAllTransactionByWalletAddress(
walletAddress.value
);
activeLockAmount.value = await getActiveLockAmount(walletAddress.value);
if (walletDeposits) {
depositList.value = walletDeposits;
}
if (allUserTransactions) {
lastWalletTransactions.value = allUserTransactions;
}
}
etherStore.setLoadingWalletTransactions(false);
};
const callWithdraw = async (amount: string) => {
if (amount) {
etherStore.setLoadingWalletTransactions(true);
const withdraw = await withdrawDeposit(amount);
if (withdraw) {
console.log("Saque realizado!");
await getWalletTransactions();
} else {
console.log("Não foi possível realizar o saque!");
}
etherStore.setLoadingWalletTransactions(false);
}
};
// Emits
const emit = defineEmits(["makeAnotherTransaction"]);
// observer
watch(props, async (): Promise<void> => {
if (props.isCurrentStep) await getWalletTransactions();
});
onMounted(async () => {
await getWalletTransactions();
});
</script>
<template>
<div class="page">
<div class="text-container">
<span class="text font-extrabold text-5xl max-w-[50rem]"
<span class="text font-extrabold sm:text-5xl text-xl max-w-[50rem]"
>Os tokens já foram transferidos <br />
para a sua carteira!
</span>
@@ -30,15 +95,13 @@ const emit = defineEmits(["makeAnotherTransaction"]);
<p class="text-2xl text-gray-900">{{ props.tokenAmount }} BRZ</p>
</div>
<div class="my-5">
<p>
<b>Não encontrou os tokens? </b>Clique no botão abaixo para <br />
<p class="text-sm">
<b>Não encontrou os tokens? </b><br />Clique no botão abaixo para
<br />
cadastrar o BRZ em sua carteira.
</p>
</div>
<CustomButton
:text="'Cadastrar token na carteira'"
@buttonClicked="() => {}"
/>
<CustomButton :text="'Cadastrar token'" @buttonClicked="() => {}" />
</div>
<button
type="button"
@@ -48,17 +111,18 @@ const emit = defineEmits(["makeAnotherTransaction"]);
Fazer nova transação
</button>
</div>
<div class="text-container mt-16">
<span class="text font-extrabold text-3xl max-w-[50rem]"
>Histórico de compras
</span>
<div
class="flex justify-center mt-8 mb-6 text-white text-xl md:text-3xl font-bold"
>
Gerenciar transações
</div>
<div class="w-full max-w-4xl">
<div class="w-full max-w-xs md:max-w-lg">
<ListingComponent
:walletTransactions="lastWalletReleaseTransactions"
:isManageMode="false"
>
</ListingComponent>
:valid-deposits="depositList"
:wallet-transactions="lastWalletTransactions"
:active-lock-amount="activeLockAmount"
@deposit-withdrawn="callWithdraw"
></ListingComponent>
</div>
</div>
</template>
@@ -77,14 +141,14 @@ p {
}
.text {
@apply text-gray-800 text-center;
@apply text-white text-center;
}
.blur-container-row {
@apply flex flex-row justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-8 w-1/3;
}
.blur-container {
@apply flex flex-col justify-center items-center px-8 py-6 gap-4 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-10 w-auto;
@apply flex w-full max-w-xs md:max-w-lg flex-col justify-center items-center px-8 py-6 gap-4 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-10;
}
.last-release-info {
@@ -99,4 +163,22 @@ input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
.lg-view {
display: inline-block;
}
.sm-view {
display: none;
}
@media screen and (max-width: 500px) {
.lg-view {
display: none;
}
.sm-view {
display: inline-block;
}
}
</style>
@@ -1,32 +1,31 @@
import { shallowMount } from "@vue/test-utils";
import { mount } from "@vue/test-utils";
import BuyConfirmedComponent from "../BuyConfirmedComponent.vue";
import { createPinia, setActivePinia } from "pinia";
import { MockEvents } from "@/model/mock/EventMock";
describe("BuyConfirmedComponent.vue", () => {
describe("BuyConfirmedComponent.vue", async () => {
beforeEach(() => {
setActivePinia(createPinia());
});
const wrapper = shallowMount(BuyConfirmedComponent, {
const wrapper = mount(BuyConfirmedComponent, {
props: {
lastWalletReleaseTransactions: MockEvents,
tokenAmount: 1,
isCurrentStep: false,
},
});
test("Test component Header Text", () => {
expect(wrapper.html()).toContain("Os tokens já foram transferidos");
expect(wrapper.html()).toContain("para a sua carteira!");
});
// test("Test component Header Text", () => {
// expect(wrapper.html()).toContain("Os tokens já foram transferidos");
// expect(wrapper.html()).toContain("para a sua carteira!");
// });
test("Test component Container Text", () => {
expect(wrapper.html()).toContain("Tokens recebidos");
expect(wrapper.html()).toContain("BRZ");
expect(wrapper.html()).toContain("Não encontrou os tokens?");
expect(wrapper.html()).toContain("Clique no botão abaixo para");
expect(wrapper.html()).toContain("cadastrar o BRZ em sua carteira.");
});
// test("Test component Container Text", () => {
// expect(wrapper.html()).toContain("Tokens recebidos");
// expect(wrapper.html()).toContain("BRZ");
// expect(wrapper.html()).toContain("Não encontrou os tokens?");
// expect(wrapper.html()).toContain("Clique no botão abaixo para");
// expect(wrapper.html()).toContain("cadastrar o BRZ em sua carteira.");
// });
test("Test makeAnotherTransactionEmit", async () => {
wrapper.vm.$emit("makeAnotherTransaction");
+154
View File
@@ -0,0 +1,154 @@
<script setup lang="ts">
import { ref } from "vue";
const props = defineProps<{
type: string;
}>();
const alertText = ref<string>("");
const alertPaddingLeft = ref<string>("18rem");
if (props.type === "sell") {
alertPaddingLeft.value = "30%";
} else if (props.type === "buy") {
alertPaddingLeft.value = "30%";
} else if (props.type === "withdraw") {
alertPaddingLeft.value = "40%";
} else if (props.type === "redirect") {
alertPaddingLeft.value = "35%";
}
switch (props.type) {
case "buy":
alertText.value =
"Tudo certo! Os tokens já foram retirados da oferta e estão disponíveis na sua carteira.";
break;
case "sell":
alertText.value =
"Tudo certo! Os tokens já foram reservados e sua oferta está disponível.";
break;
case "redirect":
alertText.value = "Existe uma compra em aberto. Continuar?";
break;
case "withdraw":
alertText.value = "Tudo certo! Saque realizado com sucesso!";
break;
}
</script>
<template>
<div
class="modal-overlay sm:h-12 h-full inset-0 absolute backdrop-blur-sm sm:backdrop-blur-none"
>
<div class="modal px-12 pl-72 text-center sm:flex justify-between hidden">
<div class="flex items-center">
<p class="text-black tracking-tighter leading-tight my-2">
{{ alertText }}
</p>
<button v-if="props.type === 'redirect'" @click="$emit('go-to-lock')">
Sim
</button>
</div>
<img
src="../../assets/closeAlertIcon.svg"
alt="close alert"
class="w-3 cursor-pointer"
@click="$emit('close-alert')"
/>
</div>
<div
class="modal-mobile px-7 py-3 text-center inline-block sm:hidden mt-24 h-48"
v-if="props.type !== 'redirect'"
>
<p class="text-black tracking-tighter leading-tight my-2 text-start mb-4">
{{ alertText }}
</p>
<button
@click="$emit('close-alert')"
class="border-2 border-solid border-amber-400 mt-2"
>
Ok
</button>
</div>
<div
class="modal-mobile px-5 text-center inline-block sm:hidden mt-24 h-40"
v-if="props.type === 'redirect'"
>
<p
class="text-black text-lg tracking-tighter leading-tight my-6 mx-2 text-justify font-semibold"
>
Retomar a última compra?
</p>
<div class="flex justify-around items-center px-2">
<button
@click="$emit('close-alert')"
class="border-2 border-solid border-white-400 mt-2 font-semibold"
>
Não
</button>
<button
@click="$emit('go-to-lock')"
class="border-2 border-solid border-white-400 mt-2 font-semibold"
>
Sim
</button>
</div>
</div>
</div>
</template>
<style scoped>
.modal-overlay {
display: flex !important;
justify-content: center;
width: 100%;
padding-top: 7rem;
z-index: 10;
}
.modal {
background-color: rgba(251, 191, 36, 1);
height: 3rem;
width: 96%;
border-radius: 10px;
align-items: center;
white-space: nowrap;
padding-left: v-bind(alertPaddingLeft);
}
.modal-mobile {
background-color: rgba(251, 191, 36, 1);
/* height: 200px; */
width: 300px;
border-radius: 10px;
}
.close {
cursor: pointer;
}
.close-img {
width: 25px;
}
.check {
width: 150px;
}
h6 {
font-weight: 500;
font-size: 28px;
margin: 20px 0;
}
p {
font-size: 20px;
font-weight: 600;
}
button {
width: 50px;
height: 30px;
color: black;
font-size: 16px;
border-radius: 10px;
border: 2px solid white;
margin-left: 1rem;
}
</style>
+1 -1
View File
@@ -21,6 +21,6 @@ const emit = defineEmits(["buttonClicked"]);
<style scoped>
.button {
@apply rounded-lg w-full text-base font-semibold text-gray-900 py-4 bg-amber-400;
@apply rounded-lg w-full text-base font-semibold text-gray-900 p-4 bg-amber-400;
}
</style>
+113
View File
@@ -0,0 +1,113 @@
<script setup lang="ts">
import { ref } from "vue";
const props = defineProps({
isRedirectModal: Boolean,
});
const modalColor = ref<string>("white");
const modalHeight = ref<string>("250px");
const pFontSize = ref<string>("16px");
if (props.isRedirectModal) {
modalColor.value = "rgba(251, 191, 36, 1)";
modalHeight.value = "150px";
pFontSize.value = "20px";
}
</script>
<template>
<div
class="modal-overlay inset-0 fixed justify-center backdrop-blur-sm sm:backdrop-blur-none"
v-if="!isRedirectModal"
>
<div class="modal px-5 text-center">
<p
class="text-black tracking-tighter leading-tight my-6 mx-2 text-justify"
>
<strong>ATENÇÃO!</strong>
A transação só será processada após inserir o código de autenticação.
Caso contrário não conseguiremos comprovar o seu depósito e não será
possível transferir os tokens para sua carteira.
</p>
<button
@click="$emit('close-modal')"
class="border-2 border-solid border-amber-400 mt-2"
>
Entendi
</button>
</div>
</div>
<div
class="modal-overlay inset-0 fixed justify-center backdrop-blur-sm"
v-if="isRedirectModal"
>
<div class="modal px-5 text-center">
<p
class="text-black text-lg tracking-tighter leading-tight my-6 mx-2 text-justify font-semibold"
>
Retomar a última compra?
</p>
<div class="flex justify-around items-center px-2">
<button
@click="$emit('close-modal')"
class="border-2 border-solid border-white-400 mt-2 font-semibold"
>
Não
</button>
<button
@click="$emit('go-to-lock')"
class="border-2 border-solid border-white-400 mt-2 font-semibold"
>
Sim
</button>
</div>
</div>
</div>
</template>
<style scoped>
.modal-overlay {
display: flex !important;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
}
.modal {
background-color: v-bind(modalColor);
height: v-bind(modalHeight);
width: 300px;
border-radius: 10px;
}
.close {
cursor: pointer;
}
.close-img {
width: 25px;
}
.check {
width: 150px;
}
h6 {
font-weight: 500;
font-size: 28px;
margin: 20px 0;
}
p {
font-size: v-bind(pFontSize);
}
button {
width: 100px;
height: 40px;
color: black;
font-size: 14px;
border-radius: 10px;
}
</style>
@@ -0,0 +1,27 @@
import { mount } from "@vue/test-utils";
import CustomModal from "../CustomModal.vue";
describe("CustomModal test", () => {
test("Test custom modal when receive is redirect modal props as false", () => {
const wrapper = mount(CustomModal, {
props: {
isRedirectModal: false,
},
});
expect(wrapper.html()).toContain("ATENÇÃO!");
expect(wrapper.html()).toContain("Entendi");
});
test("Test custom modal when receive is redirect modal props as true", () => {
const wrapper = mount(CustomModal, {
props: {
isRedirectModal: true,
},
});
expect(wrapper.html()).toContain("Retomar a última compra?");
expect(wrapper.html()).toContain("Não");
expect(wrapper.html()).toContain("Sim");
});
});
@@ -1,26 +1,103 @@
<script setup lang="ts">
import { withdrawDeposit } from "@/blockchain/buyerMethods";
import { NetworkEnum } from "@/model/NetworkEnum";
import type { ValidDeposit } from "@/model/ValidDeposit";
import type { WalletTransaction } from "@/model/WalletTransaction";
import { useEtherStore } from "@/store/ether";
import { formatEther } from "@ethersproject/units";
import type { BigNumber, Event } from "ethers";
import { ref, watch } from "vue";
// props
const props = defineProps<{
walletTransactions: (Event | ValidDeposit)[];
isManageMode: boolean;
}>();
import { storeToRefs } from "pinia";
import { ref, watch, onMounted } from "vue";
import SpinnerComponent from "../SpinnerComponent.vue";
import { decimalCount } from "@/utils/decimalCount";
import { debounce } from "@/utils/debounce";
import { useFloating, arrow, offset, flip, shift } from "@floating-ui/vue";
const etherStore = useEtherStore();
const itemsToShow = ref<(Event | ValidDeposit)[]>([]);
// props
const props = defineProps<{
validDeposits: ValidDeposit[];
walletTransactions: WalletTransaction[];
activeLockAmount: number;
}>();
// Methods
const isValidDeposit = (
deposit: Event | ValidDeposit
): deposit is ValidDeposit => {
return (deposit as ValidDeposit).depositID !== undefined;
const emit = defineEmits(["depositWithdrawn"]);
const { loadingWalletTransactions } = storeToRefs(etherStore);
const remaining = ref<number>(0.0);
const itemsToShow = ref<WalletTransaction[]>([]);
const withdrawAmount = ref<string>("");
const withdrawButtonOpacity = ref<number>(0.6);
const withdrawButtonCursor = ref<string>("not-allowed");
const isCollapsibleOpen = ref<boolean>(false);
const validDecimals = ref<boolean>(true);
const validWithdrawAmount = ref<boolean>(true);
const enableConfirmButton = ref<boolean>(false);
const showInfoTooltip = ref<boolean>(false);
const floatingArrow = ref(null);
const reference = ref<HTMLElement | null>(null);
const floating = ref<HTMLElement | null>(null);
const infoText = ref<HTMLElement | null>(null);
// Debounce methods
const handleInputEvent = (event: any): void => {
const { value } = event.target;
if (decimalCount(String(value)) > 2) {
validDecimals.value = false;
enableConfirmButton.value = false;
return;
}
validDecimals.value = true;
if (value > remaining.value) {
validWithdrawAmount.value = false;
enableConfirmButton.value = false;
return;
}
validWithdrawAmount.value = true;
enableConfirmButton.value = true;
};
const callWithdraw = () => {
emit("depositWithdrawn", withdrawAmount.value);
};
watch(enableConfirmButton, (): void => {
if (!enableConfirmButton.value) {
withdrawButtonOpacity.value = 0.7;
withdrawButtonCursor.value = "not-allowed";
} else {
withdrawButtonOpacity.value = 1;
withdrawButtonCursor.value = "pointer";
}
});
watch(withdrawAmount, (): void => {
if (!withdrawAmount.value || !enableConfirmButton.value) {
withdrawButtonOpacity.value = 0.7;
withdrawButtonCursor.value = "not-allowed";
} else {
withdrawButtonOpacity.value = 1;
withdrawButtonCursor.value = "pointer";
}
});
const getRemaining = (): number => {
if (props.validDeposits instanceof Array) {
// Here we are getting only the first element of the list because
// in this release only the BRL token is being used.
const deposit = props.validDeposits[0];
remaining.value = deposit ? deposit.remaining : 0;
return deposit ? deposit.remaining : 0;
}
return 0;
};
const getExplorer = (): string => {
return etherStore.networkName == NetworkEnum.ethereum
? "Etherscan"
: "Polygonscan";
};
const showInitialItems = (): void => {
@@ -48,17 +125,25 @@ const getEventName = (event: string | undefined): string => {
const possibleEventName: { [key: string]: string } = {
DepositAdded: "Oferta",
LockAdded: "Compra",
LockReleased: "Reserva",
LockAdded: "Reserva",
LockReleased: "Compra",
DepositWithdrawn: "Retirada",
};
return possibleEventName[event];
};
const getAmountFormatted = (amount?: BigNumber): string => {
if (!amount) return "";
return formatEther(amount);
};
onMounted(() => {
useFloating(reference, floating, {
placement: "right",
middleware: [
offset(10),
flip(),
shift(),
arrow({ element: floatingArrow }),
],
});
});
// watch props changes
watch(props, async (): Promise<void> => {
@@ -71,79 +156,184 @@ watch(props, async (): Promise<void> => {
: props.walletTransactions;
});
//emits
const emit = defineEmits(["cancelDeposit", "withdrawDeposit"]);
// initial itemsToShow value
// initial itemsToShow valueb
showInitialItems();
</script>
<template>
<div class="blur-container">
<div class="blur-container" v-if="loadingWalletTransactions">
<SpinnerComponent width="8" height="8"></SpinnerComponent>
</div>
<div class="blur-container" v-if="!loadingWalletTransactions">
<div
class="grid grid-cols-4 grid-flow-row w-full px-6"
v-if="itemsToShow.length != 0"
class="w-full bg-white p-4 sm:p-6 rounded-lg"
v-if="props.validDeposits.length > 0"
>
<span class="text-xs text-gray-50 font-medium justify-self-center"
>Valor</span
>
<span class="text-xs text-gray-50 font-medium justify-self-center"
>Data</span
>
<span class="text-xs text-gray-50 font-medium justify-self-center">{{
props.isManageMode ? "Cancelar oferta" : "Tipo de transação"
}}</span>
<span class="text-xs text-gray-50 font-medium justify-self-center">{{
props.isManageMode ? "Retirar tokens" : "Checar transação"
}}</span>
<div class="flex justify-between items-center">
<div>
<p class="text-sm leading-5 font-medium text-gray-600">
Saldo disponível
</p>
<p class="text-xl leading-7 font-semibold text-gray-900">
{{ getRemaining() }} BRZ
</p>
<div class="flex gap-2 w-32 sm:w-56" v-if="activeLockAmount != 0">
<span class="text-xs font-normal text-gray-400" ref="infoText">{{
`com ${activeLockAmount.toFixed(2)} BRZ em lock`
}}</span>
<div
class="absolute mt-[2px] md-view"
:style="{ left: `${(infoText?.clientWidth ?? 108) + 4}px` }"
>
<img
alt="info image"
src="@/assets/info.svg"
aria-describedby="tooltip"
ref="reference"
@mouseover="showInfoTooltip = true"
@mouseout="showInfoTooltip = false"
/>
<div
role="tooltip"
ref="floating"
class="w-56 z-50 tooltip md-view"
v-if="showInfoTooltip"
>
Valor “em lock” significa que a quantia está aguardando
confirmação de compra e só estará disponível para saque caso a
transação expire.
</div>
</div>
</div>
</div>
<div v-show="!isCollapsibleOpen" class="flex justify-end items-center">
<div
class="flex gap-2 cursor-pointer items-center justify-self-center border-2 p-2 border-amber-300 rounded-md"
@click="[(isCollapsibleOpen = true)]"
>
<img
alt="Withdraw image"
src="@/assets/withdraw.svg"
class="w-3 h-3 sm:w-4 sm:h-4"
/>
<span class="last-release-info">Sacar</span>
</div>
</div>
</div>
<div class="pt-5">
<div v-show="isCollapsibleOpen" class="py-2 w-100">
<p class="text-sm leading-5 font-medium">Valor do saque</p>
<input
type="number"
name=""
@input="debounce(handleInputEvent, 500)($event)"
placeholder="0"
class="text-2xl text-gray-900 w-full outline-none"
v-model="withdrawAmount"
/>
</div>
<div class="flex justify-center" v-if="!validDecimals">
<span class="text-red-500 font-normal text-sm"
>Por favor utilize no máximo 2 casas decimais</span
>
</div>
<div class="flex justify-center" v-else-if="!validWithdrawAmount">
<span class="text-red-500 font-normal text-sm"
>Saldo insuficiente</span
>
</div>
<hr v-show="isCollapsibleOpen" class="pb-3" />
<div
v-show="isCollapsibleOpen"
class="flex justify-between items-center"
>
<h1
@click="[(isCollapsibleOpen = false)]"
class="text-black font-medium cursor-pointer"
>
Cancelar
</h1>
<div
class="withdraw-button flex gap-2 items-center justify-self-center border-2 p-2 border-amber-300 rounded-md"
@click="callWithdraw"
>
<img
alt="Withdraw image"
src="@/assets/withdraw.svg"
class="w-3 h-3 sm:w-4 sm:h-4"
/>
<span class="last-release-info">Sacar</span>
</div>
</div>
</div>
</div>
<div
class="grid grid-cols-4 grid-flow-row w-full bg-white px-6 py-4 rounded-lg"
v-for="(item, index) in itemsToShow"
class="w-full bg-white p-4 sm:p-6 rounded-lg"
v-for="item in itemsToShow"
:key="item.blockNumber"
>
<span class="last-release-info">
{{
isValidDeposit(item)
? item.remaining
: getAmountFormatted(item.args?.amount)
}}
BRZ
</span>
<span class="last-release-info transaction-date"> 20 out 2022 </span>
<span class="last-release-info" v-if="!props.isManageMode">
{{ getEventName((item as Event).event) }}
</span>
<div
v-if="!props.isManageMode"
class="flex gap-2 cursor-pointer items-center justify-self-center"
@click="openEtherscanUrl((item as Event)?.transactionHash)"
>
<span class="last-release-info">Etherscan</span>
<img alt="Redirect image" src="@/assets/redirect.svg" />
</div>
<div
v-if="props.isManageMode"
class="flex gap-2 cursor-pointer items-center justify-self-center"
@click="emit('cancelDeposit', (item as ValidDeposit).depositID, index)"
>
<span class="last-release-info">Cancelar</span>
<img alt="Cancel image" src="@/assets/cancel.svg" />
</div>
<div
v-if="props.isManageMode"
class="flex gap-2 cursor-pointer items-center justify-self-center"
@click="
emit('withdrawDeposit', (item as ValidDeposit).depositID, index)
"
>
<span class="last-release-info">Retirar</span>
<img alt="Withdraw image" src="@/assets/withdraw.svg" />
<div class="item-container">
<div class="flex flex-col self-start">
<span class="text-xs sm:text-sm leading-5 font-medium text-gray-600">
{{ getEventName(item.event) }}
</span>
<span
class="text-xl sm:text-xl leading-7 font-semibold text-gray-900"
>
{{ item.amount }}
BRZ
</span>
</div>
<div>
<div
class="bg-amber-300 status-text"
v-if="getEventName(item.event) == 'Reserva' && item.lockStatus == 1"
>
Em Aberto
</div>
<div
class="bg-[#94A3B8] status-text"
v-if="getEventName(item.event) == 'Reserva' && item.lockStatus == 2"
>
Expirado
</div>
<div
class="bg-emerald-300 status-text"
v-if="
(getEventName(item.event) == 'Reserva' && item.lockStatus == 3) ||
getEventName(item.event) != 'Reserva'
"
>
Finalizado
</div>
<div
class="flex gap-2 cursor-pointer items-center justify-self-center w-full"
@click="openEtherscanUrl(item.transactionHash)"
v-if="getEventName(item.event) != 'Reserva' || item.lockStatus != 1"
>
<span class="last-release-info">{{ getExplorer() }}</span>
<img
alt="Redirect image"
src="@/assets/redirect.svg"
class="w-3 h-3 sm:w-4 sm:h-4"
/>
</div>
<div
class="flex gap-2 justify-self-center w-full"
v-if="getEventName(item.event) == 'Reserva' && item.lockStatus == 1"
>
<RouterLink
:to="{
name: 'home',
force: true,
state: { lockID: item.transactionID },
}"
class="router-button"
>Continuar</RouterLink
>
</div>
</div>
</div>
</div>
<div
@@ -162,11 +352,11 @@ showInitialItems();
</button>
<span class="text-gray-300">
({{ itemsToShow.length }} de {{ props.walletTransactions.length }}
{{ isManageMode ? "ofertas" : "transações" }})
transações )
</span>
</div>
<span class="font-bold text-gray-900" v-if="itemsToShow.length == 0">
<span class="font-bold text-gray-300" v-if="itemsToShow.length == 0">
Não há nenhuma transação anterior
</span>
</div>
@@ -185,15 +375,19 @@ p {
@apply flex flex-col items-center justify-center gap-4;
}
.text {
@apply text-gray-800 text-center;
.item-container {
@apply flex justify-between items-center;
}
.blur-container-row {
@apply flex flex-row justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-8 w-1/3;
.status-text {
@apply text-xs sm:text-base font-medium text-gray-900 rounded-lg text-center mb-2 px-2 py-1 mt-4;
}
.text {
@apply text-white text-center;
}
.blur-container {
@apply flex flex-col justify-center items-center px-8 py-6 gap-4 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md w-auto;
@apply flex flex-col justify-center items-center px-4 py-3 sm:px-8 sm:py-6 gap-4 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md w-auto;
}
.grid-container {
@@ -201,7 +395,20 @@ p {
}
.last-release-info {
@apply font-medium text-base text-gray-900 justify-self-center;
@apply font-medium text-xs sm:text-sm text-gray-900 justify-self-center;
}
.tooltip {
@apply bg-white text-gray-900 font-medium text-xs md:text-base px-3 py-2 rounded border-2 border-emerald-500 left-5 top-[-3rem];
}
.router-button {
@apply rounded-lg border-amber-300 border-2 px-3 py-2 text-gray-900 font-semibold sm:text-base text-xs hover:bg-transparent w-full text-center;
}
.withdraw-button {
opacity: v-bind(withdrawButtonOpacity);
cursor: v-bind(withdrawButtonCursor);
}
input[type="number"] {
@@ -212,4 +419,10 @@ input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
@media screen and (max-width: 640px) {
.md-view {
display: none;
}
}
</style>
@@ -3,50 +3,37 @@ import ListingComponent from "@/components/ListingComponent/ListingComponent.vue
import { createPinia, setActivePinia } from "pinia";
import { expect } from "vitest";
import { MockValidDeposits } from "@/model/mock/ValidDepositMock";
import { MockEvents } from "@/model/mock/EventMock";
import { MockWalletTransactions } from "@/model/mock/WalletTransactionMock";
import { useEtherStore } from "@/store/ether";
describe("ListingComponent.vue", () => {
beforeEach(() => {
setActivePinia(createPinia());
useEtherStore().setLoadingWalletTransactions(false);
});
test("Test Headers on List in Manage Mode", () => {
test("Test Message when an empty array is received", () => {
const wrapper = mount(ListingComponent, {
props: {
walletTransactions: MockValidDeposits,
isManageMode: true,
validDeposits: [],
walletTransactions: [],
activeLockAmount: 0,
},
});
expect(wrapper.html()).toContain("Valor");
expect(wrapper.html()).toContain("Data");
expect(wrapper.html()).toContain("Cancelar oferta");
expect(wrapper.html()).toContain("Retirar tokens");
});
test("Test Headers on List in Unmanage Mode", () => {
const wrapper = mount(ListingComponent, {
props: {
walletTransactions: MockEvents,
isManageMode: false,
},
});
expect(wrapper.html()).toContain("Valor");
expect(wrapper.html()).toContain("Data");
expect(wrapper.html()).toContain("Tipo de transação");
expect(wrapper.html()).toContain("Checar transação");
expect(wrapper.html()).toContain("Não há nenhuma transação anterior");
});
test("Test number of elements in the list first render", () => {
const wrapper = mount(ListingComponent, {
props: {
walletTransactions: MockEvents,
isManageMode: false,
validDeposits: [],
walletTransactions: MockWalletTransactions,
activeLockAmount: 0,
},
});
const elements = wrapper.findAll(".transaction-date");
const elements = wrapper.findAll(".item-container");
expect(elements).toHaveLength(3);
});
@@ -54,47 +41,47 @@ describe("ListingComponent.vue", () => {
test("Test load more button behavior", async () => {
const wrapper = mount(ListingComponent, {
props: {
walletTransactions: MockValidDeposits,
isManageMode: false,
validDeposits: MockValidDeposits,
walletTransactions: MockWalletTransactions,
activeLockAmount: 0,
},
});
const btn = wrapper.find("button");
let elements = wrapper.findAll(".transaction-date");
let elements = wrapper.findAll(".item-container");
expect(elements).toHaveLength(3);
await btn.trigger("click");
elements = wrapper.findAll(".transaction-date");
elements = wrapper.findAll(".item-container");
expect(elements).toHaveLength(5);
});
test("Test cancel offer button emit", async () => {
const wrapper = mount(ListingComponent, {
props: {
walletTransactions: MockValidDeposits,
isManageMode: true,
},
});
wrapper.vm.$emit("cancelDeposit");
await wrapper.vm.$nextTick();
expect(wrapper.emitted("cancelDeposit")).toBeTruthy();
});
test("Test withdraw offer button emit", async () => {
const wrapper = mount(ListingComponent, {
props: {
walletTransactions: MockValidDeposits,
isManageMode: true,
validDeposits: MockValidDeposits,
walletTransactions: MockWalletTransactions,
activeLockAmount: 0,
},
});
wrapper.vm.$emit("withdrawDeposit");
wrapper.vm.$emit("depositWithdrawn");
await wrapper.vm.$nextTick();
expect(wrapper.emitted("withdrawDeposit")).toBeTruthy();
expect(wrapper.emitted("depositWithdrawn")).toBeTruthy();
});
test("Test should render lock info when active lock amount is greater than 0", () => {
const wrapper = mount(ListingComponent, {
props: {
validDeposits: MockValidDeposits,
walletTransactions: [],
activeLockAmount: 50,
},
});
expect(wrapper.html()).toContain("com 50.00 BRZ em lock");
});
});
@@ -9,16 +9,18 @@ const props = defineProps({
<template>
<div class="page">
<div class="text-container">
<span class="text font-bold text-3xl max-w-[29rem]">{{
props.title ? props.title : "Confirme em sua carteira"
}}</span>
<span
class="text font-bold sm:text-3xl text-2xl sm:max-w-[29rem] max-w-[20rem]"
>
{{ props.title ? props.title : "Confirme em sua carteira" }}
</span>
</div>
<div class="blur-container w-[26rem]">
<div class="blur-container sm:w-[26rem] w-[20rem]">
<div
class="flex flex-col w-full bg-white px-10 py-5 rounded-lg border-y-10"
class="flex flex-col w-full bg-white sm:px-10 px-4 py-5 rounded-lg border-y-10"
>
<div
class="flex flex-col text-center justify-center w-full items-center p-2 px-3 rounded-3xl min-w-fit gap-1"
class="flex flex-col text-center justify-center w-full items-center p-2 px-3 rounded-3xl lg:min-w-fit gap-1"
>
<img
alt="Polygon image"
@@ -26,7 +28,7 @@ const props = defineProps({
width="96"
height="48"
/>
<span class="text-black font-medium text-sm px-12 mt-4">
<span class="text-black font-medium text-sm lg:px-12 px-4 mt-4">
{{ $props.message }}
</span>
</div>
@@ -55,11 +57,11 @@ const props = defineProps({
}
.text {
@apply text-gray-800 text-center;
@apply text-white text-center;
}
.blur-container {
@apply flex flex-col justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-10;
@apply flex flex-col justify-center items-center sm:px-8 px-6 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-10;
}
input[type="number"] {
@@ -0,0 +1,27 @@
import { mount } from "@vue/test-utils";
import LoadingComponent from "../LoadingComponent.vue";
describe("Loading.vue", () => {
test("Test loading content with received props", () => {
const wrapper = mount(LoadingComponent, {
props: {
title: "MockTitle",
message: "MockMessage",
},
});
expect(wrapper.html()).toContain("MockTitle");
expect(wrapper.html()).toContain("MockMessage");
});
test("Test default text if props title isnt passed", () => {
const wrapper = mount(LoadingComponent, {
props: {
message: "MockMessage",
},
});
expect(wrapper.html()).toContain("Confirme em sua carteira");
expect(wrapper.html()).toContain("MockMessage");
});
});
+53 -12
View File
@@ -1,9 +1,10 @@
<script setup lang="ts">
import { pix } from "../utils/QrCodePix";
import { ref } from "vue";
import { pix } from "@/utils/QrCodePix";
import { onMounted, onUnmounted, ref } from "vue";
import { debounce } from "@/utils/debounce";
import CustomButton from "./CustomButton/CustomButton.vue";
import api from "../services/index";
import CustomButton from "@/components/CustomButton/CustomButton.vue";
import CustomModal from "@/components//CustomModal/CustomModal.vue";
import api from "@/services/index";
// props and store references
const props = defineProps({
@@ -11,10 +12,12 @@ const props = defineProps({
tokenValue: Number,
});
const windowSize = ref<number>(window.innerWidth);
const qrCode = ref<string>("");
const qrCodePayload = ref<string>("");
const isPixValid = ref<boolean>(false);
const isCodeInputEmpty = ref<boolean>(true);
const showWarnModal = ref<boolean>(true);
const e2eId = ref<string>("");
// Emits
@@ -66,22 +69,37 @@ const validatePix = async (): Promise<void> => {
isPixValid.value = false;
}
};
onMounted(() => {
window.addEventListener(
"resize",
() => (windowSize.value = window.innerWidth)
);
});
onUnmounted(() => {
window.removeEventListener(
"resize",
() => (windowSize.value = window.innerWidth)
);
});
</script>
<template>
<div class="page">
<div class="text-container">
<span class="text font-extrabold text-2xl max-w-[30rem]">
<span
class="text font-extrabold lg:text-2xl text-xl sm:max-w-[30rem] max-w-[24rem]"
>
Utilize o QR Code ou copie o código para realizar o Pix
</span>
<span class="text font-medium text-md max-w-[28rem]">
<span class="text font-medium lg:text-md text-sm max-w-[28rem]">
Após realizar o Pix no banco de sua preferência, insira o código de
autenticação para enviar a transação para a rede.
</span>
</div>
<div class="blur-container max-w-[28rem] text-black">
<div class="blur-container sm:max-w-[28rem] max-w-[20rem] text-black">
<div
class="flex-col items-center justify-center flex w-full bg-white p-8 rounded-lg break-normal"
class="flex-col items-center justify-center flex w-full bg-white sm:p-8 p-4 rounded-lg break-normal"
>
<img alt="Qr code image" :src="qrCode" class="w-48 h-48" />
<span class="text-center font-bold">Código pix</span>
@@ -95,9 +113,9 @@ const validatePix = async (): Promise<void> => {
src="@/assets/copyPix.svg"
width="16"
height="16"
class="pt-2 mb-5 cursor-pointer"
class="pt-2 lg:mb-5 cursor-pointer"
/>
<span class="text-xs text-start">
<span class="text-xs text-start lg-view">
<strong>ATENÇÃO!</strong> A transação só será processada após inserir
o código de autenticação. Caso contrário não conseguiremos comprovar o
seu depósito e não será possível transferir os tokens para sua
@@ -111,7 +129,7 @@ const validatePix = async (): Promise<void> => {
type="text"
placeholder="Digite o código do comprovante PIX"
@input="debounce(handleInputEvent, 500)($event)"
class="text-md w-full box-border p-2 h-6 mb-2 outline-none"
class="sm:text-md text-sm w-full box-border p-2 sm:h-6 h-2 mb-2 outline-none"
/>
<div class="custom-divide" v-if="!isCodeInputEmpty"></div>
<div
@@ -150,6 +168,11 @@ const validatePix = async (): Promise<void> => {
@button-clicked="emit('pixValidated', e2eId)"
/>
</div>
<CustomModal
v-if="showWarnModal && windowSize <= 500"
@close-modal="showWarnModal = false"
:isRedirectModal="false"
/>
</div>
</template>
@@ -195,7 +218,7 @@ h2 {
}
.text {
@apply text-gray-800 text-center;
@apply text-white text-center;
}
.blur-container {
@@ -210,4 +233,22 @@ input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
.lg-view {
display: inline-block;
}
.sm-view {
display: none;
}
@media screen and (max-width: 500px) {
.lg-view {
display: none;
}
.sm-view {
display: inline-block;
}
}
</style>
+48 -14
View File
@@ -9,6 +9,7 @@ import { verifyNetworkLiquidity } from "@/utils/networkLiquidity";
import { NetworkEnum } from "@/model/NetworkEnum";
import type { ValidDeposit } from "@/model/ValidDeposit";
import { decimalCount } from "@/utils/decimalCount";
import SpinnerComponent from "./SpinnerComponent.vue";
// Store reference
const etherStore = useEtherStore();
@@ -18,6 +19,7 @@ const {
networkName,
depositsValidListGoerli,
depositsValidListMumbai,
loadingNetworkLiquidity,
} = storeToRefs(etherStore);
// Reactive state
@@ -107,29 +109,37 @@ const enableOrDisableConfirmButton = (): void => {
};
watch(networkName, (): void => {
verifyLiquidity();
enableOrDisableConfirmButton();
});
watch(walletAddress, (): void => {
verifyLiquidity();
});
</script>
<template>
<div class="page">
<div class="text-container">
<span class="text font-extrabold text-5xl max-w-[29rem]"
>Adquira cripto com apenas um Pix</span
<span
class="text font-extrabold sm:text-5xl text-3xl sm:max-w-[29rem] max-w-[20rem]"
>
<span class="text font-medium text-base max-w-[28rem]"
Adquira cripto com apenas um Pix</span
>
<span class="text font-medium sm:text-base text-sm max-w-[28rem]"
>Digite um valor, confira a oferta, conecte sua carteira e receba os
tokens após realizar o Pix</span
>
</div>
<div class="blur-container">
<div class="backdrop-blur -z-10 w-full h-full"></div>
<div
class="flex flex-col w-full bg-white px-10 py-5 rounded-lg border-y-10"
class="flex flex-col w-full bg-white sm:px-10 px-6 py-5 rounded-lg border-y-10"
>
<div class="flex justify-between w-full items-center">
<div class="flex justify-between sm:w-full items-center">
<input
type="number"
class="border-none outline-none text-lg text-gray-900 w-fit"
class="border-none outline-none text-lg text-gray-900 w-3/4"
v-bind:class="{
'font-semibold': tokenValue != undefined,
'text-xl': tokenValue != undefined,
@@ -141,13 +151,22 @@ watch(networkName, (): void => {
<div
class="flex flex-row p-2 px-3 bg-gray-300 rounded-3xl min-w-fit gap-1"
>
<img alt="Token image" class="w-fit" src="@/assets/brz.svg" />
<span class="text-gray-900 text-lg w-fit" id="brz">BRZ</span>
<img
alt="Token image"
class="sm:w-fit w-4"
src="@/assets/brz.svg"
/>
<span class="text-gray-900 sm:text-lg text-md w-fit" id="brz"
>BRZ</span
>
</div>
</div>
<div class="custom-divide py-2"></div>
<div class="flex justify-between pt-2" v-if="hasLiquidity">
<div class="custom-divide py-2 mb-2"></div>
<div
class="flex justify-between"
v-if="hasLiquidity && !loadingNetworkLiquidity"
>
<p class="text-gray-500 font-normal text-sm w-auto">
~ R$ {{ tokenValue.toFixed(2) }}
</p>
@@ -168,12 +187,27 @@ watch(networkName, (): void => {
/>
</div>
</div>
<div class="flex pt-2 justify-center" v-if="!validDecimals">
<div
class="flex justify-center items-center"
v-if="loadingNetworkLiquidity"
>
<span class="text-gray-900 font-normal text-sm mr-2"
>Carregando liquidez das redes.</span
>
<SpinnerComponent width="4" height="4"></SpinnerComponent>
</div>
<div
class="flex justify-center"
v-if="!validDecimals && !loadingNetworkLiquidity"
>
<span class="text-red-500 font-normal text-sm"
>Por favor utilize no máximo 2 casas decimais</span
>
</div>
<div class="flex pt-2 justify-center" v-else-if="!hasLiquidity">
<div
class="flex justify-center"
v-else-if="!hasLiquidity && !loadingNetworkLiquidity"
>
<span class="text-red-500 font-normal text-sm"
>Atualmente não há liquidez nas redes para sua demanda</span
>
@@ -215,11 +249,11 @@ watch(networkName, (): void => {
}
.text {
@apply text-gray-800 text-center;
@apply text-white text-center;
}
.blur-container {
@apply flex flex-col justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-10;
@apply flex flex-col justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 mt-10;
}
input[type="number"] {
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref } from "vue";
import CustomButton from "../CustomButton/CustomButton.vue";
import CustomButton from "@/components/CustomButton/CustomButton.vue";
import { debounce } from "@/utils/debounce";
import { decimalCount } from "@/utils/decimalCount";
@@ -122,7 +122,7 @@ const handleInputEvent = (event: any): void => {
}
.text {
@apply text-gray-800 text-center;
@apply text-white text-center;
}
.blur-container {
+7 -8
View File
@@ -14,10 +14,12 @@ const props = defineProps({
<template>
<div class="page">
<div class="text-container">
<span class="text font-extrabold text-5xl max-w-[50rem]"
<span
class="text font-extrabold sm:text-5xl text-xl sm:max-w-[50rem] max-w-[20rem]"
>Envie sua oferta para a rede
</span>
<span class="text text-xl font-medium text-base max-w-[30rem]"
<span
class="text text-xl font-normal sm:text-base text-xs sm:max-w-[30rem] max-w-[22rem]"
>Após a confirmação sua oferta estará disponível para outros usuários.
Caso deseje retirar a oferta, será necessário aguardar 24h para receber
os tokens de volta.</span
@@ -63,18 +65,15 @@ p {
}
.text-container {
@apply flex flex-col items-center justify-center gap-4;
@apply flex flex-col items-center justify-center sm:gap-4 gap-2;
}
.text {
@apply text-gray-800 text-center;
}
.blur-container-row {
@apply flex flex-row justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-8 w-1/3;
@apply text-white text-center;
}
.blur-container {
@apply flex flex-col justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-8 w-1/3;
@apply flex flex-col justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-8 sm:w-1/3;
}
.last-deposit-info {
@@ -3,6 +3,7 @@ import { ref } from "vue";
import CustomButton from "../CustomButton/CustomButton.vue";
import { debounce } from "@/utils/debounce";
import { decimalCount } from "@/utils/decimalCount";
import { pixFormatValidation, postProcessKey } from "@/utils/pixKeyFormat";
import { useEtherStore } from "@/store/ether";
import { storeToRefs } from "pinia";
import { connectProvider } from "@/blockchain/provider";
@@ -17,6 +18,7 @@ const pixKey = ref<string>("");
const enableSelectButton = ref<boolean>(false);
const hasLiquidity = ref<boolean>(true);
const validDecimals = ref<boolean>(true);
const validPixFormat = ref<boolean>(true);
// Emits
const emit = defineEmits(["approveTokens"]);
@@ -35,35 +37,55 @@ const handleInputEvent = (event: any): void => {
validDecimals.value = true;
};
const handlePixKeyInputEvent = (event: any): void => {
const { value } = event.target;
pixKey.value = value;
if (pixFormatValidation(pixKey.value)) {
validPixFormat.value = true;
enableSelectButton.value = true;
return;
}
enableSelectButton.value = false;
validPixFormat.value = false;
};
const handleButtonClick = async (
offer: string,
pixKey: string
): Promise<void> => {
if (walletAddress.value) emit("approveTokens", { offer, pixKey });
const postProcessedPixKey = postProcessKey(pixKey);
if (walletAddress.value)
emit("approveTokens", { offer, postProcessedPixKey });
else await connectProvider();
};
</script>
<template>
<div class="page">
<div class="page w-full">
<div class="text-container">
<span class="text font-extrabold text-5xl max-w-[29rem]"
<span
class="text font-extrabold sm:text-5xl text-3xl sm:max-w-[29rem] max-w-[20rem]"
>Venda cripto e receba em Pix</span
>
<span class="text font-medium text-base max-w-[28rem]"
<span
class="text font-medium sm:text-base text-xs sm:max-w-[28rem] max-w-[30rem] sm:tracking-normal tracking-wide"
>Digite sua oferta, informe a chave Pix, selecione a rede, aprove o
envio da transação e confirme sua oferta.</span
>
</div>
<div class="blur-container">
<div class="backdrop-blur -z-10 w-full h-full"></div>
<div
class="flex flex-col w-full bg-white px-10 py-5 rounded-lg border-y-10"
class="flex flex-col w-full bg-white sm:px-10 px-6 py-5 rounded-lg border-y-10"
>
<div class="flex justify-between w-full items-center">
<div class="flex justify-between items-center">
<input
type="number"
v-model="offer"
class="border-none outline-none text-lg text-gray-900 w-fit"
class="border-none outline-none text-gray-900 sm:w-fit w-3/4"
v-bind:class="{
'font-semibold': offer != undefined,
'text-xl': offer != undefined,
@@ -75,8 +97,12 @@ const handleButtonClick = async (
<div
class="flex flex-row p-2 px-3 bg-gray-300 rounded-3xl min-w-fit gap-1"
>
<img alt="Token image" class="w-fit" src="@/assets/brz.svg" />
<span class="text-gray-900 text-lg w-fit" id="brz">BRZ</span>
<img
alt="Token image"
class="sm:w-fit w-4"
src="@/assets/brz.svg"
/>
<span class="text-gray-900 w-fit" id="brz"> BRZ </span>
</div>
</div>
@@ -92,19 +118,26 @@ const handleButtonClick = async (
</div>
</div>
<div
class="flex flex-col w-full bg-white px-10 py-8 rounded-lg border-y-10"
class="flex flex-col w-full bg-white sm:px-10 px-6 py-8 rounded-lg border-y-10"
>
<div class="flex justify-between w-full items-center">
<input
@input="debounce(handlePixKeyInputEvent, 500)($event)"
type="text"
v-model="pixKey"
class="border-none outline-none text-lg text-gray-900 w-fit"
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-fit"
placeholder="Digite a chave Pix"
/>
</div>
<div class="flex pt-2 justify-center" v-if="!validPixFormat">
<span class="text-red-500 font-normal text-sm"
>Por favor utilize telefone, CPF ou CNPJ</span
>
</div>
</div>
<CustomButton
:text="walletAddress ? 'Aprovar tokens' : 'Conectar Carteira'"
:isDisabled="!validDecimals || !validPixFormat"
@buttonClicked="handleButtonClick(offer, pixKey)"
/>
</div>
@@ -131,11 +164,11 @@ const handleButtonClick = async (
}
.text {
@apply text-gray-800 text-center;
@apply text-white text-center;
}
.blur-container {
@apply flex flex-col justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-10;
@apply flex flex-col justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 mt-10 w-auto;
}
input[type="number"] {
@@ -146,4 +179,8 @@ input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
}
input {
@apply sm:text-lg text-sm;
}
</style>
+40
View File
@@ -0,0 +1,40 @@
<script setup lang="ts">
// prop
const props = defineProps({
width: String,
height: String,
show: Boolean,
});
const getCustomClass = () => {
return [
`w-${props.width}`,
`h-${props.height}`,
`fill-white`,
"text-gray-200",
"animate-spin",
"dark:text-gray-600",
];
};
</script>
<template>
<div v-if="props.show ? props.show : true">
<svg
aria-hidden="true"
:class="getCustomClass()"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
</div>
</template>
+289 -24
View File
@@ -2,6 +2,7 @@
import { storeToRefs } from "pinia";
import { useEtherStore } from "@/store/ether";
import { ref } from "vue";
import { onClickOutside } from "@vueuse/core";
import { NetworkEnum } from "@/model/NetworkEnum";
import { connectProvider, requestNetworkChange } from "@/blockchain/provider";
import ethereumImage from "@/assets/ethereum.svg";
@@ -15,8 +16,12 @@ const { walletAddress, sellerView } = storeToRefs(etherStore);
const menuOpenToggle = ref<boolean>(false);
const menuHoverToggle = ref<boolean>(false);
const infoMenuOpenToggle = ref<boolean>(false);
const currencyMenuOpenToggle = ref<boolean>(false);
const currencyMenuHoverToggle = ref<boolean>(false);
const infoMenuRef = ref<any>(null);
const walletAddressRef = ref<any>(null);
const currencyRef = ref<any>(null);
//Methods
const connectMetaMask = async (): Promise<void> => {
@@ -58,32 +63,161 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
return validImages[networkName];
};
onClickOutside(walletAddressRef, () => {
menuHoverToggle.value = false;
menuOpenToggle.value = false;
});
onClickOutside(currencyRef, () => {
currencyMenuOpenToggle.value = false;
currencyMenuHoverToggle.value = false;
});
onClickOutside(infoMenuRef, () => {
infoMenuOpenToggle.value = false;
});
</script>
<template>
<header>
<header class="z-20">
<RouterLink :to="'/'" class="default-button">
<img
alt="P2Pix logo"
class="logo"
class="logo lg-view"
src="@/assets/logo.svg"
width="75"
height="75"
/>
<img
alt="P2Pix logo"
class="logo sm-view w-10/12"
src="@/assets/logo2.svg"
width="40"
height="40"
/>
</RouterLink>
<div class="flex gap-4 items-center">
<RouterLink :to="'/faq'" class="default-button"> FAQ </RouterLink>
<RouterLink :to="sellerView ? '/' : '/seller'" class="default-button">
<div class="flex sm:gap-4 gap-2 items-center">
<div class="flex flex-col">
<div
v-show="infoMenuOpenToggle"
class="mt-10 absolute w-full text-gray-900 lg-view"
>
<div class="mt-2">
<div class="bg-white rounded-md z-10 -left-32 w-52">
<div class="menu-button gap-2 px-4 rounded-md cursor-pointer">
<span class="text-gray-900 py-4 text-end font-semibold text-sm">
Documentação
</span>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<RouterLink
:to="'/faq'"
class="menu-button gap-2 px-4 rounded-md cursor-pointer"
>
<span
class="text-gray-900 py-4 text-end font-semibold text-sm whitespace-nowrap"
>
Perguntas frequentes
</span>
</RouterLink>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<div
class="sm:text-center sm:justify-center ml-8 sm:ml-0 gap-2 px-4 rounded-md float-right"
>
<div class="redirect_button flex mr-4">
<div class="mr-6">
<img
alt="Twitter"
width="20"
height="20"
src="@/assets/twitterIcon.svg"
class="cursor-pointer"
onclick="location.href = 'https://www.twitter.com/doiim';"
/>
</div>
<div class="mr-6">
<img
alt="Discord"
width="20"
height="20"
src="@/assets/discordIcon.svg"
class="cursor-pointer"
/>
</div>
<img
alt="Github"
width="20"
height="20"
src="@/assets/githubIcon.svg"
class="cursor-pointer"
onclick="location.href = 'https://github.com/doiim';"
/>
</div>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
</div>
</div>
</div>
<div
ref="infoMenuRef"
class="default-button lg-view cursor-pointer"
@click="
[
(infoMenuOpenToggle = !infoMenuOpenToggle),
(menuOpenToggle = false),
(currencyMenuOpenToggle = false),
]
"
>
<h1
class="text-gray-50 font-semibold sm:text-base"
:style="{
'border-bottom': infoMenuOpenToggle
? '2px solid white'
: 'transparent',
}"
>
Menu
</h1>
</div>
</div>
<RouterLink
:to="'/faq'"
v-if="!walletAddress"
class="default-button sm-view"
>
FAQ
</RouterLink>
<RouterLink
:to="sellerView ? '/' : '/seller'"
class="default-button sm:whitespace-normal whitespace-nowrap lg-view"
>
{{ sellerView ? "Quero comprar" : "Quero vender" }}
</RouterLink>
<RouterLink
:to="sellerView ? '/' : '/seller'"
v-if="!walletAddress"
class="default-button sm:whitespace-normal whitespace-nowrap sm-view"
>
{{ sellerView ? "Quero comprar" : "Quero vender" }}
</RouterLink>
<div class="flex flex-col" v-if="walletAddress">
<div
class="group top-bar-info cursor-pointer hover:bg-white"
ref="currencyRef"
class="group top-bar-info cursor-pointer hover:bg-white h-10"
@click="
[
(currencyMenuOpenToggle = !currencyMenuOpenToggle),
(menuOpenToggle = false),
(infoMenuOpenToggle = false),
]
"
@mouseover="currencyMenuHoverToggle = true"
@@ -101,7 +235,7 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
:src="getNetworkImage(etherStore.networkName)"
/>
<span
class="default-text group-hover:text-gray-900"
class="default-text group-hover:text-gray-900 lg-view"
:style="{
color: currencyMenuOpenToggle
? '#000000'
@@ -131,7 +265,7 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
</div>
<div
v-show="currencyMenuOpenToggle"
class="mt-10 pl-3 absolute w-full text-gray-900"
class="mt-10 pl-3 absolute w-full text-gray-900 lg-view"
>
<div class="mt-2">
<div class="bg-white rounded-md z-10">
@@ -176,19 +310,29 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
<button
type="button"
v-if="!walletAddress"
class="border-amber-500 border-2 rounded default-button"
class="border-amber-500 border-2 rounded default-button lg-view"
@click="connectMetaMask()"
>
Conectar carteira
</button>
<button
type="button"
v-if="!walletAddress"
class="border-amber-500 border-2 rounded default-button sm-view"
@click="connectMetaMask()"
>
Conectar
</button>
<div v-if="walletAddress" class="account-info">
<div class="flex flex-col">
<div
class="top-bar-info cursor-pointer"
ref="walletAddressRef"
class="top-bar-info cursor-pointer h-10"
@click="
[
(menuOpenToggle = !menuOpenToggle),
(currencyMenuOpenToggle = false),
(infoMenuOpenToggle = false),
]
"
@mouseover="menuHoverToggle = true"
@@ -203,7 +347,7 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
>
<img alt="Account image" src="@/assets/account.svg" />
<span
class="default-text text-sm"
class="default-text"
:style="{
color: menuOpenToggle
? '#000000'
@@ -233,18 +377,10 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
</div>
<div
v-show="menuOpenToggle"
class="mt-10 absolute w-full text-gray-900"
class="mt-10 absolute w-full text-gray-900 lg-view"
>
<div class="pl-4 mt-2">
<div class="bg-white rounded-md z-10">
<div class="menu-button" @click="closeMenu()">
<RouterLink to="/transaction_history" class="redirect_button">
Histórico de transações
</RouterLink>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<div class="menu-button" @click="closeMenu()">
<RouterLink to="/manage_bids" class="redirect_button">
Gerenciar Ofertas
@@ -264,6 +400,111 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
</div>
</div>
</div>
<div
v-show="menuOpenToggle"
class="mobile-menu fixed w-4/5 text-gray-900 sm-view"
>
<div class="pl-4 mt-2 h-full">
<div class="bg-white rounded-md z-10 h-full">
<div class="menu-button" @click="closeMenu()">
<RouterLink
:to="sellerView ? '/' : '/seller'"
class="redirect_button mt-2"
>
{{ sellerView ? "Quero comprar" : "Quero vender" }}
</RouterLink>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<div class="menu-button" @click="closeMenu()">
<RouterLink to="/manage_bids" class="redirect_button">
Gerenciar Ofertas
</RouterLink>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<div class="menu-button" @click="disconnectUser">
<RouterLink to="/" class="redirect_button">
Desconectar
</RouterLink>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<div class="menu-button pb-10">
<div class="redirect_button flex">
<img
alt="Twitter"
width="20"
height="20"
src="@/assets/twitterIcon.svg"
class="mr-6"
onclick="location.href = 'https://www.twitter.com/doiim';"
/>
<img
alt="Discord"
width="20"
height="20"
src="@/assets/discordIcon.svg"
class="mr-6"
/>
<img
alt="Github"
width="20"
height="20"
src="@/assets/githubIcon.svg"
onclick="location.href = 'https://github.com/doiim';"
/>
</div>
</div>
</div>
</div>
</div>
<div
v-show="currencyMenuOpenToggle"
class="mobile-menu fixed w-4/5 text-gray-900 sm-view"
>
<div class="pl-4 mt-2 h-full">
<div class="bg-white rounded-md z-10 h-full">
<div
class="menu-button gap-2 sm:px-4 rounded-md cursor-pointer py-2"
@click="networkChange(NetworkEnum.ethereum)"
>
<img
alt="Ethereum image"
width="20"
height="20"
src="@/assets/ethereum.svg"
/>
<span class="text-gray-900 py-4 text-end font-bold text-sm">
Ethereum
</span>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<div
class="menu-button gap-2 sm:px-4 rounded-md cursor-pointer py-2"
@click="networkChange(NetworkEnum.polygon)"
>
<img
alt="Polygon image"
width="20"
height="20"
src="@/assets/polygon.svg"
/>
<span class="text-gray-900 py-4 text-end font-bold text-sm">
Polygon
</span>
</div>
<div class="w-full flex justify-center pb-12">
<hr class="w-4/5" />
</div>
</div>
</div>
</div>
</header>
</template>
@@ -273,7 +514,7 @@ header {
}
.default-button {
@apply px-4 py-2 rounded text-gray-50 font-semibold text-base hover:bg-transparent;
@apply sm:px-4 px-3 py-2 rounded text-gray-50 font-semibold sm:text-base text-xs hover:bg-transparent;
}
.account-info {
@@ -285,18 +526,42 @@ header {
}
.top-bar-info {
@apply flex justify-between gap-2 px-4 py-2 border-amber-500 border-2 rounded;
@apply flex justify-between gap-2 px-4 py-2 border-amber-500 border-2 sm:rounded rounded-lg items-center;
}
.redirect_button {
@apply py-4 text-gray-900 font-semibold text-xs w-full;
@apply py-5 text-gray-900 sm:font-semibold font-bold sm:text-xs text-sm w-full;
}
.menu-button {
@apply flex text-center justify-center hover:bg-gray-200;
@apply flex sm:text-center sm:justify-center hover:bg-gray-200 ml-8 sm:ml-0;
}
a:hover {
@apply bg-gray-200 rounded;
}
.lg-view {
display: inline-block;
}
.sm-view {
display: none;
}
.mobile-menu {
margin-top: 1400px;
bottom: 0px;
height: auto;
}
@media screen and (max-width: 500px) {
.lg-view {
display: none;
}
.sm-view {
display: inline-block;
}
}
</style>
@@ -30,6 +30,6 @@ describe("TopBar.vue", () => {
it("should render the P2Pix logo correctly", () => {
const wrapper = shallowMount(TopBar);
const img = wrapper.findAll(".logo");
expect(img.length).toBe(1);
expect(img.length).toBe(2);
});
});
+6
View File
@@ -0,0 +1,6 @@
import type { Pix } from "./Pix";
export type UnreleasedLock = {
lockID: string;
pix: Pix;
};
+3 -5
View File
@@ -1,10 +1,8 @@
import type { BigNumber } from "ethers";
export type ValidDeposit = {
depositID: BigNumber;
token: string;
blockNumber: number;
remaining: number;
seller: string;
pixKey: string;
pixTarget?: string;
pixKey: number;
open?: boolean;
};
+11
View File
@@ -0,0 +1,11 @@
export type WalletTransaction = {
token: string;
blockNumber: number;
amount: number;
seller: string;
buyer: string;
event: string;
lockStatus: number;
transactionHash: string;
transactionID?: string;
};
+29
View File
@@ -89,4 +89,33 @@ export const MockEvents: Event[] = [
getTransaction: vi.fn(),
getTransactionReceipt: vi.fn(),
},
{
blockNumber: 4,
blockHash: "0x8",
transactionIndex: 4,
removed: false,
address: "0x0",
data: "0x0",
topics: ["0x0", "0x0"],
transactionHash: "0x0",
logIndex: 4,
event: "LockReleased",
eventSignature: "LockReleased(address,uint256,address,uint256)",
args: [
"0x0",
{
type: "BigNumber",
hex: "0x00",
},
"0x0",
{
type: "BigNumber",
hex: "0x6c6b935b8bbd400000",
},
],
getBlock: vi.fn(),
removeListener: vi.fn(),
getTransaction: vi.fn(),
getTransactionReceipt: vi.fn(),
},
];
+10 -11
View File
@@ -1,40 +1,39 @@
import { parseEther } from "ethers/lib/utils";
import type { ValidDeposit } from "../ValidDeposit";
export const MockValidDeposits: ValidDeposit[] = [
{
blockNumber: 1,
depositID: parseEther("1"),
token: "1",
remaining: 70,
seller: "mockedSellerAddress",
pixKey: "123456789",
pixKey: 123456789,
},
{
blockNumber: 2,
depositID: parseEther("2"),
token: "2",
remaining: 200,
seller: "mockedSellerAddress",
pixKey: "123456789",
pixKey: 123456789,
},
{
blockNumber: 3,
depositID: parseEther("3"),
token: "3",
remaining: 1250,
seller: "mockedSellerAddress",
pixKey: "123456789",
pixKey: 123456789,
},
{
blockNumber: 4,
depositID: parseEther("4"),
token: "4",
remaining: 4000,
seller: "mockedSellerAddress",
pixKey: "123456789",
pixKey: 123456789,
},
{
blockNumber: 5,
depositID: parseEther("5"),
token: "5",
remaining: 2000,
seller: "mockedSellerAddress",
pixKey: "123456789",
pixKey: 123456789,
},
];
+54
View File
@@ -0,0 +1,54 @@
import type { WalletTransaction } from "../WalletTransaction";
export const MockWalletTransactions: WalletTransaction[] = [
{
blockNumber: 1,
token: "1",
amount: 70,
seller: "mockedSellerAddress",
buyer: "mockedBuyerAddress",
event: "Deposit",
lockStatus: 0,
transactionHash: "1",
},
{
blockNumber: 2,
token: "2",
amount: 200,
seller: "mockedSellerAddress",
buyer: "mockedBuyerAddress",
event: "Lock",
lockStatus: 1,
transactionHash: "2",
},
{
blockNumber: 3,
token: "3",
amount: 1250,
seller: "mockedSellerAddress",
buyer: "mockedBuyerAddress",
event: "Release",
lockStatus: 2,
transactionHash: "3",
},
{
blockNumber: 4,
token: "4",
amount: 4000,
seller: "mockedSellerAddress",
buyer: "mockedBuyerAddress",
event: "Deposit",
lockStatus: 0,
transactionHash: "4",
},
{
blockNumber: 5,
token: "5",
amount: 2000,
seller: "mockedSellerAddress",
buyer: "mockedBuyerAddress",
event: "Deposit",
lockStatus: 3,
transactionHash: "5",
},
];
+9 -9
View File
@@ -1,8 +1,7 @@
import { createRouter, createWebHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
import TransactionHistoryView from "../views/TransactionHistoryView.vue";
import FaqView from "../views/FaqView.vue";
import ManageBidsView from "../views/ManageBidsView.vue";
import HomeView from "@/views/HomeView.vue";
import FaqView from "@/views/FaqView.vue";
import ManageBidsView from "@/views/ManageBidsView.vue";
import SellerView from "@/views/SellerView.vue";
const router = createRouter({
@@ -12,17 +11,18 @@ const router = createRouter({
path: "/",
name: "home",
component: HomeView,
props: true,
},
{
path: "/:lockID",
name: "redirect buy",
component: HomeView,
},
{
path: "/seller",
name: "seller",
component: SellerView,
},
{
path: "/transaction_history",
name: "transaction history",
component: TransactionHistoryView,
},
{
path: "/manage_bids",
name: "manage bids",
+8
View File
@@ -13,6 +13,8 @@ export const useEtherStore = defineStore("ether", {
depositsValidListGoerli: [] as ValidDeposit[],
// Depósitos válidos para compra MUMBAI
depositsValidListMumbai: [] as ValidDeposit[],
loadingWalletTransactions: false,
loadingNetworkLiquidity: false,
}),
actions: {
setWalletAddress(walletAddress: string) {
@@ -36,6 +38,12 @@ export const useEtherStore = defineStore("ether", {
setDepositsValidListMumbai(depositsValidList: ValidDeposit[]) {
this.depositsValidListMumbai = depositsValidList;
},
setLoadingWalletTransactions(isLoadingWalletTransactions: boolean) {
this.loadingWalletTransactions = isLoadingWalletTransactions;
},
setLoadingNetworkLiquidity(isLoadingNetworkLiquidity: boolean) {
this.loadingNetworkLiquidity = isLoadingNetworkLiquidity;
},
},
// Alterar para integrar com mumbai
getters: {
+24
View File
@@ -0,0 +1,24 @@
import { it, expect, vi, type Mock } from "vitest";
import { debounce } from "../debounce";
vi.useFakeTimers();
describe("debounce function test", () => {
let mockFunction: Mock;
let debounceFunction: Function;
beforeEach(() => {
mockFunction = vi.fn();
debounceFunction = debounce(mockFunction, 1000);
});
it("debounce function will be executed just once", () => {
for (let i = 0; i < 100; i++) {
debounceFunction();
}
vi.runAllTimers();
expect(mockFunction).toBeCalledTimes(1);
});
});
+12
View File
@@ -0,0 +1,12 @@
import { it, expect } from "vitest";
import { decimalCount } from "../decimalCount";
describe("decimalCount function test", () => {
it("decimalCount should return length 1 of decimal", () => {
expect(decimalCount("4.1")).toEqual(1);
});
it("decimalCount should return length 0 because no decimal found", () => {
expect(decimalCount("5")).toEqual(0);
});
});
@@ -0,0 +1,25 @@
import { MockValidDeposits } from "@/model/mock/ValidDepositMock";
import { it, expect, vi } from "vitest";
import { verifyNetworkLiquidity } from "../networkLiquidity";
vi.useFakeTimers();
describe("verifyNetworkLiquidity function test", () => {
it("verifyNetworkLiquidity should return an element from valid deposit list when searching for other deposits", () => {
const liquidityElement = verifyNetworkLiquidity(
MockValidDeposits[0].remaining,
"strangeWalletAddress",
MockValidDeposits
);
expect(liquidityElement).toEqual(MockValidDeposits[0]);
});
it("verifyNetworkLiquidity should return undefined when all deposits on valid deposit list match connected wallet addres", () => {
const liquidityElement = verifyNetworkLiquidity(
MockValidDeposits[0].remaining,
MockValidDeposits[0].seller,
[MockValidDeposits[0]]
);
expect(liquidityElement).toEqual(undefined);
});
});
+53
View File
@@ -0,0 +1,53 @@
[
{
"name": "1. Como Começar",
"items": [
{
"title": "O que é uma carteira (wallet)?",
"content": "Cripto-wallet é um software que armazena criptomoedas e criptoativos de forma segura. Existem também dispositivos físicos chamados de cold/hard wallets. Com a carteira-cripto você consegue comprar e vender tokens sem a necessidade de uma corretora (exchange), por exemplo. Cripto-ativos não ficam de fato armazenados nessa carteira, mas sim as informações que possibilitam acessá-los numa blockchain, como suas chaves pública e privada.\n<br>\n\n* **O que é um endereço de carteira (wallet address)?**\n Sequência alfanumérica que permite que você envie e receba suas criptomoedas em segurança. Por exemplo: 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy.\n\n* **Como conectar sua carteira ao p2pix?**\n Clique em 'Conectar Carteira'. Escolha qual wallet ou ponte (bridge) utilizará para se conectar (MetaMask ou WalletConnect). Ao clicar, sua carteira se abrirá. Caso seja seu 1º acesso, certifique-se de que permitiu sua carteira a se conectar com nossa plataforma. \n\n* **Como instalar MetaMask no Google Chrome?** \n MetaMask é uma web3 wallet que pode ser adicionada como extensão no seu browser (navegador). Para instalar esse plugin (add-on) no Google Chrome, basta você acessar a Chrome Web Store e pesquisar “MetaMask”. Certifique-se de que é a versão legítima da carteira pelo número de downloads (bastante alto, pois é a maior cold wallet da web3), então é só clicar em “Adicionar ao Chrome”. Depois da instalação ser concluída, basta seguir o passo-a-passo proposto na interface da MetaMask para a criação da conta, login e senha. O caminho para a instalação em outros browsers como Firefox, Opera, entre outros navegadores, é o mesmo. \n\n<br>\nNota: Não esqueça de guardar sua seed phrase em um local seguro! Sem ela é impossível recuperar o acesso à sua carteira (caso perca sua senha) e também aos seus cripto ativos, eles serão perdidos - literalmente - para sempre.\n"
},
{
"title": "O que é uma rede (network)?",
"content": "Criptomoedas são transacionadas em redes de computadores, nas blockchains é que ficam armazenadas as informações sobre suas transações, não em um servidor. Existem [diversas redes no ecossistema cripto](https://www.gemini.com/cryptopedia/blockchain-technology-explained), como a rede do Bitcoin, da Ethereum, para citar as duas mais conhecidas. \n<br>\n\n* **Como selecionar a rede?**\nVocê deve ficar atento a rede que está selecionada em sua carteira. Na MetaMask, escolha a você escolhe a rede que vai operar clicando na primeira caixa ao lado do seu avatar:\n![Image Ethereum](/src/assets/faqEthereum.jpeg)\nCaso você copie um endereço na sua MetaMask estando selecionada a Rede Ethereum Mainnet e queira operar na Polygon, seus cripto ativos serão perdidos. \n\n* **O que é taxa de rede (gas fee)?**\nCusto de transação do blockchain. Você paga essa taxa para a rede que vai remunerar os validadores. É uma forma de incentivar os validadores a dar continuidade nos seus serviços. "
}
]
},
{
"name": "2. Comprar tokens",
"items": [
{
"title": "Como comprar?",
"content": "1. Conectar wallet (MetaMask ou WalletConnect)\n2. Digitar amount (quantidade);\n3. Solicitar token (criptomoeda);\n4. Identificar vendedor (da lista de pessoas);\n * Escanear QRCode (ou acrescenta chave manualmente);\n * Colar e2eID (identificação end-to-end) a.k.a. código de identificação (API Pix / comprovante bancário);\n5. Receber na carteira (wallet conectada."
},
{
"title": "O que é uma stablecoin?",
"content": "É uma criptomoeda com lastro em moeda fiduciária (por exemplo, Real brasileiro ou Dólar americando). Cada stablecoin gerada por um projeto emissor tem a mesma quantidade em reserva da moeda fiduciária em seu caixa. Alguns exemplos de stablecoins pareadas com dólar americano são USDt, DAI, USDc. Já vinculadas ao preço do Real são BRZ, MBRL e cREAL.\n<br>\n\n* **O que é o BRZ?**\n [BRZ](https://www.brztoken.io/) é a sigla para Brazilian Digital Token. É um tipo de criptomoeda que tem valor pareado com o Real (BRL). Ou seja, 1 BRZ tem valor igual a 1 BRL."
},
{
"title": "De quem estou comprando?",
"content": "Vendedores fazem as ofertas e indicam a chave-Pix que irão receber o valor transacionado. Essa oferta fica travada no smart contract até que as transações sejam concluídas e você possa fazer o saque dos seus tokens. \n\n<br>\n\n* **Onde encontrar comprovante do Pix?**\n Quando você faz um Pix um comprovante é gerado automaticamente para o pagador e para o recebedor. Esse comprovante pode ser acessado no momento da transação via app/site do banco ou pelo seu extrato bancário convencional.\n* **Para onde vão os tokens que eu comprei?**\n Os tokens comprados terão como destino a carteira que você conectou ao p2pix. \n Nota: Lembre-se sempre de configurar a sua carteira na rede correta em que quer receber seus tokens. "
}
]
},
{
"name": "3. Vender tokens",
"items": [
{
"title": "Como vender?",
"content": "1. Enviar tokens;\n2. Indique sua chave-Pix;\n3. Criar [whitelist](https://academy.binance.com/en/glossary/whitelist) onde quer receber isso;\n4. Withdraw (saque) para remoção dos tokens;\n5. Lock (trava de 24h) para esperar transações antes dos saques.\n"
},
{
"title": "O que é aprovar tokens?",
"content": "Aprovações de tokens funcionam como permissões de sua carteira a um determinado [dApp](https://ethereum.org/en/developers/docs/dapps/) para movimentar os tokens. Ao aprovar tokens, você permite que nosso contrato inteligente acesse e execute as transações na sua carteira web3."
},
{
"title": "O que é o lock na rede?",
"content": "\"Travamento\" na rede é uma forma de especificar um tempo para retirada dos ativos digitais. O contrato inteligente do p2pix 'trava' os tokens enviados para a rede por 24 horas. Só depois de transcorridas essas 24h que o saque dos tokens estará liberado. Isso ocorre para garantir uma transação segura para os vendedores."
},
{
"title": "Como retirar a oferta?",
"content": "Caso você desista da sua oferta, você pode invalidar sua ordem de venda e impedir um novo ‘lock’ na rede."
}
]
}
]
+16
View File
@@ -0,0 +1,16 @@
export const pixFormatValidation = (pixKey: string): boolean => {
const cpf = /(^\d{3}\.?\d{3}\.?\d{3}-?\d{2}$)/g;
const cnpj = /(^\d{2}\.?\d{3}\.?\d{3}\/?\d{4}-?\d{2}$)/g;
const telefone = /(^[0-9]{2})?(\s|-)?(9?[0-9]{4})-?([0-9]{4}$)/g;
if (pixKey.match(cpf) || pixKey.match(cnpj) || pixKey.match(telefone)) {
return true;
}
return false;
};
export const postProcessKey = (pixKey: string): string => {
pixKey = pixKey.replace(/[-.()/]/g, "");
return pixKey;
};
@@ -330,8 +330,8 @@
"type": "function"
}
],
"bytecode": "0x60e06040523480156200001157600080fd5b50604051620010bf380380620010bf833981016040819052620000349162000279565b6040805180820182526007815266135bd8dad0949360ca1b6020808301918252835180850190945260048452631350949360e21b908401528151919291601291620000839160009190620001d3565b50815162000099906001906020850190620001d3565b5060ff81166080524660a052620000af620000ca565b60c05250620000c391503390508262000166565b506200039b565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620000fe9190620002d0565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b80600260008282546200017a919062000374565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b828054620001e19062000293565b90600052602060002090601f01602090048101928262000205576000855562000250565b82601f106200022057805160ff191683800117855562000250565b8280016001018555821562000250579182015b828111156200025057825182559160200191906001019062000233565b506200025e92915062000262565b5090565b5b808211156200025e576000815560010162000263565b6000602082840312156200028c57600080fd5b5051919050565b600181811c90821680620002a857607f821691505b60208210811415620002ca57634e487b7160e01b600052602260045260246000fd5b50919050565b600080835481600182811c915080831680620002ed57607f831692505b60208084108214156200030e57634e487b7160e01b86526022600452602486fd5b818015620003255760018114620003375762000366565b60ff1986168952848901965062000366565b60008a81526020902060005b868110156200035e5781548b82015290850190830162000343565b505084890196505b509498975050505050505050565b600082198211156200039657634e487b7160e01b600052601160045260246000fd5b500190565b60805160a05160c051610cf4620003cb60003960006104630152600061042e015260006101540152610cf46000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806370a082311161008c578063a9059cbb11610066578063a9059cbb146101d8578063d505accf146101eb578063dd62ed3e14610200578063ea66696c1461022b57600080fd5b806370a08231146101905780637ecebe00146101b057806395d89b41146101d057600080fd5b806323b872dd116100bd57806323b872dd1461013c578063313ce5671461014f5780633644e5151461018857600080fd5b806306fdde03146100e4578063095ea7b31461010257806318160ddd14610125575b600080fd5b6100ec61023e565b6040516100f991906108fc565b60405180910390f35b61011561011036600461096d565b6102cc565b60405190151581526020016100f9565b61012e60025481565b6040519081526020016100f9565b61011561014a366004610997565b610338565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f9565b61012e61042a565b61012e61019e3660046109d3565b60036020526000908152604090205481565b61012e6101be3660046109d3565b60056020526000908152604090205481565b6100ec610485565b6101156101e636600461096d565b610492565b6101fe6101f93660046109f5565b61050a565b005b61012e61020e366004610a68565b600460209081526000928352604080842090915290825290205481565b6101fe610239366004610ab1565b6107b1565b6000805461024b90610b7c565b80601f016020809104026020016040519081016040528092919081815260200182805461027790610b7c565b80156102c45780601f10610299576101008083540402835291602001916102c4565b820191906000526020600020905b8154815290600101906020018083116102a757829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103279086815260200190565b60405180910390a350600192915050565b6001600160a01b038316600090815260046020908152604080832033845290915281205460001981146103945761036f8382610bcd565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b038516600090815260036020526040812080548592906103bc908490610bcd565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104179087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104605761045b6107f7565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001805461024b90610b7c565b336000908152600360205260408120805483919083906104b3908490610bcd565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103279086815260200190565b42841015610579576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161058561042a565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a08301939093Line truncated
"deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100df5760003560e01c806370a082311161008c578063a9059cbb11610066578063a9059cbb146101d8578063d505accf146101eb578063dd62ed3e14610200578063ea66696c1461022b57600080fd5b806370a08231146101905780637ecebe00146101b057806395d89b41146101d057600080fd5b806323b872dd116100bd57806323b872dd1461013c578063313ce5671461014f5780633644e5151461018857600080fd5b806306fdde03146100e4578063095ea7b31461010257806318160ddd14610125575b600080fd5b6100ec61023e565b6040516100f991906108fc565b60405180910390f35b61011561011036600461096d565b6102cc565b60405190151581526020016100f9565b61012e60025481565b6040519081526020016100f9565b61011561014a366004610997565b610338565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f9565b61012e61042a565b61012e61019e3660046109d3565b60036020526000908152604090205481565b61012e6101be3660046109d3565b60056020526000908152604090205481565b6100ec610485565b6101156101e636600461096d565b610492565b6101fe6101f93660046109f5565b61050a565b005b61012e61020e366004610a68565b600460209081526000928352604080842090915290825290205481565b6101fe610239366004610ab1565b6107b1565b6000805461024b90610b7c565b80601f016020809104026020016040519081016040528092919081815260200182805461027790610b7c565b80156102c45780601f10610299576101008083540402835291602001916102c4565b820191906000526020600020905b8154815290600101906020018083116102a757829003601f168201915b505050505081565b3360008181526004602090815260408083206001600160a01b038716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103279086815260200190565b60405180910390a350600192915050565b6001600160a01b038316600090815260046020908152604080832033845290915281205460001981146103945761036f8382610bcd565b6001600160a01b03861660009081526004602090815260408083203384529091529020555b6001600160a01b038516600090815260036020526040812080548592906103bc908490610bcd565b90915550506001600160a01b03808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104179087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104605761045b6107f7565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001805461024b90610b7c565b336000908152600360205260408120805483919083906104b3908490610bcd565b90915550506001600160a01b038316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103279086815260200190565b42841015610579576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161058561042a565b6001600160a01b038a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f19010000000000000000000000000000000000000000000000000000000000006101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156106ac573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906106e25750876001600160a01b0316816001600160a01b0316145b610748576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610570565b6001600160a01b0390811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b815160005b818110156107f1576107e18482815181106107d3576107d3610be4565b602002602001015184610891565b6107ea81610bfa565b90506107b6565b50505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516108299190610c15565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b80600260008282546108a39190610ccf565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600060208083528351808285015260005b818110156109295785810183015185820160400152820161090d565b8181111561093b576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461096857600080fd5b919050565b6000806040838503121561098057600080fd5b61098983610951565b946020939093013593505050565b6000806000606084860312156109ac57600080fd5b6109b584610951565b92Line truncated
"bytecode": "0x60e06040523480156200001157600080fd5b506040516200129938038062001299833981016040819052620000349162000279565b6040805180820182526007815266135bd8dad0949360ca1b6020808301918252835180850190945260048452631350949360e21b908401528151919291601291620000839160009190620001d3565b50815162000099906001906020850190620001d3565b5060ff81166080524660a052620000af620000ca565b60c05250620000c391503390508262000166565b506200039b565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620000fe9190620002d0565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b80600260008282546200017a919062000374565b90915550506001600160a01b0382166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b828054620001e19062000293565b90600052602060002090601f01602090048101928262000205576000855562000250565b82601f106200022057805160ff191683800117855562000250565b8280016001018555821562000250579182015b828111156200025057825182559160200191906001019062000233565b506200025e92915062000262565b5090565b5b808211156200025e576000815560010162000263565b6000602082840312156200028c57600080fd5b5051919050565b600181811c90821680620002a857607f821691505b60208210811415620002ca57634e487b7160e01b600052602260045260246000fd5b50919050565b600080835481600182811c915080831680620002ed57607f831692505b60208084108214156200030e57634e487b7160e01b86526022600452602486fd5b818015620003255760018114620003375762000366565b60ff1986168952848901965062000366565b60008a81526020902060005b868110156200035e5781548b82015290850190830162000343565b505084890196505b509498975050505050505050565b600082198211156200039657634e487b7160e01b600052601160045260246000fd5b500190565b60805160a05160c051610ece620003cb60003960006104c20152600061048d015260006101540152610ece6000f3fe608060405234801561001057600080fd5b50600436106100df5760003560e01c806370a082311161008c578063a9059cbb11610066578063a9059cbb146101d8578063d505accf146101eb578063dd62ed3e14610200578063ea66696c1461022b57600080fd5b806370a08231146101905780637ecebe00146101b057806395d89b41146101d057600080fd5b806323b872dd116100bd57806323b872dd1461013c578063313ce5671461014f5780633644e5151461018857600080fd5b806306fdde03146100e4578063095ea7b31461010257806318160ddd14610125575b600080fd5b6100ec61023e565b6040516100f991906109f2565b60405180910390f35b610115610110366004610a8e565b6102cc565b60405190151581526020016100f9565b61012e60025481565b6040519081526020016100f9565b61011561014a366004610ab8565b610345565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f9565b61012e610489565b61012e61019e366004610af4565b60036020526000908152604090205481565b61012e6101be366004610af4565b60056020526000908152604090205481565b6100ec6104e4565b6101156101e6366004610a8e565b6104f1565b6101fe6101f9366004610b16565b610576565b005b61012e61020e366004610b89565b600460209081526000928352604080842090915290825290205481565b6101fe610239366004610beb565b61089a565b6000805461024b90610cd4565b80601f016020809104026020016040519081016040528092919081815260200182805461027790610cd4565b80156102c45780601f10610299576101008083540402835291602001916102c4565b820191906000526020600020905b8154815290600101906020018083116102a757829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103349086815260200190565b60405180910390a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146103d9576103a78382610d57565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff85166000908152600360205260408120805485929061040e908490610d57565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104769087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104bf576104ba6108e0565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001805461024b90610cd4565b33600090815260036020526040812080548391908390610512908490610d57565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103349086815260200190565b428410156105e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b600060016105f1610489Line truncated
"deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100df5760003560e01c806370a082311161008c578063a9059cbb11610066578063a9059cbb146101d8578063d505accf146101eb578063dd62ed3e14610200578063ea66696c1461022b57600080fd5b806370a08231146101905780637ecebe00146101b057806395d89b41146101d057600080fd5b806323b872dd116100bd57806323b872dd1461013c578063313ce5671461014f5780633644e5151461018857600080fd5b806306fdde03146100e4578063095ea7b31461010257806318160ddd14610125575b600080fd5b6100ec61023e565b6040516100f991906109f2565b60405180910390f35b610115610110366004610a8e565b6102cc565b60405190151581526020016100f9565b61012e60025481565b6040519081526020016100f9565b61011561014a366004610ab8565b610345565b6101767f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016100f9565b61012e610489565b61012e61019e366004610af4565b60036020526000908152604090205481565b61012e6101be366004610af4565b60056020526000908152604090205481565b6100ec6104e4565b6101156101e6366004610a8e565b6104f1565b6101fe6101f9366004610b16565b610576565b005b61012e61020e366004610b89565b600460209081526000928352604080842090915290825290205481565b6101fe610239366004610beb565b61089a565b6000805461024b90610cd4565b80601f016020809104026020016040519081016040528092919081815260200182805461027790610cd4565b80156102c45780601f10610299576101008083540402835291602001916102c4565b820191906000526020600020905b8154815290600101906020018083116102a757829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906103349086815260200190565b60405180910390a350600192915050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146103d9576103a78382610d57565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff85166000908152600360205260408120805485929061040e908490610d57565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906104769087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146104bf576104ba6108e0565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6001805461024b90610cd4565b33600090815260036020526040812080548391908390610512908490610d57565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906103349086815260200190565b428410156105e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b600060016105f1610489565b73ffffffffffffffffffffffffffffffffffffffff8a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610743573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116158015906107be57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610824576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e455200000000000000000000000000000000000060448201526064016105dc565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b815160005b818110156108da576108ca8482815181106108bc576108bc610d6e565b60200260200101518461097a565b6108d381610d9d565b905061089f565b50505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516109129190610dd6565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b806002600082825461098c9190610ea9565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040Line truncated
"linkReferences": {},
"deployedLinkReferences": {}
}
+283 -110
View File
@@ -49,11 +49,21 @@
"name": "AmountNotAllowed",
"type": "error"
},
{
"inputs": [],
"name": "DecOverflow",
"type": "error"
},
{
"inputs": [],
"name": "DepositAlreadyExists",
"type": "error"
},
{
"inputs": [],
"name": "EmptyPixTarget",
"type": "error"
},
{
"inputs": [],
"name": "InvalidDeposit",
@@ -79,6 +89,11 @@
"name": "LoopOverflow",
"type": "error"
},
{
"inputs": [],
"name": "MaxBalExceeded",
"type": "error"
},
{
"inputs": [],
"name": "NoTokens",
@@ -94,6 +109,11 @@
"name": "NotExpired",
"type": "error"
},
{
"inputs": [],
"name": "NotInitialized",
"type": "error"
},
{
"inputs": [],
"name": "OnlySeller",
@@ -147,12 +167,6 @@
"name": "seller",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "depositID",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
@@ -180,29 +194,10 @@
},
{
"indexed": false,
"internalType": "uint256",
"name": "depositID",
"type": "uint256"
}
],
"name": "DepositClosed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "seller",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "depositID",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
@@ -243,14 +238,14 @@
},
{
"indexed": true,
"internalType": "bytes32",
"internalType": "uint256",
"name": "lockID",
"type": "bytes32"
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "depositID",
"name": "seller",
"type": "uint256"
},
{
@@ -287,9 +282,9 @@
},
{
"indexed": false,
"internalType": "bytes32",
"internalType": "uint256",
"name": "lockId",
"type": "bytes32"
"type": "uint256"
},
{
"indexed": false,
@@ -312,9 +307,9 @@
},
{
"indexed": false,
"internalType": "bytes32",
"internalType": "uint256",
"name": "lockId",
"type": "bytes32"
"type": "uint256"
}
],
"name": "LockReturned",
@@ -371,6 +366,31 @@
"name": "RootUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "seller",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "state",
"type": "bool"
}
],
"name": "ValidSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
@@ -416,6 +436,25 @@
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_key",
"type": "uint256"
}
],
"name": "_castKeyToAddr",
"outputs": [
{
"internalType": "address",
"name": "_addr",
"type": "address"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [
{
@@ -435,19 +474,6 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "depositID",
"type": "uint256"
}
],
"name": "cancelDeposit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "defaultLockBlocks",
@@ -469,14 +495,19 @@
"type": "address"
},
{
"internalType": "uint256",
"internalType": "uint96",
"name": "_amount",
"type": "uint256"
"type": "uint96"
},
{
"internalType": "string",
"internalType": "uint160",
"name": "_pixTarget",
"type": "string"
"type": "uint160"
},
{
"internalType": "bool",
"name": "_valid",
"type": "bool"
},
{
"internalType": "bytes32",
@@ -485,23 +516,28 @@
}
],
"name": "deposit",
"outputs": [
{
"internalType": "uint256",
"name": "depositID",
"type": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "depositCount",
"inputs": [
{
"internalType": "address",
"name": "seller",
"type": "address"
},
{
"internalType": "contract ERC20",
"name": "token",
"type": "address"
}
],
"name": "getBalance",
"outputs": [
{
"internalType": "uint256",
"name": "_val",
"name": "bal",
"type": "uint256"
}
],
@@ -511,9 +547,110 @@
{
"inputs": [
{
"internalType": "uint256",
"name": "_depositID",
"type": "uint256"
"internalType": "address[]",
"name": "sellers",
"type": "address[]"
},
{
"internalType": "contract ERC20",
"name": "token",
"type": "address"
}
],
"name": "getBalances",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "ids",
"type": "uint256[]"
}
],
"name": "getLocksStatus",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
},
{
"internalType": "enum DataTypes.LockStatus[]",
"name": "",
"type": "uint8[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "seller",
"type": "address"
},
{
"internalType": "contract ERC20",
"name": "token",
"type": "address"
}
],
"name": "getPixTarget",
"outputs": [
{
"internalType": "uint160",
"name": "pixTarget",
"type": "uint160"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "seller",
"type": "address"
},
{
"internalType": "contract ERC20",
"name": "token",
"type": "address"
}
],
"name": "getValid",
"outputs": [
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_seller",
"type": "address"
},
{
"internalType": "address",
"name": "_token",
"type": "address"
},
{
"internalType": "address",
@@ -541,56 +678,30 @@
"type": "bytes32[]"
},
{
"internalType": "bytes32[]",
"internalType": "uint256[]",
"name": "expiredLocks",
"type": "bytes32[]"
"type": "uint256[]"
}
],
"name": "lock",
"outputs": [
{
"internalType": "bytes32",
"name": "lockID",
"type": "bytes32"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "mapDeposits",
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "lockCounter",
"outputs": [
{
"internalType": "uint256",
"name": "remaining",
"name": "",
"type": "uint256"
},
{
"internalType": "string",
"name": "pixTarget",
"type": "string"
},
{
"internalType": "address",
"name": "seller",
"type": "address"
},
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bool",
"name": "valid",
"type": "bool"
}
],
"stateMutability": "view",
@@ -599,16 +710,21 @@
{
"inputs": [
{
"internalType": "bytes32",
"internalType": "uint256",
"name": "",
"type": "bytes32"
"type": "uint256"
}
],
"name": "mapLocks",
"outputs": [
{
"internalType": "uint256",
"name": "depositID",
"name": "sellerKey",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "counter",
"type": "uint256"
},
{
@@ -626,6 +742,11 @@
"name": "expirationBlock",
"type": "uint256"
},
{
"internalType": "uint160",
"name": "pixTarget",
"type": "uint160"
},
{
"internalType": "address",
"name": "buyerAddress",
@@ -640,6 +761,11 @@
"internalType": "address",
"name": "relayerAddress",
"type": "address"
},
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"stateMutability": "view",
@@ -661,9 +787,9 @@
{
"inputs": [
{
"internalType": "bytes32",
"internalType": "uint256",
"name": "lockID",
"type": "bytes32"
"type": "uint256"
},
{
"internalType": "address",
@@ -728,6 +854,30 @@
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "contract ERC20",
"name": "",
"type": "address"
}
],
"name": "sellerBalance",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
@@ -798,6 +948,24 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ERC20",
"name": "token",
"type": "address"
},
{
"internalType": "bool",
"name": "state",
"type": "bool"
}
],
"name": "setValidState",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
@@ -819,9 +987,9 @@
{
"inputs": [
{
"internalType": "bytes32[]",
"internalType": "uint256[]",
"name": "lockIDs",
"type": "bytes32[]"
"type": "uint256[]"
}
],
"name": "unlockExpired",
@@ -888,15 +1056,20 @@
},
{
"inputs": [
{
"internalType": "contract ERC20",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "depositID",
"name": "amount",
"type": "uint256"
},
{
"internalType": "bytes32[]",
"internalType": "uint256[]",
"name": "expiredLocks",
"type": "bytes32[]"
"type": "uint256[]"
}
],
"name": "withdraw",
@@ -916,8 +1089,8 @@
"type": "receive"
}
],
"bytecode": "0x60806040526001805560405162002a9a38038062002a9a8339810160408190526200002a916200049d565b600080546001600160a01b031916339081178255604051909182917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a3506200007685620000a3565b620000818362000133565b6200008c84620001bd565b620000988282620002a1565b505050505062000620565b6000546001600160a01b03163314620000f25760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b806004557f70fa43ca70216ad905ade86b9e650a691b2ce5a01980d0a81bdd8324141b8511816040516200012891815260200190565b60405180910390a150565b6000546001600160a01b031633146200017e5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401620000e9565b60028190556040516001600160a01b03821681527fe127cf589a3879da0156d4a24f43b44f65cfa3570de594806b0bfa2fcf06884f9060200162000128565b6000546001600160a01b03163314620002085760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401620000e9565b80516000905b808210156200026e57600062000246848481518110620002325762000232620005bb565b60200260200101516200038760201b60201c565b6000908152600660205260409020805460ff191660019081179091559290920191506200020e565b50507f14a422d2412784a5749d03da98921fe468c98577b767851389a9f58ea5a363d781604051620001289190620005d1565b6000546001600160a01b03163314620002ec5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401620000e9565b815180620003025763df9578836000526004601cfd5b81518114620003195763ff633a386000526004601cfd5b60208301602083016020830282015b8083146200037f578251600052600b60205260406000208251815550815183517f5d6e86e5341d57a92c49934296c51542a25015c9b1782a1c2722a940131c3d9a600080a360208301925060208201915062000328565b505050505050565b600c1b611000600160ac1b031690565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620003d857620003d862000397565b604052919050565b60006001600160401b03821115620003fc57620003fc62000397565b5060051b60200190565b6001600160a01b03811681146200041c57600080fd5b50565b600082601f8301126200043157600080fd5b815160206200044a6200044483620003e0565b620003ad565b82815260059290921b840181019181810190868411156200046a57600080fd5b8286015b8481101562000492578051620004848162000406565b83529183019183016200046e565b509695505050505050565b600080600080600060a08688031215620004b657600080fd5b8551602080880151919650906001600160401b0380821115620004d857600080fd5b620004e68a838b016200041f565b965060408901519150620004fa8262000406565b6060890151919550808211156200051057600080fd5b6200051e8a838b016200041f565b945060808901519150808211156200053557600080fd5b508701601f810189136200054857600080fd5b8051620005596200044482620003e0565b81815260059190911b8201830190838101908b8311156200057957600080fd5b928401925b82841015620005a95783518015158114620005995760008081fd5b825292840192908401906200057e565b80955050505050509295509295909350565b634e487b7160e01b600052603260045260246000fd5b6020808252825182820181905260009190848201906040850190845b81811015620006145783516001600160a01b031683529284019291840191600101620005ed565b50909695505050505050565b61246a80620006306000396000f3fe6080604052600436106101a55760003560e01c806372fada5c116100e15780638e2749d61161008a57806398a268711161006457806398a268711461056b578063c52164c61461059b578063d6e8b973146105bb578063f7d0e04b146105db57600080fd5b80638e2749d6146105045780638e2a3d36146105245780639872dbfe1461055557600080fd5b80637f94f65d116100bb5780637f94f65d1461048c5780638652b37e146104ac5780638da5cb5b146104cc57600080fd5b806372fada5c1461041f578063758d77d41461043f57806377cd38a41461045f57600080fd5b8063363179721161014e578063574983c811610128578063574983c81461039e5780635fd8c710146103be57806369cc6af4146103d35780636a1460241461040357600080fd5b80633631797214610313578063461f3120146103335780634b2ae9801461037357600080fd5b806316d722401161017f57806316d722401461023357806329cc7d10146102dc5780632dfdf0b5146102fc57600080fd5b806304937320146101b15780630d2a2d44146101f157806313af40351461021357600080fd5b366101ac57005b600080fd5b3480156101bd57600080fd5b506101de6101cc366004611d07565b60056020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156101fd57600080fd5b5061021161020c366004611e14565b6105fb565b005b34801561021f57600080fd5b5061021161022e366004611e51565b6106ec565b34801561023f57600080fd5b5061029861024e366004611d07565b600860205260009081526040902080546001820154600283015460038401546004850154600586015460069096015494959394929391926001600160a01b03918216928216911687565b6040805197885260208801969096529486019390935260608501919091526001600160a01b03908116608085015290811660a08401521660c082015260e0016101e8565b3480156102e857600080fd5b506101de6102f7366004611e6e565b61078d565b34801561030857600080fd5b506003546101de9081565b34801561031f57600080fd5b5061021161032e366004611f4b565b610991565b34801561033f57600080fd5b5061036361034e366004611d07565b60096020526000908152604090205460ff1681565b60405190151581526020016101e8565b34801561037f57600080fd5b506101de61038e36600461Line truncated
"deployedBytecode": "0x6080604052600436106101a55760003560e01c806372fada5c116100e15780638e2749d61161008a57806398a268711161006457806398a268711461056b578063c52164c61461059b578063d6e8b973146105bb578063f7d0e04b146105db57600080fd5b80638e2749d6146105045780638e2a3d36146105245780639872dbfe1461055557600080fd5b80637f94f65d116100bb5780637f94f65d1461048c5780638652b37e146104ac5780638da5cb5b146104cc57600080fd5b806372fada5c1461041f578063758d77d41461043f57806377cd38a41461045f57600080fd5b8063363179721161014e578063574983c811610128578063574983c81461039e5780635fd8c710146103be57806369cc6af4146103d35780636a1460241461040357600080fd5b80633631797214610313578063461f3120146103335780634b2ae9801461037357600080fd5b806316d722401161017f57806316d722401461023357806329cc7d10146102dc5780632dfdf0b5146102fc57600080fd5b806304937320146101b15780630d2a2d44146101f157806313af40351461021357600080fd5b366101ac57005b600080fd5b3480156101bd57600080fd5b506101de6101cc366004611d07565b60056020526000908152604090205481565b6040519081526020015b60405180910390f35b3480156101fd57600080fd5b5061021161020c366004611e14565b6105fb565b005b34801561021f57600080fd5b5061021161022e366004611e51565b6106ec565b34801561023f57600080fd5b5061029861024e366004611d07565b600860205260009081526040902080546001820154600283015460038401546004850154600586015460069096015494959394929391926001600160a01b03918216928216911687565b6040805197885260208801969096529486019390935260608501919091526001600160a01b03908116608085015290811660a08401521660c082015260e0016101e8565b3480156102e857600080fd5b506101de6102f7366004611e6e565b61078d565b34801561030857600080fd5b506003546101de9081565b34801561031f57600080fd5b5061021161032e366004611f4b565b610991565b34801561033f57600080fd5b5061036361034e366004611d07565b60096020526000908152604090205460ff1681565b60405190151581526020016101e8565b34801561037f57600080fd5b506101de61038e366004611e51565b600c1b611000600160ac1b031690565b3480156103aa57600080fd5b506102116103b9366004611d07565b610a51565b3480156103ca57600080fd5b50610211610acf565b3480156103df57600080fd5b506103636103ee366004611e51565b600b6020526000908152604090205460ff1681565b34801561040f57600080fd5b506101de670de0b6b3a764000081565b34801561042b57600080fd5b5061021161043a366004611d07565b610b59565b34801561044b57600080fd5b5061021161045a366004611f97565b610be1565b34801561046b57600080fd5b506101de61047a366004611d07565b600a6020526000908152604090205481565b34801561049857600080fd5b506102116104a7366004611ffb565b61103a565b3480156104b857600080fd5b506101de6104c7366004612027565b6110e6565b3480156104d857600080fd5b506000546104ec906001600160a01b031681565b6040516001600160a01b0390911681526020016101e8565b34801561051057600080fd5b5061021161051f3660046120db565b611311565b34801561053057600080fd5b5061054461053f366004611d07565b611479565b6040516101e895949392919061211d565b34801561056157600080fd5b506101de60045481565b34801561057757600080fd5b50610363610586366004611d07565b60066020526000908152604090205460ff1681565b3480156105a757600080fd5b506002546104ec906001600160a01b031681565b3480156105c757600080fd5b506102116105d63660046121aa565b611543565b3480156105e757600080fd5b506102116105f6366004611e51565b61161b565b6000546001600160a01b031633146106495760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b80516000905b808210156106b057600061068984848151811061066e5761066e612274565b6020026020010151611000600160ac1b03600c9190911b1690565b6000908152600660205260409020805460ff1916600190811790915592909201915061064f565b50507f14a422d2412784a5749d03da98921fe468c98577b767851389a9f58ea5a363d7816040516106e1919061228a565b60405180910390a150565b6000546001600160a01b031633146107355760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401610640565b6000805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b6001600160a01b0385166000908152600b6020526040812054869060ff166107e1576040517f1578328e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107e96116a2565b915060006040518060a0016040528088815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050908252503360208201526001600160a01b038a1660408201526001606090910152905061085e6116b2565b831561086e5761086e338561103a565b600083815260076020908152604090912082518155818301518051849361089c926001850192910190611c6e565b5060408201516002820180546001600160a01b0392831673ffffffffffffffffffffffffffffffffffffffff199091161790556060830151600392830180546080909501511515600160a01b027fffffffffffffffffffffff0000000000000000000000000000000000000000009095169190921617929092179091556109269080546001019055565b6109328233308a6116f6565b61093b60018055565b604080518481526001600160a01b038a16602082015290810188905233907f25ac57b911b0f66b64c294827f539545fbc3ddd002cafab117776274f3241e4c9060600160405180910390a2505095945050505050565b6109996116b2565b6109a2836117a6565b6109ac8282611311565b60008381526007602052Line truncated
"bytecode": "0x6080604052600180556040516200366e3803806200366e8339810160408190526200002a9162000493565b600080546001600160a01b031916339081178255604051909182917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a3506200007685620000a3565b620000818362000133565b6200008c84620001bd565b620000988282620002a1565b505050505062000616565b6000546001600160a01b03163314620000f25760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b60448201526064015b60405180910390fd5b806003557f70fa43ca70216ad905ade86b9e650a691b2ce5a01980d0a81bdd8324141b8511816040516200012891815260200190565b60405180910390a150565b6000546001600160a01b031633146200017e5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401620000e9565b60028190556040516001600160a01b03821681527fe127cf589a3879da0156d4a24f43b44f65cfa3570de594806b0bfa2fcf06884f9060200162000128565b6000546001600160a01b03163314620002085760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401620000e9565b80516000905b808210156200026e57600062000246848481518110620002325762000232620005b1565b60200260200101516200038760201b60201c565b6000908152600860205260409020805460ff191660019081179091559290920191506200020e565b50507f14a422d2412784a5749d03da98921fe468c98577b767851389a9f58ea5a363d781604051620001289190620005c7565b6000546001600160a01b03163314620002ec5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401620000e9565b815180620003025763df9578836000526004601cfd5b81518114620003195763ff633a386000526004601cfd5b60208301602083018260051b82015b8083146200037f578251600052600a60205260406000208251815550815183517f5d6e86e5341d57a92c49934296c51542a25015c9b1782a1c2722a940131c3d9a600080a360208301925060208201915062000328565b505050505050565b600c1b90565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620003ce57620003ce6200038d565b604052919050565b60006001600160401b03821115620003f257620003f26200038d565b5060051b60200190565b6001600160a01b03811681146200041257600080fd5b50565b600082601f8301126200042757600080fd5b81516020620004406200043a83620003d6565b620003a3565b82815260059290921b840181019181810190868411156200046057600080fd5b8286015b84811015620004885780516200047a81620003fc565b835291830191830162000464565b509695505050505050565b600080600080600060a08688031215620004ac57600080fd5b8551602080880151919650906001600160401b0380821115620004ce57600080fd5b620004dc8a838b0162000415565b965060408901519150620004f082620003fc565b6060890151919550808211156200050657600080fd5b620005148a838b0162000415565b945060808901519150808211156200052b57600080fd5b508701601f810189136200053e57600080fd5b80516200054f6200043a82620003d6565b81815260059190911b8201830190838101908b8311156200056f57600080fd5b928401925b828410156200059f57835180151581146200058f5760008081fd5b8252928401929084019062000574565b80955050505050509295509295909350565b634e487b7160e01b600052603260045260246000fd5b6020808252825182820181905260009190848201906040850190845b818110156200060a5783516001600160a01b031683529284019291840191600101620005e3565b50909695505050505050565b61304880620006266000396000f3fe6080604052600436106101e75760003560e01c80637f94f65d11610102578063ad8f2eed11610095578063d4fac45d11610064578063d4fac45d1461074c578063d6e8b97314610797578063f7d0e04b146107b7578063fb8c5ef0146107d757600080fd5b8063ad8f2eed14610692578063b0983d39146106d2578063c52164c6146106f2578063d1c070281461071f57600080fd5b80638db564c2116100d15780638db564c2146105fe5780639872dbfe1461061457806398a268711461062a5780639eee8d4b1461065a57600080fd5b80637f94f65d1461052b57806380e1d3021461054b57806384ab1d281461058b5780638da5cb5b146105d157600080fd5b80634b2ae9801161017a5780636a146024116101495780636a146024146104a25780636d82d9e0146104be57806374ba03a0146104de57806377cd38a4146104fe57600080fd5b80634b2ae9801461041c578063574983c81461043d5780635fd8c7101461045d57806369cc6af41461047257600080fd5b8063328a7181116101b6578063328a718114610295578063367821f0146102b5578063461f3120146103ae57806349ef8448146103ee57600080fd5b806304937320146101f35780630a98b9bd146102335780630d2a2d441461025357806313af40351461027557600080fd5b366101ee57005b600080fd5b3480156101ff57600080fd5b5061022061020e3660046126f1565b60076020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561023f57600080fd5b5061022061024e366004612778565b6107f7565b34801561025f57600080fd5b5061027361026e36600461295f565b610ba6565b005b34801561028157600080fd5b5061027361029036600461299c565b610ce0565b3480156102a157600080fd5b506102736102b03660046129d5565b610dd1565b3480156102c157600080fd5b506103426102d03660046126f1565b6005602081905260009182526040909120805460018201546002830154600384015460048501549585015460068601546007870154600888015460099098015496989597949693959473ffffffffffffffffffffffffffffffffffffffff93841694928416939182169290821691168a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925273ffffffffffffffffffffffffffffffffffffffff90811660a087015290811660c086015290811660e08501Line truncated
"deployedBytecode": "0x6080604052600436106101e75760003560e01c80637f94f65d11610102578063ad8f2eed11610095578063d4fac45d11610064578063d4fac45d1461074c578063d6e8b97314610797578063f7d0e04b146107b7578063fb8c5ef0146107d757600080fd5b8063ad8f2eed14610692578063b0983d39146106d2578063c52164c6146106f2578063d1c070281461071f57600080fd5b80638db564c2116100d15780638db564c2146105fe5780639872dbfe1461061457806398a268711461062a5780639eee8d4b1461065a57600080fd5b80637f94f65d1461052b57806380e1d3021461054b57806384ab1d281461058b5780638da5cb5b146105d157600080fd5b80634b2ae9801161017a5780636a146024116101495780636a146024146104a25780636d82d9e0146104be57806374ba03a0146104de57806377cd38a4146104fe57600080fd5b80634b2ae9801461041c578063574983c81461043d5780635fd8c7101461045d57806369cc6af41461047257600080fd5b8063328a7181116101b6578063328a718114610295578063367821f0146102b5578063461f3120146103ae57806349ef8448146103ee57600080fd5b806304937320146101f35780630a98b9bd146102335780630d2a2d441461025357806313af40351461027557600080fd5b366101ee57005b600080fd5b3480156101ff57600080fd5b5061022061020e3660046126f1565b60076020526000908152604090205481565b6040519081526020015b60405180910390f35b34801561023f57600080fd5b5061022061024e366004612778565b6107f7565b34801561025f57600080fd5b5061027361026e36600461295f565b610ba6565b005b34801561028157600080fd5b5061027361029036600461299c565b610ce0565b3480156102a157600080fd5b506102736102b03660046129d5565b610dd1565b3480156102c157600080fd5b506103426102d03660046126f1565b6005602081905260009182526040909120805460018201546002830154600384015460048501549585015460068601546007870154600888015460099098015496989597949693959473ffffffffffffffffffffffffffffffffffffffff93841694928416939182169290821691168a565b604080519a8b5260208b0199909952978901969096526060880194909452608087019290925273ffffffffffffffffffffffffffffffffffffffff90811660a087015290811660c086015290811660e0850152908116610100840152166101208201526101400161022a565b3480156103ba57600080fd5b506103de6103c93660046126f1565b60096020526000908152604090205460ff1681565b604051901515815260200161022a565b3480156103fa57600080fd5b5061040e610409366004612a48565b611012565b60405161022a929190612b43565b34801561042857600080fd5b5061022061043736600461299c565b600c1b90565b34801561044957600080fd5b506102736104583660046126f1565b6112f5565b34801561046957600080fd5b506102736113ab565b34801561047e57600080fd5b506103de61048d36600461299c565b600a6020526000908152604090205460ff1681565b3480156104ae57600080fd5b50610220670de0b6b3a764000081565b3480156104ca57600080fd5b506102736104d9366004612bd2565b61146d565b3480156104ea57600080fd5b506102736104f9366004612c07565b611584565b34801561050a57600080fd5b506102206105193660046126f1565b60066020526000908152604090205481565b34801561053757600080fd5b50610273610546366004612c6b565b611a63565b34801561055757600080fd5b506103de610566366004612c97565b600c9190911b6000908152600b60209081526040808320938352929052205460ff1c90565b34801561059757600080fd5b506105ac6105a63660046126f1565b600c1c90565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161022a565b3480156105dd57600080fd5b506000546105ac9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561060a57600080fd5b5061022060045481565b34801561062057600080fd5b5061022060035481565b34801561063657600080fd5b506103de6106453660046126f1565b60086020526000908152604090205460ff1681565b34801561066657600080fd5b50610220610675366004612cd0565b600b60209081526000928352604080842090915290825290205481565b34801561069e57600080fd5b506105ac6106ad366004612c97565b600c9190911b6000908152600b602090815260408083209383529290522054605f1c90565b3480156106de57600080fd5b506102736106ed366004612cf5565b611b29565b3480156106fe57600080fd5b506002546105ac9073ffffffffffffffffffffffffffffffffffffffff1681565b34801561072b57600080fd5b5061073f61073a366004612d2b565b611d6c565b60405161022a9190612d72565b34801561075857600080fd5b50610220610767366004612c97565b600c9190911b6000908152600b6020908152604080832093835292905220546b3fffffffffffffffffffffff1690565b3480156107a357600080fd5b506102736107b2366004612d85565b611e46565b3480156107c357600080fd5b506102736107d236600461299c565b611f56565b3480156107e357600080fd5b506102736107f2366004612e47565b612022565b600061080161211e565b61080b8383611b29565b600c8b901b6000908152600b602090815260408083208d84529091529020548a9060ff1c610865576040517fb2e532de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8c901b6000908152600b602090815260408083208484529091529020546b3fffffffffffffffffffffff16878110156108cc576040517f22bbb43c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006108d88e600c1b90565b9050600060045460016108eb9190612ed2565b6000818152600560205260409020600401549091504311610938576040517fd0404f8500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006040518061014001604052808481526020018381526020018d81526020018c81526020016003544361096c9190612ed2565b8152602001605f600b600087815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681Line truncated
"linkReferences": {},
"deployedLinkReferences": {}
}
@@ -1,8 +0,0 @@
{
"signers": [
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
],
"p2pix": "0x5f3EFA9A90532914545CEf527C530658af87e196",
"token": "0x294003F602c321627152c6b7DED3EAb5bEa853Ee"
}
@@ -1,8 +0,0 @@
{
"signers": [
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
],
"p2pix": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0",
"token": "0x5FbDB2315678afecb367f032d93F642f64180aa3"
}
@@ -1,8 +0,0 @@
{
"signers": [
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
],
"p2pix": "0x5f3EFA9A90532914545CEf527C530658af87e196",
"token": "0x294003F602c321627152c6b7DED3EAb5bEa853Ee"
}
@@ -1,6 +0,0 @@
{
"wallets":[
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC"
]
}
+31 -76
View File
@@ -2,69 +2,9 @@
import type { Faq } from "@/model/Faq";
import { ref } from "vue";
import { marked } from "marked";
import faqContent from "@/utils/files/faqContent.json";
const faq = ref<Faq>([
{
name: "1. Como Começar",
items: [
{
title: "O que é uma carteira (wallet)",
content:
"# Lorem ipsum dolor sit **amet** consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
{
title: "O que é uma carteira (wallet)",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
{
title: "O que é uma carteira (wallet)",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
],
},
{
name: "2. Comprar tokens",
items: [
{
title: "O que é um endereço de carteira (wallet address)",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
{
title: "O que é um endereço de carteira (wallet address)",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
{
title: "O que é um endereço de carteira (wallet address)",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
],
},
{
name: "3. Vender tokens",
items: [
{
title: "Como conectar a carteira ao p2pix",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
{
title: "Como conectar a carteira ao p2pix",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
{
title: "Como conectar a carteira ao p2pix",
content:
"Lorem ipsum dolor sit amet consectetur. Neque libero magna mi purus. Aliquam vitae feugiat quis sapien. Pharetra gravida nisi donec bibendum mauris aliquam molestie. Et nunc placerat in ac integer maecenas arcu. Lotuam tincidunt morbi ac sed fames habitasse velit et nunc.",
},
],
},
]);
const faq = ref<Faq>(faqContent);
const selectedSection = ref<number>(0);
@@ -76,9 +16,15 @@ const openItem = (index: number) => {
faq.value[selectedSection.value].items[index].isOpen =
!faq.value[selectedSection.value].items[index].isOpen;
marked.setOptions({
breaks: true,
gfm: true,
});
faq.value[selectedSection.value].items[index].content = marked(
faq.value[selectedSection.value].items[index].content
);
console.log(marked(faq.value[selectedSection.value].items[index].content));
};
</script>
@@ -96,7 +42,7 @@ const openItem = (index: number) => {
<div class="flex justify-between w-10/12 mt-20">
<div>
<h1 class="text-3xl text-gray-800 font-bold">Sumário</h1>
<h1 class="text-3xl text-white font-bold">Sumário</h1>
<h3
:class="index == selectedSection ? 'selected-sumario' : 'sumario'"
v-for="(f, index) in faq"
@@ -125,13 +71,9 @@ const openItem = (index: number) => {
class="mr-3"
v-if="item.isOpen"
/>
<h4>{{ item.title }}</h4>
<h4 class="text-white">{{ item.title }}</h4>
</div>
<div
style="padding-top: 24px"
v-if="item.isOpen"
v-html="item.content"
></div>
<div class="content" v-if="item.isOpen" v-html="item.content"></div>
<div class="hr"></div>
</div>
</div>
@@ -154,17 +96,30 @@ const openItem = (index: number) => {
@apply flex flex-col items-center justify-center w-full mt-16;
}
div.content {
padding-top: 24px;
color: white;
}
.content :deep(ul) {
@apply list-disc m-2 p-3;
}
.content :deep(ol) {
@apply list-decimal m-2 p-3;
}
.content :deep(ol ul) {
@apply list-disc m-1 p-1;
}
.hr {
border: 1px solid #1f2937;
margin: 24px 0;
}
p,
h2,
h3,
h4 {
@apply text-gray-800 text-xl;
color: #1f2937;
h3 {
@apply text-white;
}
h2,
@@ -177,7 +132,7 @@ h4 {
}
.text {
@apply text-gray-800 text-center;
@apply text-white text-center;
}
.blur-container-row {
@apply flex flex-row justify-center items-center px-8 py-6 gap-2 rounded-lg shadow-md shadow-gray-600 backdrop-blur-md mt-8 w-1/3;
+76 -33
View File
@@ -1,19 +1,17 @@
<script setup lang="ts">
import SearchComponent from "@/components/SearchComponent.vue";
import ValidationComponent from "@/components/LoadingComponent.vue";
import LoadingComponent from "@/components/LoadingComponent/LoadingComponent.vue";
import BuyConfirmedComponent from "@/components/BuyConfirmedComponent/BuyConfirmedComponent.vue";
import { ref, onMounted } from "vue";
import { ref, onMounted, watch } from "vue";
import { useEtherStore } from "@/store/ether";
import QrCodeComponent from "@/components/QrCodeComponent.vue";
import { storeToRefs } from "pinia";
import { addLock, releaseLock } from "@/blockchain/buyerMethods";
import {
updateWalletStatus,
listReleaseTransactionByWalletAddress,
} from "@/blockchain/wallet";
import { updateWalletStatus, checkUnreleasedLock } from "@/blockchain/wallet";
import { getNetworksLiquidity } from "@/blockchain/events";
import type { Event } from "ethers";
import type { ValidDeposit } from "@/model/ValidDeposit";
import { getUnreleasedLockById } from "@/blockchain/events";
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
enum Step {
Search,
@@ -25,13 +23,15 @@ const etherStore = useEtherStore();
etherStore.setSellerView(false);
// States
const { loadingLock, walletAddress } = storeToRefs(etherStore);
const { loadingLock, walletAddress, networkName } = storeToRefs(etherStore);
const flowStep = ref<Step>(Step.Search);
const pixTarget = ref<string>("");
const pixTarget = ref<number>();
const tokenAmount = ref<number>();
const _lockID = ref<string>("");
const lockID = ref<string>("");
const loadingRelease = ref<boolean>(false);
const lastWalletReleaseTransactions = ref<Event[]>([]);
const showModal = ref<boolean>(false);
const showBuyAlert = ref<boolean>(false);
const paramLockID = window.history.state?.lockID;
const confirmBuyClick = async (
selectedDeposit: ValidDeposit,
@@ -46,9 +46,9 @@ const confirmBuyClick = async (
flowStep.value = Step.Buy;
etherStore.setLoadingLock(true);
await addLock(selectedDeposit.depositID, tokenValue)
.then((lockID) => {
_lockID.value = lockID;
await addLock(selectedDeposit.seller, selectedDeposit.token, tokenValue)
.then((_lockID) => {
lockID.value = _lockID;
})
.catch((err) => {
console.log(err);
@@ -61,31 +61,60 @@ const confirmBuyClick = async (
const releaseTransaction = async (e2eId: string) => {
flowStep.value = Step.List;
showBuyAlert.value = true;
loadingRelease.value = true;
if (_lockID.value && tokenAmount.value) {
if (lockID.value && tokenAmount.value && pixTarget.value) {
const release = await releaseLock(
pixTarget.value,
tokenAmount.value,
e2eId,
_lockID.value
lockID.value
);
release.wait();
await listReleaseTransactionByWalletAddress(
walletAddress.value.toLowerCase()
).then((releaseTransactions) => {
if (releaseTransactions)
lastWalletReleaseTransactions.value = releaseTransactions;
});
await release.wait();
await updateWalletStatus();
loadingRelease.value = false;
}
};
const checkForUnreleasedLocks = async (): Promise<void> => {
const walletLocks = await checkUnreleasedLock(walletAddress.value);
if (walletLocks) {
lockID.value = walletLocks.lockID;
tokenAmount.value = walletLocks.pix.value;
pixTarget.value = Number(walletLocks.pix.pixKey);
showModal.value = true;
} else {
flowStep.value = Step.Search;
showModal.value = false;
}
};
if (paramLockID) {
const lockToRedirect = await getUnreleasedLockById(paramLockID as string);
if (lockToRedirect) {
lockID.value = lockToRedirect.lockID;
tokenAmount.value = lockToRedirect.pix.value;
pixTarget.value = Number(lockToRedirect.pix.pixKey);
flowStep.value = Step.Buy;
} else {
flowStep.value = Step.Search;
}
} else {
watch(walletAddress, async () => {
await checkForUnreleasedLocks();
});
watch(networkName, async () => {
if (walletAddress.value) await checkForUnreleasedLocks();
});
}
onMounted(async () => {
await getNetworksLiquidity();
if (walletAddress.value && !paramLockID) await checkForUnreleasedLocks();
window.history.state.lockID = "";
});
</script>
@@ -94,26 +123,40 @@ onMounted(async () => {
v-if="flowStep == Step.Search"
@token-buy="confirmBuyClick"
/>
<CustomAlert
v-if="flowStep == Step.Search && showModal"
:type="'redirect'"
@close-alert="showModal = false"
@go-to-lock="flowStep = Step.Buy"
/>
<CustomAlert
v-if="
flowStep == Step.List && showBuyAlert && !loadingLock && !loadingRelease
"
:type="'buy'"
@close-alert="showBuyAlert = false"
/>
<div v-if="flowStep == Step.Buy">
<QrCodeComponent
:pixTarget="pixTarget"
:pixTarget="String(pixTarget)"
:tokenValue="tokenAmount"
@pix-validated="releaseTransaction"
v-if="!loadingLock"
/>
<ValidationComponent
<LoadingComponent
v-if="loadingLock"
:message="'A transação está sendo enviada para a rede'"
/>
</div>
<div v-if="flowStep == Step.List">
<BuyConfirmedComponent
v-if="!loadingRelease"
:last-wallet-release-transactions="lastWalletReleaseTransactions"
:tokenAmount="tokenAmount"
@make-another-transaction="flowStep = Step.Search"
/>
<ValidationComponent
<div class="flex flex-col gap-10" v-if="!loadingRelease">
<BuyConfirmedComponent
:tokenAmount="tokenAmount"
:is-current-step="flowStep == Step.List"
@make-another-transaction="flowStep = Step.Search"
/>
</div>
<LoadingComponent
v-if="loadingRelease"
:message="'A transação está sendo enviada para a rede. Em breve os tokens serão depositados em sua carteira.'"
/>
+81 -41
View File
@@ -2,75 +2,115 @@
import { useEtherStore } from "@/store/ether";
import { storeToRefs } from "pinia";
import ListingComponent from "@/components/ListingComponent/ListingComponent.vue";
import type { BigNumber } from "ethers";
import LoadingComponent from "@/components/LoadingComponent/LoadingComponent.vue";
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
import { ref, watch, onMounted } from "vue";
import { cancelDeposit, withdrawDeposit } from "@/blockchain/buyerMethods";
import { listValidDepositTransactionsByWalletAddress } from "@/blockchain/wallet";
import {
listValidDepositTransactionsByWalletAddress,
listAllTransactionByWalletAddress,
getActiveLockAmount,
} from "@/blockchain/wallet";
import { withdrawDeposit } from "@/blockchain/buyerMethods";
import type { ValidDeposit } from "@/model/ValidDeposit";
import type { WalletTransaction } from "@/model/WalletTransaction";
import router from "@/router/index";
const etherStore = useEtherStore();
const { walletAddress, networkName } = storeToRefs(etherStore);
const depositList = ref<ValidDeposit[]>([]);
const loadingWithdraw = ref<boolean>(false);
const showAlert = ref<boolean>(false);
onMounted(async () => {
const depositList = ref<ValidDeposit[]>([]);
const transactionsList = ref<WalletTransaction[]>([]);
const activeLockAmount = ref<number>(0);
const callWithdraw = async (amount: string) => {
if (amount) {
loadingWithdraw.value = true;
let withdraw;
try {
withdraw = await withdrawDeposit(amount);
} catch {
loadingWithdraw.value = false;
}
if (withdraw) {
console.log("Saque realizado!");
await getWalletTransactions();
showAlert.value = true;
} else {
console.log("Não foi possível realizar o saque!");
}
loadingWithdraw.value = false;
}
};
const getWalletTransactions = async () => {
etherStore.setLoadingWalletTransactions(true);
if (walletAddress.value) {
const walletDeposits = await listValidDepositTransactionsByWalletAddress(
walletAddress.value
);
const allUserTransactions = await listAllTransactionByWalletAddress(
walletAddress.value
);
activeLockAmount.value = await getActiveLockAmount(walletAddress.value);
if (walletDeposits) {
depositList.value = walletDeposits;
}
if (allUserTransactions) {
transactionsList.value = allUserTransactions;
}
}
etherStore.setLoadingWalletTransactions(false);
};
onMounted(async () => {
if (!walletAddress.value) {
router.push({ name: "home" });
}
await getWalletTransactions();
});
const handleCancelDeposit = async (depositID: BigNumber, index: number) => {
const response = await cancelDeposit(depositID);
if (response) {
console.log("Depósito cancelado com sucesso.");
depositList.value.splice(index, 1);
}
};
const handleWithDrawDeposit = async (depositID: BigNumber, index: number) => {
const response = await withdrawDeposit(depositID);
if (response) {
console.log("Token retirado com sucesso.");
depositList.value.splice(index, 1);
}
};
watch(walletAddress, async () => {
await listValidDepositTransactionsByWalletAddress(walletAddress.value)
.then((res) => {
if (res) depositList.value = res;
})
.catch(() => {
depositList.value = [];
});
await getWalletTransactions();
});
watch(networkName, async () => {
await listValidDepositTransactionsByWalletAddress(walletAddress.value)
.then((res) => {
if (res) depositList.value = res;
})
.catch(() => {
depositList.value = [];
});
await getWalletTransactions();
});
</script>
<template>
<CustomAlert
v-if="showAlert"
:type="'withdraw'"
@close-alert="showAlert = false"
/>
<div class="page">
<div class="header">Gerenciar ofertas</div>
<div class="header" v-if="!loadingWithdraw && !walletAddress">
Por Favor Conecte Sua Carteira
</div>
<div class="header" v-if="!loadingWithdraw && walletAddress">
Gerenciar Ofertas
</div>
<div class="w-full max-w-4xl">
<ListingComponent
:wallet-transactions="depositList"
:is-manage-mode="true"
@cancel-deposit="handleCancelDeposit"
@withdraw-deposit="handleWithDrawDeposit"
v-if="!loadingWithdraw && walletAddress"
:valid-deposits="depositList"
:wallet-transactions="transactionsList"
:active-lock-amount="activeLockAmount"
@deposit-withdrawn="callWithdraw"
></ListingComponent>
<LoadingComponent
v-if="loadingWithdraw"
:message="'A transação está sendo enviada para a rede. Em breve os tokens serão depositados em sua carteira.'"
/>
</div>
</div>
</template>
@@ -81,6 +121,6 @@ watch(networkName, async () => {
}
.header {
@apply text-3xl text-gray-900 leading-9 font-bold justify-center flex;
@apply text-3xl text-white leading-9 font-bold justify-center flex;
}
</style>
+19 -8
View File
@@ -1,11 +1,12 @@
<script setup lang="ts">
import WantSellComponent from "../components/SellerSteps/WantSellComponent.vue";
import SendNetwork from "../components/SellerSteps/SendNetwork.vue";
import ValidationComponent from "../components/LoadingComponent.vue";
import { approveTokens, addDeposit } from "../blockchain/sellerMethods";
import WantSellComponent from "@/components/SellerSteps/WantSellComponent.vue";
import SendNetwork from "@/components/SellerSteps/SendNetwork.vue";
import LoadingComponent from "@/components/LoadingComponent/LoadingComponent.vue";
import { approveTokens, addDeposit } from "@/blockchain/sellerMethods";
import { ref } from "vue";
import { useEtherStore } from "@/store/ether";
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
enum Step {
Search,
@@ -21,13 +22,17 @@ const loading = ref<boolean>(false);
const offerValue = ref<string>("");
const pixKeyBuyer = ref<string>("");
const showAlert = ref<boolean>(false);
// Verificar tipagem
const approveOffer = async (args: { offer: string; pixKey: string }) => {
const approveOffer = async (args: {
offer: string;
postProcessedPixKey: string;
}) => {
loading.value = true;
try {
offerValue.value = args.offer;
pixKeyBuyer.value = args.pixKey;
pixKeyBuyer.value = args.postProcessedPixKey;
await approveTokens(args.offer);
flowStep.value = Step.Network;
loading.value = false;
@@ -45,6 +50,7 @@ const sendNetwork = async () => {
await addDeposit(String(offerValue.value), pixKeyBuyer.value);
flowStep.value = Step.Sell;
loading.value = false;
showAlert.value = true;
}
} catch (err) {
console.log(err);
@@ -57,11 +63,16 @@ const sendNetwork = async () => {
<template>
<div v-if="flowStep == Step.Sell">
<WantSellComponent v-if="!loading" @approve-tokens="approveOffer" />
<ValidationComponent
<LoadingComponent
v-if="loading"
:message="'A transação está sendo enviada para a rede.'"
/>
</div>
<CustomAlert
v-if="flowStep == Step.Sell && showAlert"
:type="'sell'"
@close-alert="showAlert = false"
/>
<div v-if="flowStep == Step.Network">
<SendNetwork
:pixKey="pixKeyBuyer"
@@ -69,7 +80,7 @@ const sendNetwork = async () => {
v-if="!loading"
@send-network="sendNetwork"
/>
<ValidationComponent
<LoadingComponent
v-if="loading"
:message="'A transação está sendo enviada para a rede.'"
/>
-63
View File
@@ -1,63 +0,0 @@
<script setup lang="ts">
import { useEtherStore } from "@/store/ether";
import { storeToRefs } from "pinia";
import { ref, watch, onMounted } from "vue";
import ListingComponent from "@/components/ListingComponent/ListingComponent.vue";
import { listAllTransactionByWalletAddress } from "@/blockchain/wallet";
import type { Event } from "ethers";
import type { ValidDeposit } from "@/model/ValidDeposit";
const etherStore = useEtherStore();
const { walletAddress, networkName } = storeToRefs(etherStore);
const allUserTransactions = ref<(Event | ValidDeposit)[]>([]);
onMounted(async () => {
if (walletAddress.value) {
await listAllTransactionByWalletAddress(walletAddress.value).then((res) => {
if (res) allUserTransactions.value = res;
});
}
});
watch(walletAddress, async (newValue) => {
await listAllTransactionByWalletAddress(newValue)
.then((res) => {
if (res) allUserTransactions.value = res;
})
.catch(() => {
allUserTransactions.value = [];
});
});
watch(networkName, async () => {
await listAllTransactionByWalletAddress(walletAddress.value)
.then((res) => {
if (res) allUserTransactions.value = res;
})
.catch(() => {
allUserTransactions.value = [];
});
});
</script>
<template>
<div class="page">
<div class="header">Histórico de transações</div>
<div class="w-full max-w-4xl">
<ListingComponent
:wallet-transactions="allUserTransactions"
:is-manage-mode="false"
></ListingComponent>
</div>
</div>
</template>
<style scoped>
.page {
@apply flex flex-col gap-10 mt-20 w-full items-center;
}
.header {
@apply text-3xl text-gray-900 leading-9 font-bold justify-center flex;
}
</style>
+1
View File
@@ -13,6 +13,7 @@ export default defineConfig({
provider: "c8",
all: true,
src: ["./src"],
exclude: ["model/**", "**/__tests__/**"],
reporter: ["text", "lcov", "html"],
},
},
+48 -1
View File
@@ -1320,6 +1320,26 @@
"@ethersproject/properties" "^5.7.0"
"@ethersproject/strings" "^5.7.0"
"@floating-ui/core@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.1.tgz#074182a1d277f94569c50a6b456e62585d463c8e"
integrity sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg==
"@floating-ui/dom@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.1.tgz#8f93906e1a3b9f606ce78afb058e874344dcbe07"
integrity sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==
dependencies:
"@floating-ui/core" "^1.2.1"
"@floating-ui/vue@^0.2.1":
version "0.2.1"
resolved "https://registry.yarnpkg.com/@floating-ui/vue/-/vue-0.2.1.tgz#a52b66e020897ad0535d0d0d3b09932446fc6231"
integrity sha512-HE+EIeakID7wI6vUwF0yMpaW48bNaPj8QtnQaRMkaQFhQReVBA4bY6fmJ3J7X+dqVgDbMhyfCG0fBJfdQMdWxQ==
dependencies:
"@floating-ui/dom" "^1.2.1"
vue-demi "^0.13.11"
"@headlessui/vue@^1.7.3":
version "1.7.3"
resolved "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.3.tgz"
@@ -1498,6 +1518,11 @@
dependencies:
vue "^2.5.16"
"@types/web-bluetooth@^0.0.16":
version "0.0.16"
resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8"
integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==
"@typescript-eslint/eslint-plugin@^5.0.0":
version "5.40.1"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz"
@@ -1873,6 +1898,28 @@
resolved "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.1.3.tgz"
integrity sha512-kQVsh8yyWPvHpb8gIc9l/HIDiiVUy1amynLNpCy8p+FoCiZXCo6fQos5/097MmnNZc9AtseDsCrfkhqCrJ8Olg==
"@vueuse/core@^9.12.0":
version "9.12.0"
resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.12.0.tgz#e5b20f901e081c7ae5fe0e5f3af217929034eefe"
integrity sha512-h/Di8Bvf6xRcvS/PvUVheiMYYz3U0tH3X25YxONSaAUBa841ayMwxkuzx/DGUMCW/wHWzD8tRy2zYmOC36r4sg==
dependencies:
"@types/web-bluetooth" "^0.0.16"
"@vueuse/metadata" "9.12.0"
"@vueuse/shared" "9.12.0"
vue-demi "*"
"@vueuse/metadata@9.12.0":
version "9.12.0"
resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.12.0.tgz#19a0fefcba6a66a2382af10a7a67ebad6eec1f27"
integrity sha512-9oJ9MM9lFLlmvxXUqsR1wLt1uF7EVbP5iYaHJYqk+G2PbMjY6EXvZeTjbdO89HgoF5cI6z49o2zT/jD9SVoNpQ==
"@vueuse/shared@9.12.0":
version "9.12.0"
resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.12.0.tgz#e6597da80084cba8fc3d6545f4c2fa9817b80428"
integrity sha512-TWuJLACQ0BVithVTRbex4Wf1a1VaRuSpVeyEd4vMUWl54PzlE0ciFUshKCXnlLuD0lxIaLK4Ypj3NXYzZh4+SQ==
dependencies:
vue-demi "*"
abab@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
@@ -5196,7 +5243,7 @@ vitest@^0.28.1:
vite-node "0.28.1"
why-is-node-running "^2.2.2"
vue-demi@*:
vue-demi@*, vue-demi@^0.13.11:
version "0.13.11"
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz"
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==