Compare commits

...

17 Commits

Author SHA1 Message Date
hueso
1264d91f5c Görli -> Sepolia
Some checks are pending
Deploy FrontEnd / deploy-staging (push) Waiting to run
Deploy FrontEnd / deploy-production (push) Waiting to run
CI script / lint (push) Waiting to run
CI script / build (push) Waiting to run
CI script / SonarCloud (push) Waiting to run
2024-07-18 18:57:30 -03:00
hueso
0108bbb0e9 add Rootstock testnet 2024-07-18 18:55:04 -03:00
hueso
511c7f980f fix chain detection 2024-07-18 16:36:05 -03:00
hueso
d794064a91 add favicon/title 2023-10-27 19:09:22 -03:00
Bruno Esteves
b9dd4a7621
Merge pull request #60 from liftlearning/create_alerts
Create alerts
2023-02-28 21:35:58 -03:00
enzoggqs
e9b4ee7b98 Fix withdraw button behavior 2023-02-28 21:12:46 -03:00
enzoggqs
e4e6c32d64 Add alert to withdraw flow 2023-02-28 21:07:56 -03:00
enzoggqs
e48f73354d Fix mobile view 2023-02-28 01:59:22 -03:00
RcleydsonR
481803e643 add continue button on manage bids that allow user to continue lock and release it, also fix some responsive points
Co-authored-by: enzoggqs <eggqsaraiva@gmail.com>
2023-02-27 20:41:58 -03:00
RcleydsonR
1fe834d12d Merge branch 'develop' into create_alerts 2023-02-27 19:36:38 -03:00
Rafael Ramos
9c80f89cae
Merge pull request #59 from liftlearning/active-lock-value
Active lock value
2023-02-27 18:00:57 -03:00
RcleydsonR
309c57b808 fix waiting component to be rendered by adding the function to render listing component on unMounted lifecycle 2023-02-27 17:23:46 -03:00
RcleydsonR
34c5ce3b87 Add tooltip to inform what a locked value is 2023-02-27 09:43:55 -03:00
RcleydsonR
b86a70df19 improve layout from buy confirmed component 2023-02-24 01:39:58 -03:00
RcleydsonR
8f45016532 add text on listing component to show active lock amount 2023-02-24 00:57:34 -03:00
RcleydsonR
d686c0b9bc add method to get active lock amount from a seller wallet 2023-02-24 00:50:32 -03:00
RcleydsonR
5cb9103ef5 fix fill color from spinner component to always white instead of passing as parameter 2023-02-24 00:49:06 -03:00
25 changed files with 640 additions and 202 deletions

View File

@ -2,9 +2,11 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" href="/p2pix.svg" type="image/svg+xml">
<link rel="shortcut icon" href="/p2pix.svg" type="image/svg+xml">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<title>P2Pix</title>
</head>
<body>
<div id="app"></div>

View File

@ -14,6 +14,7 @@
"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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

