commit
						3177aaece9
					
				| @ -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} | ||||
| @ -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" | ||||
|       "0xefa5cE4351cda51192509cf8De7d8881ADAE95DD" | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
| @ -63,13 +63,13 @@ describe("addresses.ts functions", () => { | ||||
|     const etherStore = useEtherStore(); | ||||
|     etherStore.setNetworkName(NetworkEnum.polygon); | ||||
|     expect(getP2PixAddress()).toBe( | ||||
|       "0x5f3EFA9A90532914545CEf527C530658af87e196" | ||||
|       "0xA9258eBb157E4cf5e756b77FDD0DF09C2F73240b" | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
|   it("getP2PixAddress Default", () => { | ||||
|     expect(getP2PixAddress()).toBe( | ||||
|       "0x5f3EFA9A90532914545CEf527C530658af87e196" | ||||
|       "0xefa5cE4351cda51192509cf8De7d8881ADAE95DD" | ||||
|     ); | ||||
|   }); | ||||
| 
 | ||||
| @ -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); | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @ -5,8 +5,8 @@ const getTokenAddress = (): string => { | ||||
|   const etherStore = useEtherStore(); | ||||
| 
 | ||||
|   const possibleTokenAddresses: { [key: string]: string } = { | ||||
|     Ethereum: "0x294003F602c321627152c6b7DED3EAb5bEa853Ee", | ||||
|     Polygon: "0x294003F602c321627152c6b7DED3EAb5bEa853Ee", | ||||
|     Ethereum: "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00", | ||||
|     Polygon: "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29", | ||||
|   }; | ||||
| 
 | ||||
|   return possibleTokenAddresses[etherStore.networkName]; | ||||
| @ -16,8 +16,8 @@ const getP2PixAddress = (): string => { | ||||
|   const etherStore = useEtherStore(); | ||||
| 
 | ||||
|   const possibleP2PixAddresses: { [key: string]: string } = { | ||||
|     Ethereum: "0x5f3EFA9A90532914545CEf527C530658af87e196", | ||||
|     Polygon: "0x5f3EFA9A90532914545CEf527C530658af87e196", | ||||
|     Ethereum: "0xefa5cE4351cda51192509cf8De7d8881ADAE95DD", | ||||
|     Polygon: "0xA9258eBb157E4cf5e756b77FDD0DF09C2F73240b", | ||||
|   }; | ||||
| 
 | ||||
|   return possibleP2PixAddresses[etherStore.networkName]; | ||||
|  | ||||
| @ -9,7 +9,8 @@ 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,13 @@ const cancelDeposit = async (depositId: BigNumber): Promise<any> => { | ||||
|   return cancel; | ||||
| }; | ||||
| 
 | ||||
| const withdrawDeposit = async (depositId: BigNumber): Promise<any> => { | ||||
| const withdrawDeposit = async ( | ||||
|   depositId: BigNumber, | ||||
|   amount: string | ||||
| ): Promise<any> => { | ||||
|   const contract = getContract(); | ||||
| 
 | ||||
|   const withdraw = await contract.withdraw(depositId, []); | ||||
|   const withdraw = await contract.withdraw(depositId, amount, []); | ||||
|   await withdraw.wait(); | ||||
| 
 | ||||
|   return withdraw; | ||||
|  | ||||
| @ -20,19 +20,25 @@ const getNetworksLiquidity = async (): Promise<void> => { | ||||
|   ); // mumbai provider
 | ||||
| 
 | ||||
|   const p2pContractGoerli = new ethers.Contract( | ||||
|     "0x5f3EFA9A90532914545CEf527C530658af87e196", | ||||
|     "0xefa5cE4351cda51192509cf8De7d8881ADAE95DD", | ||||
|     p2pix.abi, | ||||
|     goerliProvider | ||||
|   ); | ||||
|   const p2pContractMumbai = new ethers.Contract( | ||||
|     "0x5f3EFA9A90532914545CEf527C530658af87e196", | ||||
|     "0xA9258eBb157E4cf5e756b77FDD0DF09C2F73240b", | ||||
|     p2pix.abi, | ||||
|     mumbaiProvider | ||||
|   ); | ||||
| 
 | ||||
|   const depositListGoerli = await getValidDeposits(p2pContractGoerli); | ||||
|   const depositListGoerli = await getValidDeposits( | ||||
|     "0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00", | ||||
|     p2pContractGoerli | ||||
|   ); | ||||
| 
 | ||||
|   const depositListMumbai = await getValidDeposits(p2pContractMumbai); | ||||
|   const depositListMumbai = await getValidDeposits( | ||||
|     "0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29", | ||||
|     p2pContractMumbai | ||||
|   ); | ||||
| 
 | ||||
|   etherStore.setDepositsValidListGoerli(depositListGoerli); | ||||
|   console.log(depositListGoerli); | ||||
| @ -42,6 +48,7 @@ const getNetworksLiquidity = async (): Promise<void> => { | ||||
| }; | ||||
| 
 | ||||
| const getValidDeposits = async ( | ||||
|   token: string, | ||||
|   contract?: Contract | ||||
| ): Promise<ValidDeposit[]> => { | ||||
|   let p2pContract: Contract; | ||||
| @ -56,29 +63,41 @@ 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 }; | ||||
|  | ||||
| @ -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("") | ||||
|   ); | ||||
| 
 | ||||
|  | ||||
| @ -35,7 +35,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 | ||||
| @ -51,7 +51,7 @@ const listValidDepositTransactionsByWalletAddress = async ( | ||||
| const listAllTransactionByWalletAddress = async ( | ||||
|   walletAddress: string | ||||
| ): Promise<Event[]> => { | ||||
|   const p2pContract = getContract(); | ||||
|   const p2pContract = getContract(true); | ||||
| 
 | ||||
|   const filterDeposits = p2pContract.filters.DepositAdded([walletAddress]); | ||||
|   const eventsDeposits = await p2pContract.queryFilter(filterDeposits); | ||||
|  | ||||
| @ -1,10 +1,13 @@ | ||||
| <script setup lang="ts"> | ||||
| </script> | ||||
| <script setup lang="ts"></script> | ||||
| 
 | ||||
| <template> | ||||
|   <div class="modal-overlay inset-0 fixed justify-center backdrop-blur-sm sm:backdrop-blur-none"> | ||||
|   <div | ||||
|     class="modal-overlay inset-0 fixed justify-center backdrop-blur-sm sm:backdrop-blur-none" | ||||
|   > | ||||
|     <div class="modal px-5 text-center"> | ||||
|       <p class="text-black tracking-tighter leading-tight my-6 mx-2 text-justify"> | ||||
|       <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á | ||||
| @ -21,7 +24,6 @@ | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| .modal-overlay { | ||||
|   display: flex !important; | ||||
| } | ||||
| @ -62,5 +64,4 @@ button { | ||||
|   font-size: 14px; | ||||
|   border-radius: 10px; | ||||
| } | ||||
| 
 | ||||
| </style> | ||||
| </style> | ||||
|  | ||||
| @ -16,11 +16,17 @@ const etherStore = useEtherStore(); | ||||
| 
 | ||||
| const itemsToShow = ref<(Event | ValidDeposit)[]>([]); | ||||
| 
 | ||||
| const getExplorer = (): string => { | ||||
|   return etherStore.networkName == NetworkEnum.ethereum | ||||
|     ? "Etherscan" | ||||
|     : "Polygonscan"; | ||||
| }; | ||||
| 
 | ||||
| // Methods | ||||
| const isValidDeposit = ( | ||||
|   deposit: Event | ValidDeposit | ||||
| ): deposit is ValidDeposit => { | ||||
|   return (deposit as ValidDeposit).depositID !== undefined; | ||||
|   return (deposit as ValidDeposit).token !== undefined; | ||||
| }; | ||||
| 
 | ||||
| const showInitialItems = (): void => { | ||||
| @ -48,8 +54,8 @@ const getEventName = (event: string | undefined): string => { | ||||
| 
 | ||||
|   const possibleEventName: { [key: string]: string } = { | ||||
|     DepositAdded: "Oferta", | ||||
|     LockAdded: "Compra", | ||||
|     LockReleased: "Reserva", | ||||
|     LockAdded: "Reserva", | ||||
|     LockReleased: "Compra", | ||||
|   }; | ||||
| 
 | ||||
|   return possibleEventName[event]; | ||||
| @ -72,7 +78,7 @@ watch(props, async (): Promise<void> => { | ||||
| }); | ||||
| 
 | ||||
| //emits | ||||
| const emit = defineEmits(["cancelDeposit", "withdrawDeposit"]); | ||||
| const emit = defineEmits(["withdrawDeposit"]); | ||||
| 
 | ||||
| // initial itemsToShow valueb | ||||
| showInitialItems(); | ||||
| @ -109,7 +115,7 @@ showInitialItems(); | ||||
|             class="flex gap-2 cursor-pointer items-center justify-self-center" | ||||
|             @click="openEtherscanUrl((item as Event)?.transactionHash)" | ||||
|           > | ||||
|             <span class="last-release-info">Etherscan</span> | ||||
|             <span class="last-release-info">{{ getExplorer() }}</span> | ||||
|             <img alt="Redirect image" src="@/assets/redirect.svg" /> | ||||
|           </div> | ||||
|         </div> | ||||
| @ -122,19 +128,10 @@ showInitialItems(); | ||||
| 
 | ||||
|         <hr class="pb-3" /> | ||||
|         <div class="flex justify-between items-center"> | ||||
|           <div | ||||
|             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> | ||||
|           </div> | ||||
| 
 | ||||
|           <div | ||||
|             class="flex gap-2 cursor-pointer items-center justify-self-center border-2 p-2 border-amber-300 rounded-md" | ||||
|             @click=" | ||||
|               emit('withdrawDeposit', (item as ValidDeposit).depositID, index) | ||||
|               emit('withdrawDeposit', (item as ValidDeposit).token, index) | ||||
|             " | ||||
|           > | ||||
|             <img alt="Withdraw image" src="@/assets/withdraw.svg" /> | ||||
|  | ||||
| @ -10,6 +10,17 @@ describe("ListingComponent.vue", () => { | ||||
|     setActivePinia(createPinia()); | ||||
|   }); | ||||
| 
 | ||||
|   test("Test Message when an empty array is received", () => { | ||||
|     const wrapper = mount(ListingComponent, { | ||||
|       props: { | ||||
|         walletTransactions: [], | ||||
|         isManageMode: true, | ||||
|       }, | ||||
|     }); | ||||
| 
 | ||||
|     expect(wrapper.html()).toContain("Não há nenhuma transação anterior"); | ||||
|   }); | ||||
| 
 | ||||
|   test("Test Headers on List in Manage Mode", () => { | ||||
|     const wrapper = mount(ListingComponent, { | ||||
|       props: { | ||||
| @ -20,7 +31,6 @@ describe("ListingComponent.vue", () => { | ||||
| 
 | ||||
|     expect(wrapper.html()).toContain("Valor"); | ||||
|     expect(wrapper.html()).toContain("Data"); | ||||
|     expect(wrapper.html()).toContain("Cancelar oferta"); | ||||
|     expect(wrapper.html()).toContain("Retirar tokens"); | ||||
|   }); | ||||
| 
 | ||||
| @ -70,20 +80,6 @@ describe("ListingComponent.vue", () => { | ||||
|     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: { | ||||
|  | ||||
| @ -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"); | ||||
|   }); | ||||
| }); | ||||
| @ -154,10 +154,7 @@ const validatePix = async (): Promise<void> => { | ||||
|         @button-clicked="emit('pixValidated', e2eId)" | ||||
|       /> | ||||
|     </div> | ||||
|     <CustomModal | ||||
|       v-if="showModal" | ||||
|       @close-modal="showModal = false" | ||||
|     /> | ||||
|     <CustomModal v-if="showModal" @close-modal="showModal = false" /> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
|  | ||||
| @ -107,8 +107,13 @@ const enableOrDisableConfirmButton = (): void => { | ||||
| }; | ||||
| 
 | ||||
| watch(networkName, (): void => { | ||||
|   verifyLiquidity(); | ||||
|   enableOrDisableConfirmButton(); | ||||
| }); | ||||
| 
 | ||||
| watch(walletAddress, (): void => { | ||||
|   verifyLiquidity(); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
| @ -149,7 +154,9 @@ watch(networkName, (): void => { | ||||
|               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> | ||||
|             <span class="text-gray-900 sm:text-lg text-md w-fit" id="brz" | ||||
|               >BRZ</span | ||||
|             > | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
|  | ||||
| @ -14,10 +14,12 @@ const props = defineProps({ | ||||
| <template> | ||||
|   <div class="page"> | ||||
|     <div class="text-container"> | ||||
|       <span class="text font-extrabold sm:text-5xl text-xl sm:max-w-[50rem] max-w-[20rem]" | ||||
|       <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-normal sm:text-base text-xs sm:max-w-[30rem] max-w-[22rem]" | ||||
|       <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 | ||||
|  | ||||
| @ -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,10 +37,26 @@ 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> => { | ||||
|   console.log(postProcessKey(pixKey)); | ||||
|   if (walletAddress.value) emit("approveTokens", { offer, pixKey }); | ||||
|   else await connectProvider(); | ||||
| }; | ||||
| @ -47,10 +65,12 @@ const handleButtonClick = async ( | ||||
| <template> | ||||
|   <div class="page w-full"> | ||||
|     <div class="text-container"> | ||||
|       <span class="text font-extrabold sm:text-5xl text-3xl sm:max-w-[29rem] max-w-[20rem]" | ||||
|       <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 sm:text-base text-xs sm:max-w-[28rem] max-w-[30rem] sm:tracking-normal tracking-wide" | ||||
|       <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 | ||||
|       > | ||||
| @ -81,9 +101,7 @@ const handleButtonClick = async ( | ||||
|               class="sm:w-fit w-4" | ||||
|               src="@/assets/brz.svg" | ||||
|             /> | ||||
|             <span class="text-gray-900 w-fit" id="brz"> | ||||
|               BRZ | ||||
|             </span> | ||||
|             <span class="text-gray-900 w-fit" id="brz"> BRZ </span> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
| @ -103,15 +121,22 @@ const handleButtonClick = async ( | ||||
|       > | ||||
|         <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 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> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <script setup lang="ts"> | ||||
| import { storeToRefs } from "pinia"; | ||||
| import { useEtherStore } from "@/store/ether"; | ||||
| import { ref, onBeforeUnmount, onMounted } from "vue"; | ||||
| import { ref } from "vue"; | ||||
| import { onClickOutside } from "@vueuse/core"; | ||||
| import { NetworkEnum } from "@/model/NetworkEnum"; | ||||
| import { connectProvider, requestNetworkChange } from "@/blockchain/provider"; | ||||
|  | ||||
| @ -1,11 +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; | ||||
| }; | ||||
|  | ||||
| @ -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, | ||||
|   }, | ||||
| ]; | ||||
|  | ||||
							
								
								
									
										24
									
								
								src/utils/__tests__/debounce.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/utils/__tests__/debounce.spec.ts
									
									
									
									
									
										Normal 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
									
								
								src/utils/__tests__/decimalCount.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/utils/__tests__/decimalCount.spec.ts
									
									
									
									
									
										Normal 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); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										25
									
								
								src/utils/__tests__/networkLiquidity.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/utils/__tests__/networkLiquidity.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @ -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); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										16
									
								
								src/utils/pixKeyFormat.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/utils/pixKeyFormat.ts
									
									
									
									
									
										Normal 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; | ||||
| }; | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -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" | ||||
|     ] | ||||
| } | ||||
| @ -1,6 +1,6 @@ | ||||
| <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 { useEtherStore } from "@/store/ether"; | ||||
| @ -27,7 +27,7 @@ etherStore.setSellerView(false); | ||||
| // States | ||||
| const { loadingLock, walletAddress } = 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 loadingRelease = ref<boolean>(false); | ||||
| @ -46,7 +46,7 @@ const confirmBuyClick = async ( | ||||
|     flowStep.value = Step.Buy; | ||||
|     etherStore.setLoadingLock(true); | ||||
| 
 | ||||
|     await addLock(selectedDeposit.depositID, tokenValue) | ||||
|     await addLock(selectedDeposit.seller, selectedDeposit.token, tokenValue) | ||||
|       .then((lockID) => { | ||||
|         _lockID.value = lockID; | ||||
|       }) | ||||
| @ -63,7 +63,7 @@ const releaseTransaction = async (e2eId: string) => { | ||||
|   flowStep.value = Step.List; | ||||
|   loadingRelease.value = true; | ||||
| 
 | ||||
|   if (_lockID.value && tokenAmount.value) { | ||||
|   if (_lockID.value && tokenAmount.value && pixTarget.value) { | ||||
|     const release = await releaseLock( | ||||
|       pixTarget.value, | ||||
|       tokenAmount.value, | ||||
| @ -96,12 +96,12 @@ onMounted(async () => { | ||||
|   /> | ||||
|   <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'" | ||||
|     /> | ||||
| @ -113,7 +113,7 @@ onMounted(async () => { | ||||
|       :tokenAmount="tokenAmount" | ||||
|       @make-another-transaction="flowStep = Step.Search" | ||||
|     /> | ||||
|     <ValidationComponent | ||||
|     <LoadingComponent | ||||
|       v-if="loadingRelease" | ||||
|       :message="'A transação está sendo enviada para a rede. Em breve os tokens serão depositados em sua carteira.'" | ||||
|     /> | ||||
|  | ||||
| @ -4,7 +4,7 @@ import { storeToRefs } from "pinia"; | ||||
| import ListingComponent from "@/components/ListingComponent/ListingComponent.vue"; | ||||
| import type { BigNumber } from "ethers"; | ||||
| import { ref, watch, onMounted } from "vue"; | ||||
| import { cancelDeposit, withdrawDeposit } from "@/blockchain/buyerMethods"; | ||||
| import { withdrawDeposit } from "@/blockchain/buyerMethods"; | ||||
| import { listValidDepositTransactionsByWalletAddress } from "@/blockchain/wallet"; | ||||
| import type { ValidDeposit } from "@/model/ValidDeposit"; | ||||
| 
 | ||||
| @ -24,16 +24,9 @@ onMounted(async () => { | ||||
|   } | ||||
| }); | ||||
| 
 | ||||
| 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); | ||||
| const handleWithDrawDeposit = async (token: BigNumber, index: number) => { | ||||
|   const fixedAmount = "1"; // Need to ask user for amount | ||||
|   const response = await withdrawDeposit(token, fixedAmount); | ||||
|   if (response) { | ||||
|     console.log("Token retirado com sucesso."); | ||||
|     depositList.value.splice(index, 1); | ||||
| @ -68,7 +61,6 @@ watch(networkName, async () => { | ||||
|       <ListingComponent | ||||
|         :wallet-transactions="depositList" | ||||
|         :is-manage-mode="true" | ||||
|         @cancel-deposit="handleCancelDeposit" | ||||
|         @withdraw-deposit="handleWithDrawDeposit" | ||||
|       ></ListingComponent> | ||||
|     </div> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <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 LoadingComponent from "@/components/LoadingComponent/LoadingComponent.vue"; | ||||
| import { approveTokens, addDeposit } from "../blockchain/sellerMethods"; | ||||
| 
 | ||||
| import { ref } from "vue"; | ||||
| @ -57,7 +57,7 @@ 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.'" | ||||
|     /> | ||||
| @ -69,7 +69,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.'" | ||||
|     /> | ||||
|  | ||||
| @ -13,6 +13,7 @@ export default defineConfig({ | ||||
|       provider: "c8", | ||||
|       all: true, | ||||
|       src: ["./src"], | ||||
|       exclude: ["model/**", "**/__tests__/**"], | ||||
|       reporter: ["text", "lcov", "html"], | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
							
								
								
									
										27
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								yarn.lock
									
									
									
									
									
								
							| @ -1498,6 +1498,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 +1878,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" | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user