72
public/p2pix.svg Normal file
View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="81.253998"
height="81.253998"
viewBox="0 0 81.253998 81.253998"
fill="none"
version="1.1"
id="svg8"
sodipodi:docname="p2pix.svg"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.0617761"
inkscape:cx="129.5"
inkscape:cy="23.805873"
inkscape:window-width="1920"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<path
d="m 21.877862,66.609161 c 0,4.29324 -2.73444,7.334258 -6.49095,7.334258 -2.197613,0 -3.884411,-1.07331 -4.906471,-2.657693 v 8.739769 H 7.5927121 v -20.44393 h 2.8877289 v 2.402197 c 1.02206,-1.609964 2.708858,-2.708857 4.932061,-2.708857 3.67975,0 6.46536,3.041058 6.46536,7.334256 z m -2.91311,0 c 0,-2.683233 -1.73796,-4.574316 -4.19099,-4.574316 -2.453445,0 -4.318904,1.891083 -4.318904,4.574316 0,2.708816 1.865459,4.574317 4.318904,4.574317 2.42745,0 4.19099,-1.865501 4.19099,-4.574317 z"
fill="#14b8a6"
id="path1"
style="stroke-width:0.419393" />
<path
d="m 37.722102,70.876818 v 2.759941 h -13.56988 v -2.069955 l 5.18789,-4.548777 c 4.01191,-3.501007 5.03397,-4.395445 5.03397,-5.979827 0,-1.558841 -1.20114,-2.836605 -3.39876,-2.836605 -2.17203,0 -3.37317,1.252181 -3.7565,3.296595 h -2.9131 c 0.40891,-3.731044 3.09218,-6.056523 6.79752,-6.056523 3.80767,0 6.18437,2.453268 6.18437,5.468744 0,2.708816 -1.89105,4.31878 -5.54564,7.513127 l -2.81077,2.427739 -0.0512,0.02554 z"
fill="#f59e0b"
id="path2"
style="stroke-width:0.419393" />
<path
d="m 54.869392,66.609161 c 0,4.29324 -2.73444,7.334258 -6.49094,7.334258 -2.19804,0 -3.88442,-1.07331 -4.9069,-2.657693 v 8.739769 h -2.88752 v -20.44393 h 2.88752 v 2.402197 c 1.02248,-1.609964 2.70886,-2.708857 4.93248,-2.708857 3.67975,0 6.46536,3.041058 6.46536,7.334256 z m -2.91352,0 c 0,-2.683233 -1.73755,-4.574316 -4.19099,-4.574316 -2.45303,0 -4.31849,1.891083 -4.31849,4.574316 0,2.708816 1.86546,4.574317 4.31849,4.574317 2.42786,0 4.19099,-1.865501 4.19099,-4.574317 z"
fill="#14b8a6"
id="path3"
style="stroke-width:0.419393" />
<path
d="m 61.104502,55.007239 c 0,1.047748 -0.79223,1.814394 -1.89104,1.814394 -1.04764,0 -1.86546,-0.766646 -1.86546,-1.814394 0,-1.022194 0.81782,-1.763286 1.86546,-1.763286 1.09881,0 1.89104,0.741092 1.89104,1.763286 z m -3.32201,4.574326 h 2.88752 v 14.055194 h -2.88752 z"
fill="#14b8a6"
id="path4"
style="stroke-width:0.419393" />
<path
d="m 73.089912,73.636759 -3.39876,-5.034308 -3.27126,5.034308 h -3.47551 l 5.03439,-7.23201 -4.75298,-6.823143 h 3.44992 l 3.11735,4.702064 3.01585,-4.702064 h 3.47509 l -4.75297,6.874225 5.0088,7.180928 z"
fill="#14b8a6"
id="path5"
style="stroke-width:0.419393" />
<path
d="m 8.11425,0 c 3.66615,0 6.76355,2.43731 7.76895,5.77851 3.8591,0.2742 7.5557,1.9498 10.2875,4.702 l 14.7458,14.7356 c 0.0508,0.0508 0.1117,0.1016 0.1625,0.1625 l 16.1676,16.1574 c 1.9702,1.9803 4.6918,3.1076 7.4744,3.1076 0.0102,0 0.0203,0 0.0305,0 h 0.8937 c 1.2187,-2.9349 4.113,-4.9965 7.4948,-4.9965 4.4785,0 8.1142,3.6357 8.1142,8.1142 0,4.4786 -3.6357,8.1143 -8.1142,8.1143 -3.6154,0 -6.6621,-2.3561 -7.7182,-5.6262 h -0.6601 c -0.0102,0 -0.0305,0 -0.0407,0 -4.2551,0 -8.4189,-1.7264 -11.4147,-4.7426 L 38.4995,30.70011 c -0.0609,-0.0508 -0.132,-0.1016 -0.1929,-0.1625 L 22.1898,14.42081 c -1.7671,-1.7772 -4.1536,-2.8638 -6.6519,-3.067 -1.2491,2.8639 -4.1028,4.8645 -7.43381,4.8645 C 3.63567,16.21831 0,12.59281 0,8.11421 0,3.63571 3.63567,0 8.11425,0 Z"
fill="#f59e0b"
id="path6" />
<path
d="m 8.11425,39.64711 c 3.38175,0 6.26595,2.0616 7.49475,4.9965 h 0.8937 c 0.0102,0 0.0203,0 0.0305,0 2.7927,0 5.5144,-1.1272 7.4744,-3.1075 l 9.6477,-9.6478 3.9505,3.9505 -9.6578,9.6579 c -3.0061,3.0162 -7.1597,4.7426 -11.4148,4.7426 -0.0102,0 -0.0305,0 -0.0407,0 h -0.6601 c -1.046,3.2599 -4.1028,5.6262 -7.71815,5.6262 C 3.63567,55.86551 0,52.22981 0,47.75121 c 0,-4.4786 3.63567,-8.1041 8.11425,-8.1041 z"
fill="#f59e0b"
id="path7" />
<path
d="m 73.1298,16.21831 c -3.3818,0 -6.266,-2.0615 -7.4948,-4.9965 h -0.8937 c -0.0101,0 -0.0203,0 -0.0304,0 -2.7928,0 -5.5145,1.1273 -7.4745,3.1076 l -9.6477,9.6478 -3.9505,-3.9505 9.6579,-9.6579 c 3.006,-3.0162 7.1596,-4.7426 11.4148,-4.7426 0.0101,0 0.0304,0 0.0406,0 h 0.6601 c 1.0562,-3.2701 4.113,-5.6262 7.7182,-5.6262 4.4786,0 8.1142,3.6357 8.1142,8.1143 0,4.4785 -3.6356,8.104 -8.1142,8.104 z"
fill="#f59e0b"
id="path8" />
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -1,5 +1,6 @@
<script setup lang="ts">
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>

5
src/assets/info.svg Normal file
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

24
src/assets/rootstock.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -5,8 +5,9 @@ const getTokenAddress = (network?: NetworkEnum): string => {
const etherStore = useEtherStore();
const possibleTokenAddresses: { [key: string]: string } = {
Ethereum: "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00",
Ethereum: "0x3eBE67A2C7bdB2081CBd34ba3281E90377462289",
Polygon: "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29",
Rootstock: "0xfE841c74250e57640390f46d914C88d22C51e82e",
};
return possibleTokenAddresses[network ? network : etherStore.networkName];
@ -16,8 +17,9 @@ const getP2PixAddress = (network?: NetworkEnum): string => {
const etherStore = useEtherStore();
const possibleP2PixAddresses: { [key: string]: string } = {
Ethereum: "0x2414817FF64A114d91eCFA16a834d3fCf69103d4",
Ethereum: "0xb7cD135F5eFD9760981e02E2a898790b688939fe",
Polygon: "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00",
Rootstock: "0x98ba35eb14b38D6Aa709338283af3e922476dE34",
};
return possibleP2PixAddresses[network ? network : etherStore.networkName];
@ -27,28 +29,29 @@ const getProviderUrl = (): string => {
const etherStore = useEtherStore();
const possibleProvidersUrls: { [key: string]: string } = {
Ethereum: import.meta.env.VITE_GOERLI_API_URL,
Ethereum: import.meta.env.VITE_SEPOLIA_API_URL,
Polygon: import.meta.env.VITE_MUMBAI_API_URL,
Rootstock: import.meta.env.VITE_RSK_API_URL,
};
return possibleProvidersUrls[etherStore.networkName];
};
const possibleChains: { [key: string]: NetworkEnum } = {
"0x5": NetworkEnum.ethereum,
"5": NetworkEnum.ethereum,
"0x13881": NetworkEnum.polygon,
"11155111": NetworkEnum.ethereum,
"80001": NetworkEnum.polygon,
"31": NetworkEnum.rootstock,
};
const network2Chain: { [key: string]: string } = {
Ethereum: "0x5",
Ethereum: "0xAA36A7",
Polygon: "0x13881",
Localhost: "0x7a69",
Rootstock: "0x1f",
};
const isPossibleNetwork = (networkChain: string): boolean => {
if (Object.keys(possibleChains).includes(networkChain)) {
if (Object.keys(possibleChains).includes(networkChain.toString())) {
return true;
}
return false;

View File

@ -7,23 +7,29 @@ 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();
const goerliProvider = new ethers.providers.JsonRpcProvider(
import.meta.env.VITE_GOERLI_API_URL,
5
); // goerli provider
const sepoliaProvider = new ethers.providers.JsonRpcProvider(
import.meta.env.VITE_SEPOLIA_API_URL,
11155111
); // sepolia provider
const mumbaiProvider = new ethers.providers.JsonRpcProvider(
import.meta.env.VITE_MUMBAI_API_URL,
80001
); // mumbai provider
const rootstockProvider = new ethers.providers.JsonRpcProvider(
import.meta.env.VITE_RSK_API_URL,
31
); // rootstock provider
const p2pContractGoerli = new ethers.Contract(
const p2pContractSepolia = new ethers.Contract(
getP2PixAddress(NetworkEnum.ethereum),
p2pix.abi,
goerliProvider
sepoliaProvider
);
const p2pContractMumbai = new ethers.Contract(
getP2PixAddress(NetworkEnum.polygon),
@ -31,19 +37,32 @@ const getNetworksLiquidity = async (): Promise<void> => {
mumbaiProvider
);
etherStore.setLoadingNetworkLiquidity(true);
const depositListGoerli = await getValidDeposits(
getTokenAddress(NetworkEnum.ethereum),
p2pContractGoerli
const p2pContractRootstock = new ethers.Contract(
getP2PixAddress(NetworkEnum.rootstock),
p2pix.abi,
rootstockProvider
);
etherStore.setLoadingNetworkLiquidity(true);
const depositListSepolia = await getValidDeposits(
getTokenAddress(NetworkEnum.ethereum),
p2pContractSepolia
);
const depositListMumbai = await getValidDeposits(
getTokenAddress(NetworkEnum.polygon),
p2pContractMumbai
);
etherStore.setDepositsValidListGoerli(depositListGoerli);
const depositListRootstock = await getValidDeposits(
getTokenAddress(NetworkEnum.rsktestnet),
p2pContractRootstock
);
etherStore.setDepositsValidListSepolia(depositListSepolia);
etherStore.setDepositsValidListMumbai(depositListMumbai);
etherStore.setDepositsValidListRootstock(depositListRootstock);
etherStore.setLoadingNetworkLiquidity(false);
};
@ -100,4 +119,25 @@ const getValidDeposits = async (
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 };

View File

@ -1,7 +1,7 @@
import { useEtherStore } from "@/store/ether";
import { getContract, getProvider } from "./provider";
import { getTokenAddress, possibleChains } from "./addresses";
import { getTokenAddress, possibleChains, isPossibleNetwork } from "./addresses";
import mockToken from "@/utils/smart_contract_files/MockToken.json";
@ -21,6 +21,10 @@ const updateWalletStatus = async (): Promise<void> => {
const signer = provider.getSigner();
const { chainId } = await provider.getNetwork();
if(!isPossibleNetwork(chainId)){
window.alert("Invalid chain!:"+chainId);
return false;
}
etherStore.setNetworkName(possibleChains[chainId]);
const mockTokenContract = new ethers.Contract(
@ -80,6 +84,9 @@ const filterLockStatus = async (
transactionHash: transaction.transactionHash
? transaction.transactionHash
: "",
transactionID: transaction.args?.lockID
? String(transaction.args?.lockID)
: "",
};
return tx;
@ -155,6 +162,22 @@ const listLockTransactionByWalletAddress = async (
});
};
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> => {
@ -187,10 +210,37 @@ const checkUnreleasedLock = async (
}
};
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,
};

View File

@ -1,13 +1,81 @@
<script setup lang="ts">
import { withdrawDeposit } from "@/blockchain/buyerMethods";
import {
getActiveLockAmount,
listAllTransactionByWalletAddress,
listValidDepositTransactionsByWalletAddress,
} from "@/blockchain/wallet";
import CustomButton from "@/components/CustomButton/CustomButton.vue";
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<{
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>
@ -33,10 +101,7 @@ const emit = defineEmits(["makeAnotherTransaction"]);
cadastrar o BRZ em sua carteira.
</p>
</div>
<CustomButton
:text="'Cadastrar token na carteira'"
@buttonClicked="() => {}"
/>
<CustomButton :text="'Cadastrar token'" @buttonClicked="() => {}" />
</div>
<button
type="button"
@ -46,6 +111,19 @@ const emit = defineEmits(["makeAnotherTransaction"]);
Fazer nova transação
</button>
</div>
<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-xs md:max-w-lg">
<ListingComponent
:valid-deposits="depositList"
:wallet-transactions="lastWalletTransactions"
:active-lock-amount="activeLockAmount"
@deposit-withdrawn="callWithdraw"
></ListingComponent>
</div>
</div>
</template>
@ -70,7 +148,7 @@ p {
}
.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 {

View File

@ -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");

View File

@ -6,15 +6,15 @@ const props = defineProps<{
const alertText = ref<string>("");
const alertPaddingLeft = ref<string>("18rem");
const alertPaddingTop = ref<string>("0rem");
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%";
alertPaddingTop.value = "8rem";
}
switch (props.type) {
@ -29,13 +29,16 @@ switch (props.type) {
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 inset-0 absolute backdrop-blur-sm sm:backdrop-blur-none"
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 flex justify-between">
<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 }}
@ -51,6 +54,44 @@ switch (props.type) {
@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>
@ -59,7 +100,6 @@ switch (props.type) {
justify-content: center;
width: 100%;
padding-top: 7rem;
height: 3rem;
z-index: 10;
}
@ -72,6 +112,13 @@ switch (props.type) {
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;
}

View File

@ -5,10 +5,11 @@ import type { ValidDeposit } from "@/model/ValidDeposit";
import type { WalletTransaction } from "@/model/WalletTransaction";
import { useEtherStore } from "@/store/ether";
import { storeToRefs } from "pinia";
import { ref, watch } from "vue";
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();
@ -16,6 +17,7 @@ const etherStore = useEtherStore();
const props = defineProps<{
validDeposits: ValidDeposit[];
walletTransactions: WalletTransaction[];
activeLockAmount: number;
}>();
const emit = defineEmits(["depositWithdrawn"]);
@ -30,6 +32,12 @@ 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 => {
@ -51,19 +59,22 @@ const handleInputEvent = (event: any): void => {
enableConfirmButton.value = true;
};
const callWithdraw = async () => {
if (withdrawAmount.value) {
const withdraw = await withdrawDeposit(withdrawAmount.value);
if (withdraw) {
console.log(withdraw);
alert("Saque realizado!");
emit("depositWithdrawn");
}
}
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) {
if (!withdrawAmount.value || !enableConfirmButton.value) {
withdrawButtonOpacity.value = 0.7;
withdrawButtonCursor.value = "not-allowed";
} else {
@ -96,7 +107,7 @@ const showInitialItems = (): void => {
const openEtherscanUrl = (transactionHash: string): void => {
const networkUrl =
etherStore.networkName == NetworkEnum.ethereum
? "goerli.etherscan.io"
? "sepolia.etherscan.io"
: "mumbai.polygonscan.com";
const url = `https://${networkUrl}/tx/${transactionHash}`;
window.open(url, "_blank");
@ -122,6 +133,18 @@ const getEventName = (event: string | undefined): string => {
return possibleEventName[event];
};
onMounted(() => {
useFloating(reference, floating, {
placement: "right",
middleware: [
offset(10),
flip(),
shift(),
arrow({ element: floatingArrow }),
],
});
});
// watch props changes
watch(props, async (): Promise<void> => {
const itemsToShowQty = itemsToShow.value.length;
@ -139,11 +162,11 @@ showInitialItems();
<template>
<div class="blur-container" v-if="loadingWalletTransactions">
<SpinnerComponent width="8" height="8" fillColor="white"></SpinnerComponent>
<SpinnerComponent width="8" height="8"></SpinnerComponent>
</div>
<div class="blur-container" v-if="!loadingWalletTransactions">
<div
class="w-full bg-white p-6 rounded-lg"
class="w-full bg-white p-4 sm:p-6 rounded-lg"
v-if="props.validDeposits.length > 0"
>
<div class="flex justify-between items-center">
@ -154,25 +177,55 @@ showInitialItems();
<p class="text-xl leading-7 font-semibold text-gray-900">
{{ getRemaining() }} BRZ
</p>
<p class="text-xs leading-4 font-medium text-gray-600"></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 estará disponível para saque caso a
transação expire.
</div>
</div>
</div>
</div>
</div>
<div class="pt-5">
<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" />
<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=""
id=""
@input="debounce(handleInputEvent, 500)($event)"
placeholder="0"
class="text-2xl text-gray-900 w-full outline-none"
@ -202,38 +255,42 @@ showInitialItems();
</h1>
<div
v-if="enableConfirmButton"
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" />
<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="w-full bg-white p-6 rounded-lg"
class="w-full bg-white p-4 sm:p-6 rounded-lg"
v-for="item in itemsToShow"
:key="item.blockNumber"
>
<div class="item-container">
<div>
<p class="text-sm leading-5 font-medium text-gray-600">
<div class="flex flex-col self-start">
<span class="text-xs sm:text-sm leading-5 font-medium text-gray-600">
{{ getEventName(item.event) }}
</p>
<p class="text-xl leading-7 font-semibold text-gray-900">
</span>
<span
class="text-xl sm:text-xl leading-7 font-semibold text-gray-900"
>
{{ item.amount }}
BRZ
</p>
<p class="text-xs leading-4 font-medium text-gray-600"></p>
</span>
</div>
<div>
<div
class="bg-amber-300 status-text"
v-if="getEventName(item.event) == 'Reserva' && item.lockStatus == 1"
>
Ativo
Em Aberto
</div>
<div
class="bg-[#94A3B8] status-text"
@ -251,11 +308,30 @@ showInitialItems();
Finalizado
</div>
<div
class="flex gap-2 cursor-pointer items-center justify-self-center"
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" />
<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>
@ -280,7 +356,7 @@ showInitialItems();
</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 nenhuma transação anterior
</span>
</div>
@ -304,17 +380,14 @@ p {
}
.status-text {
@apply text-base font-medium text-gray-900 rounded-lg text-center mb-2 p-1;
@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-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 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 {
@ -322,7 +395,15 @@ 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 {
@ -338,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>

View File

@ -17,6 +17,7 @@ describe("ListingComponent.vue", () => {
props: {
validDeposits: [],
walletTransactions: [],
activeLockAmount: 0,
},
});
@ -28,6 +29,7 @@ describe("ListingComponent.vue", () => {
props: {
validDeposits: [],
walletTransactions: MockWalletTransactions,
activeLockAmount: 0,
},
});
@ -41,6 +43,7 @@ describe("ListingComponent.vue", () => {
props: {
validDeposits: MockValidDeposits,
walletTransactions: MockWalletTransactions,
activeLockAmount: 0,
},
});
const btn = wrapper.find("button");
@ -60,6 +63,7 @@ describe("ListingComponent.vue", () => {
props: {
validDeposits: MockValidDeposits,
walletTransactions: MockWalletTransactions,
activeLockAmount: 0,
},
});
wrapper.vm.$emit("depositWithdrawn");
@ -68,4 +72,16 @@ describe("ListingComponent.vue", () => {
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");
});
});

View File

@ -17,7 +17,7 @@ const etherStore = useEtherStore();
const {
walletAddress,
networkName,
depositsValidListGoerli,
depositsValidListSepolia,
depositsValidListMumbai,
loadingNetworkLiquidity,
} = storeToRefs(etherStore);
@ -28,8 +28,9 @@ const enableConfirmButton = ref<boolean>(false);
const enableWalletButton = ref<boolean>(false);
const hasLiquidity = ref<boolean>(true);
const validDecimals = ref<boolean>(true);
const selectedGoerliDeposit = ref<ValidDeposit>();
const selectedSepoliaDeposit = ref<ValidDeposit>();
const selectedMumbaiDeposit = ref<ValidDeposit>();
const selectedRootstockDeposit = ref<ValidDeposit>();
// Emits
const emit = defineEmits(["tokenBuy"]);
@ -44,7 +45,7 @@ const connectAccount = async (): Promise<void> => {
const emitConfirmButton = (): void => {
const selectedDeposit =
networkName.value == NetworkEnum.ethereum
? selectedGoerliDeposit.value
? selectedSepoliaDeposit.value
: selectedMumbaiDeposit.value;
emit("tokenBuy", selectedDeposit, tokenValue.value);
};
@ -68,18 +69,19 @@ const handleInputEvent = (event: any): void => {
// Verify if there is a valid deposit to buy
const verifyLiquidity = (): void => {
enableConfirmButton.value = false;
selectedGoerliDeposit.value = undefined;
selectedSepoliaDeposit.value = undefined;
selectedMumbaiDeposit.value = undefined;
selectedRootstockDeposit.value = undefined;
if (tokenValue.value <= 0) {
enableWalletButton.value = false;
return;
}
selectedGoerliDeposit.value = verifyNetworkLiquidity(
selectedSepoliaDeposit.value = verifyNetworkLiquidity(
tokenValue.value,
walletAddress.value,
depositsValidListGoerli.value
depositsValidListSepolia.value
);
selectedMumbaiDeposit.value = verifyNetworkLiquidity(
tokenValue.value,
@ -88,7 +90,7 @@ const verifyLiquidity = (): void => {
);
enableOrDisableConfirmButton();
if (selectedGoerliDeposit.value || selectedMumbaiDeposit.value) {
if (selectedSepoliaDeposit.value || selectedMumbaiDeposit.value) {
hasLiquidity.value = true;
enableWalletButton.value = true;
} else {
@ -98,7 +100,7 @@ const verifyLiquidity = (): void => {
};
const enableOrDisableConfirmButton = (): void => {
if (selectedGoerliDeposit.value && networkName.value == NetworkEnum.ethereum)
if (selectedSepoliaDeposit.value && networkName.value == NetworkEnum.ethereum)
enableConfirmButton.value = true;
else if (
selectedMumbaiDeposit.value &&
@ -183,7 +185,7 @@ watch(walletAddress, (): void => {
src="@/assets/ethereum.svg"
width="24"
height="24"
v-if="selectedGoerliDeposit"
v-if="selectedSepoliaDeposit"
/>
</div>
</div>
@ -194,11 +196,7 @@ watch(walletAddress, (): void => {
<span class="text-gray-900 font-normal text-sm mr-2"
>Carregando liquidez das redes.</span
>
<SpinnerComponent
width="4"
height="4"
fillColor="white"
></SpinnerComponent>
<SpinnerComponent width="4" height="4"></SpinnerComponent>
</div>
<div
class="flex justify-center"

View File

@ -3,7 +3,6 @@
const props = defineProps({
width: String,
height: String,
fillColor: String,
show: Boolean,
});
@ -11,7 +10,7 @@ const getCustomClass = () => {
return [
`w-${props.width}`,
`h-${props.height}`,
`fill-${props.fillColor}`,
`fill-white`,
"text-gray-200",
"animate-spin",
"dark:text-gray-600",

View File

@ -7,6 +7,7 @@ import { NetworkEnum } from "@/model/NetworkEnum";
import { connectProvider, requestNetworkChange } from "@/blockchain/provider";
import ethereumImage from "@/assets/ethereum.svg";
import polygonImage from "@/assets/polygon.svg";
import rootstockImage from "@/assets/rootstock.svg";
// Store reference
const etherStore = useEtherStore();
@ -58,6 +59,7 @@ const getNetworkImage = (networkName: NetworkEnum): string => {
let validImages = {
Ethereum: ethereumImage,
Polygon: polygonImage,
Rootstock: rootstockImage,
Localhost: ethereumImage,
};
@ -233,6 +235,8 @@ onClickOutside(infoMenuRef, () => {
<img
alt="Choosed network image"
:src="getNetworkImage(etherStore.networkName)"
height="24"
width="24"
/>
<span
class="default-text group-hover:text-gray-900 lg-view"
@ -269,6 +273,23 @@ onClickOutside(infoMenuRef, () => {
>
<div class="mt-2">
<div class="bg-white rounded-md z-10">
<div
class="menu-button gap-2 px-4 rounded-md cursor-pointer"
@click="networkChange(NetworkEnum.rootstock)"
>
<img
alt="Rootstock image"
width="20"
height="20"
src="@/assets/rootstock.svg"
/>
<span class="text-gray-900 py-4 text-end font-semibold text-sm">
Rootstock
</span>
</div>
<div class="w-full flex justify-center">
<hr class="w-4/5" />
</div>
<div
class="menu-button gap-2 px-4 rounded-md cursor-pointer"
@click="networkChange(NetworkEnum.ethereum)"
@ -468,6 +489,23 @@ onClickOutside(infoMenuRef, () => {
>
<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.rsktestnet)"
>
<img
alt="Rootstock image"
width="20"
height="20"
src="@/assets/rootstock.svg"
/>
<span class="text-gray-900 py-4 text-end font-bold text-sm">
Rootstock
</span>
</div>
<div class="w-full flex justify-center pb-12">
<hr class="w-4/5" />
</div>
<div
class="menu-button gap-2 sm:px-4 rounded-md cursor-pointer py-2"
@click="networkChange(NetworkEnum.ethereum)"

View File

@ -1,4 +1,5 @@
export enum NetworkEnum {
ethereum = "Ethereum",
polygon = "Polygon",
rootstock = "Rootstock",
}

View File

@ -7,4 +7,5 @@ export type WalletTransaction = {
event: string;
lockStatus: number;
transactionHash: string;
transactionID?: string;
};

View File

@ -11,6 +11,12 @@ const router = createRouter({
path: "/",
name: "home",
component: HomeView,
props: true,
},
{
path: "/:lockID",
name: "redirect buy",
component: HomeView,
},
{
path: "/seller",

View File

@ -9,8 +9,8 @@ export const useEtherStore = defineStore("ether", {
networkName: NetworkEnum.ethereum,
loadingLock: false,
sellerView: false,
// Depósitos válidos para compra GOERLI
depositsValidListGoerli: [] as ValidDeposit[],
// Depósitos válidos para compra SEPOLIA
depositsValidListSepolia: [] as ValidDeposit[],
// Depósitos válidos para compra MUMBAI
depositsValidListMumbai: [] as ValidDeposit[],
loadingWalletTransactions: false,
@ -32,12 +32,15 @@ export const useEtherStore = defineStore("ether", {
setSellerView(sellerView: boolean) {
this.sellerView = sellerView;
},
setDepositsValidListGoerli(depositsValidList: ValidDeposit[]) {
this.depositsValidListGoerli = depositsValidList;
setDepositsValidListSepolia(depositsValidList: ValidDeposit[]) {
this.depositsValidListSepolia = depositsValidList;
},
setDepositsValidListMumbai(depositsValidList: ValidDeposit[]) {
this.depositsValidListMumbai = depositsValidList;
},
setDepositsValidListRootstock(depositsValidList: ValidDeposit[]) {
this.depositsValidListRootstock = depositsValidList;
},
setLoadingWalletTransactions(isLoadingWalletTransactions: boolean) {
this.loadingWalletTransactions = isLoadingWalletTransactions;
},
@ -49,7 +52,7 @@ export const useEtherStore = defineStore("ether", {
getters: {
getValidDepositByWalletAddress: (state) => {
return (walletAddress: string) =>
state.depositsValidListGoerli
state.depositsValidListSepolia
.filter((deposit) => deposit.seller == walletAddress)
.sort((a, b) => {
return b.blockNumber - a.blockNumber;

View File

@ -2,26 +2,15 @@
import SearchComponent from "@/components/SearchComponent.vue";
import LoadingComponent from "@/components/LoadingComponent/LoadingComponent.vue";
import BuyConfirmedComponent from "@/components/BuyConfirmedComponent/BuyConfirmedComponent.vue";
import ListingComponent from "@/components/ListingComponent/ListingComponent.vue";
import { ref, onMounted, watch } from "vue";
import { useEtherStore } from "@/store/ether";
import QrCodeComponent from "@/components/QrCodeComponent.vue";
import CustomModal from "@/components/CustomModal/CustomModal.vue";
import { storeToRefs } from "pinia";
import {
addLock,
releaseLock,
withdrawDeposit,
} from "@/blockchain/buyerMethods";
import {
updateWalletStatus,
listAllTransactionByWalletAddress,
checkUnreleasedLock,
listValidDepositTransactionsByWalletAddress,
} from "@/blockchain/wallet";
import { addLock, releaseLock } from "@/blockchain/buyerMethods";
import { updateWalletStatus, checkUnreleasedLock } from "@/blockchain/wallet";
import { getNetworksLiquidity } from "@/blockchain/events";
import type { ValidDeposit } from "@/model/ValidDeposit";
import type { WalletTransaction } from "@/model/WalletTransaction";
import { getUnreleasedLockById } from "@/blockchain/events";
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
enum Step {
@ -41,9 +30,8 @@ const tokenAmount = ref<number>();
const lockID = ref<string>("");
const loadingRelease = ref<boolean>(false);
const showModal = ref<boolean>(false);
const lastWalletTransactions = ref<WalletTransaction[]>([]);
const depositList = ref<ValidDeposit[]>([]);
const showBuyAlert = ref<boolean>(false);
const paramLockID = window.history.state?.lockID;
const confirmBuyClick = async (
selectedDeposit: ValidDeposit,
@ -83,50 +71,13 @@ const releaseTransaction = async (e2eId: string) => {
e2eId,
lockID.value
);
release.wait();
await getWalletTransactions();
await release.wait();
await updateWalletStatus();
loadingRelease.value = false;
}
};
const getWalletTransactions = async () => {
etherStore.setLoadingWalletTransactions(true);
if (walletAddress.value) {
const walletDeposits = await listValidDepositTransactionsByWalletAddress(
walletAddress.value
);
const allUserTransactions = await listAllTransactionByWalletAddress(
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);
}
};
const checkForUnreleasedLocks = async (): Promise<void> => {
const walletLocks = await checkUnreleasedLock(walletAddress.value);
if (walletLocks) {
@ -140,20 +91,30 @@ const checkForUnreleasedLocks = async (): Promise<void> => {
}
};
if (walletAddress.value) {
await checkForUnreleasedLocks();
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();
});
}
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>
@ -191,18 +152,9 @@ onMounted(async () => {
<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
class="text-3xl text-white leading-9 font-bold justify-center flex mt-4"
>
Gerenciar transações
</div>
<ListingComponent
:valid-deposits="depositList"
:wallet-transactions="lastWalletTransactions"
@deposit-withdrawn="callWithdraw"
></ListingComponent>
</div>
<LoadingComponent
v-if="loadingRelease"

View File

@ -3,27 +3,28 @@ import { useEtherStore } from "@/store/ether";
import { storeToRefs } from "pinia";
import ListingComponent from "@/components/ListingComponent/ListingComponent.vue";
import LoadingComponent from "@/components/LoadingComponent/LoadingComponent.vue";
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
import { ref, watch, onMounted } from "vue";
import {
listValidDepositTransactionsByWalletAddress,
listAllTransactionByWalletAddress,
checkUnreleasedLock,
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";
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
const etherStore = useEtherStore();
const { walletAddress, networkName } = storeToRefs(etherStore);
const loadingWithdraw = ref<boolean>(false);
const showAlert = ref<boolean>(false);
const depositList = ref<ValidDeposit[]>([]);
const transactionsList = ref<WalletTransaction[]>([]);
const showAlert = ref<boolean>(false);
const activeLockAmount = ref<number>(0);
const callWithdraw = async (amount: string) => {
if (amount) {
@ -38,6 +39,7 @@ const callWithdraw = async (amount: string) => {
if (withdraw) {
console.log("Saque realizado!");
await getWalletTransactions();
showAlert.value = true;
} else {
console.log("Não foi possível realizar o saque!");
}
@ -56,6 +58,8 @@ const getWalletTransactions = async () => {
walletAddress.value
);
activeLockAmount.value = await getActiveLockAmount(walletAddress.value);
if (walletDeposits) {
depositList.value = walletDeposits;
}
@ -66,25 +70,11 @@ const getWalletTransactions = async () => {
etherStore.setLoadingWalletTransactions(false);
};
const checkForUnreleasedLocks = async (): Promise<void> => {
const walletLocks = await checkUnreleasedLock(walletAddress.value);
if (walletLocks) {
showAlert.value = true;
} else {
showAlert.value = false;
}
};
const goToLock = () => {
router.push({ name: "home" });
};
onMounted(async () => {
if (!walletAddress.value) {
router.push({ name: "home" });
}
await getWalletTransactions();
await checkForUnreleasedLocks();
});
watch(walletAddress, async () => {
@ -99,9 +89,8 @@ watch(networkName, async () => {
<template>
<CustomAlert
v-if="showAlert"
:type="'redirect'"
:type="'withdraw'"
@close-alert="showAlert = false"
@go-to-lock="goToLock()"
/>
<div class="page">
<div class="header" v-if="!loadingWithdraw && !walletAddress">
@ -115,6 +104,7 @@ watch(networkName, async () => {
v-if="!loadingWithdraw && walletAddress"
:valid-deposits="depositList"
:wallet-transactions="transactionsList"
:active-lock-amount="activeLockAmount"
@deposit-withdrawn="callWithdraw"
></ListingComponent>
<LoadingComponent

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"
@ -5223,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==