Compare commits
7 Commits
9cda680494
...
3227e3209c
Author | SHA1 | Date | |
---|---|---|---|
|
3227e3209c | ||
|
54cff28ba0 | ||
|
d5f9c8f6fa | ||
|
0f17a67e00 | ||
|
c90f468d3c | ||
|
c4dae86b5f | ||
|
92f6cb4d35 |
@ -59,9 +59,9 @@
|
||||
"postcss": "^8.4.18",
|
||||
"prettier": "^2.7.1",
|
||||
"tailwindcss": "^3.2.1",
|
||||
"typescript": "~4.7.4",
|
||||
"typescript": "~5.8.2",
|
||||
"vite": "^3.1.8",
|
||||
"vitest": "^0.28.1",
|
||||
"vue-tsc": "^1.0.8"
|
||||
"vue-tsc": "^2.2.8"
|
||||
}
|
||||
}
|
||||
|
@ -19,3 +19,14 @@
|
||||
opacity: 0;
|
||||
transform: translateY(15px);
|
||||
}
|
||||
|
||||
.resize-enter-active,
|
||||
.resize-leave-active {
|
||||
max-height: 100px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.resize-enter-from,
|
||||
.resize-leave-to {
|
||||
max-height: 0px;
|
||||
}
|
||||
|
@ -32,14 +32,6 @@ describe("addresses.ts functions", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("getTokenAddress Polygon", () => {
|
||||
const etherStore = useEtherStore();
|
||||
etherStore.setNetworkId(NetworkEnum.polygon);
|
||||
expect(getTokenAddress(TokenEnum.BRZ)).toBe(
|
||||
"0xC86042E9F2977C62Da8c9dDF7F9c40fde4796A29"
|
||||
);
|
||||
});
|
||||
|
||||
it("getTokenAddress Rootstock", () => {
|
||||
const etherStore = useEtherStore();
|
||||
etherStore.setNetworkId(NetworkEnum.rootstock);
|
||||
@ -48,7 +40,6 @@ describe("addresses.ts functions", () => {
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
it("getTokenAddress Default", () => {
|
||||
expect(getTokenAddress(TokenEnum.BRZ)).toBe(
|
||||
"0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00"
|
||||
@ -63,14 +54,6 @@ describe("addresses.ts functions", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("getP2PixAddress Polygon", () => {
|
||||
const etherStore = useEtherStore();
|
||||
etherStore.setNetworkId(NetworkEnum.polygon);
|
||||
expect(getP2PixAddress()).toBe(
|
||||
"0x4A2886EAEc931e04297ed336Cc55c4eb7C75BA00"
|
||||
);
|
||||
});
|
||||
|
||||
it("getP2PixAddress Rootstock", () => {
|
||||
const etherStore = useEtherStore();
|
||||
etherStore.setNetworkId(NetworkEnum.rootstock);
|
||||
@ -91,12 +74,6 @@ describe("addresses.ts functions", () => {
|
||||
expect(getProviderUrl()).toBe(import.meta.env.VITE_GOERLI_API_URL);
|
||||
});
|
||||
|
||||
it("getProviderUrl Polygon", () => {
|
||||
const etherStore = useEtherStore();
|
||||
etherStore.setNetworkId(NetworkEnum.polygon);
|
||||
expect(getProviderUrl()).toBe(import.meta.env.VITE_MUMBAI_API_URL);
|
||||
});
|
||||
|
||||
it("getProviderUrl Rootstock", () => {
|
||||
const etherStore = useEtherStore();
|
||||
etherStore.setNetworkId(NetworkEnum.rootstock);
|
||||
@ -110,12 +87,12 @@ describe("addresses.ts functions", () => {
|
||||
it("isPossibleNetwork Returns", () => {
|
||||
const etherStore = useEtherStore();
|
||||
etherStore.setNetworkId(NetworkEnum.sepolia);
|
||||
expect(isPossibleNetwork(0x5)).toBe(true);
|
||||
expect(isPossibleNetwork(5)).toBe(true);
|
||||
expect(isPossibleNetwork(0x13881)).toBe(true);
|
||||
expect(isPossibleNetwork(80001)).toBe(true);
|
||||
expect(isPossibleNetwork(0x5 as NetworkEnum)).toBe(true);
|
||||
expect(isPossibleNetwork(5 as NetworkEnum)).toBe(true);
|
||||
expect(isPossibleNetwork(0x13881 as NetworkEnum)).toBe(true);
|
||||
expect(isPossibleNetwork(80001 as NetworkEnum)).toBe(true);
|
||||
|
||||
expect(isPossibleNetwork(NaN)).toBe(false);
|
||||
expect(isPossibleNetwork(0x55)).toBe(false);
|
||||
expect(isPossibleNetwork(NaN as NetworkEnum)).toBe(false);
|
||||
expect(isPossibleNetwork(0x55 as NetworkEnum)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -1,28 +1,22 @@
|
||||
import { getContract, getProvider } from "./provider";
|
||||
import { getP2PixAddress, getTokenAddress } from "./addresses";
|
||||
import { encodeBytes32String, Signature, Contract, parseEther } from "ethers";
|
||||
|
||||
import p2pix from "@/utils/smart_contract_files/P2PIX.json";
|
||||
|
||||
import {
|
||||
solidityPackedKeccak256,
|
||||
encodeBytes32String,
|
||||
Signature,
|
||||
Contract,
|
||||
getBytes,
|
||||
Wallet,
|
||||
parseEther,
|
||||
} from "ethers";
|
||||
import type { TokenEnum } from "@/model/NetworkEnum";
|
||||
import { createSolicitation } from "../utils/bbPay";
|
||||
import type { Offer } from "../utils/bbPay";
|
||||
|
||||
const addLock = async (
|
||||
seller: string,
|
||||
sellerId: string,
|
||||
token: string,
|
||||
amount: number
|
||||
): Promise<string> => {
|
||||
const p2pContract = await getContract();
|
||||
|
||||
const lock = await p2pContract.lock(
|
||||
seller,
|
||||
sellerId,
|
||||
token,
|
||||
parseEther(String(amount)), // BigNumber
|
||||
[],
|
||||
@ -32,26 +26,29 @@ const addLock = async (
|
||||
const lock_rec = await lock.wait();
|
||||
const [t] = lock_rec.events;
|
||||
|
||||
return String(t.args.lockID);
|
||||
const offer: Offer = {
|
||||
amount,
|
||||
lockId: String(t.args.lockID),
|
||||
sellerId: sellerId,
|
||||
};
|
||||
const solicitation = await createSolicitation(offer);
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
const releaseLock = async (
|
||||
pixKey: string,
|
||||
amount: number,
|
||||
e2eId: string,
|
||||
lockId: string
|
||||
): Promise<any> => {
|
||||
const mockBacenSigner = new Wallet(
|
||||
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
||||
);
|
||||
const releaseLock = async (solicitation: any): Promise<any> => {
|
||||
// const mockBacenSigner = new Wallet(
|
||||
// "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
||||
// );
|
||||
|
||||
const messageToSign = solidityPackedKeccak256(
|
||||
["bytes32", "uint256", "bytes32"],
|
||||
[pixKey, parseEther(String(amount)), encodeBytes32String(e2eId)]
|
||||
);
|
||||
// const messageToSign = solidityPackedKeccak256(
|
||||
// ["bytes32", "uint256", "bytes32"],
|
||||
// [sellerId, parseEther(String(amount)), encodeBytes32String(signature)]
|
||||
// );
|
||||
|
||||
// const messageHashBytes = getBytes(messageToSign);
|
||||
// const flatSig = await mockBacenSigner.signMessage(messageHashBytes);
|
||||
|
||||
const messageHashBytes = getBytes(messageToSign);
|
||||
const flatSig = await mockBacenSigner.signMessage(messageHashBytes);
|
||||
const provider = getProvider();
|
||||
|
||||
const sig = Signature.from(flatSig);
|
||||
|
@ -5,12 +5,15 @@ import { encodeBytes32String, Contract, parseEther } from "ethers";
|
||||
|
||||
import mockToken from "../utils/smart_contract_files/MockToken.json";
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { createParticipant } from "@/utils/bbPay";
|
||||
import type { Participant } from "@/utils/bbPay";
|
||||
|
||||
const approveTokens = async (tokenQty: string): Promise<any> => {
|
||||
const approveTokens = async (participant: Participant): Promise<any> => {
|
||||
const provider = getProvider();
|
||||
const signer = await provider?.getSigner();
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
etherStore.setSeller(participant);
|
||||
const tokenContract = new Contract(
|
||||
getTokenAddress(etherStore.selectedToken),
|
||||
mockToken.abi,
|
||||
@ -22,11 +25,11 @@ const approveTokens = async (tokenQty: string): Promise<any> => {
|
||||
await signer?.getAddress(),
|
||||
getP2PixAddress()
|
||||
);
|
||||
if (approved < parseEther(tokenQty)) {
|
||||
if (approved < parseEther(participant.offer)) {
|
||||
// Approve tokens
|
||||
const apprv = await tokenContract.approve(
|
||||
getP2PixAddress(),
|
||||
parseEther(tokenQty)
|
||||
parseEther(participant.offer)
|
||||
);
|
||||
await apprv.wait();
|
||||
return true;
|
||||
@ -34,15 +37,18 @@ const approveTokens = async (tokenQty: string): Promise<any> => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const addDeposit = async (tokenQty: string, pixKey: string): Promise<any> => {
|
||||
const addDeposit = async (): Promise<any> => {
|
||||
const p2pContract = await getContract();
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const sellerId = await createParticipant(etherStore.seller);
|
||||
etherStore.setSellerId(sellerId.id);
|
||||
|
||||
const deposit = await p2pContract.deposit(
|
||||
pixKey,
|
||||
sellerId,
|
||||
encodeBytes32String(""),
|
||||
getTokenAddress(etherStore.selectedToken),
|
||||
parseEther(tokenQty),
|
||||
parseEther(etherStore.seller.offer),
|
||||
true
|
||||
);
|
||||
|
||||
|
@ -26,8 +26,8 @@ export const updateWalletStatus = async (): Promise<void> => {
|
||||
|
||||
const provider = await getProvider();
|
||||
const signer = await provider?.getSigner();
|
||||
|
||||
const { chainId } = await provider?.getNetwork();
|
||||
const network = await provider?.getNetwork();
|
||||
const chainId = network?.chainId;
|
||||
if (!isPossibleNetwork(Number(chainId))) {
|
||||
window.alert("Invalid chain!:" + chainId);
|
||||
return;
|
||||
|
@ -1,75 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import { pix } from "@/utils/QrCodePix";
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import { debounce } from "@/utils/debounce";
|
||||
import CustomButton from "@/components/CustomButton/CustomButton.vue";
|
||||
import CustomModal from "@/components//CustomModal/CustomModal.vue";
|
||||
import api from "@/services/index";
|
||||
import QRCode from "qrcode";
|
||||
|
||||
// props and store references
|
||||
const props = defineProps({
|
||||
pixTarget: String,
|
||||
tokenValue: Number,
|
||||
sellerId: String,
|
||||
amount: Number,
|
||||
qrcode: String,
|
||||
});
|
||||
|
||||
const windowSize = ref<number>(window.innerWidth);
|
||||
const qrCode = ref<string>("");
|
||||
const qrCodePayload = ref<string>("");
|
||||
const isPixValid = ref<boolean>(false);
|
||||
const isCodeInputEmpty = ref<boolean>(true);
|
||||
const showWarnModal = ref<boolean>(true);
|
||||
const e2eId = ref<string>("");
|
||||
const releaseSignature = ref<string>("");
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["pixValidated"]);
|
||||
|
||||
const pixQrCode = pix({
|
||||
pixKey: props.pixTarget ?? "",
|
||||
value: props.tokenValue,
|
||||
});
|
||||
|
||||
pixQrCode.base64QrCode().then((code: string) => {
|
||||
qrCode.value = code;
|
||||
});
|
||||
|
||||
qrCodePayload.value = pixQrCode.payload();
|
||||
|
||||
const handleInputEvent = async (event: any): Promise<void> => {
|
||||
const { value } = event.target;
|
||||
e2eId.value = value;
|
||||
await validatePix();
|
||||
};
|
||||
|
||||
const validatePix = async (): Promise<void> => {
|
||||
if (e2eId.value == "") {
|
||||
isPixValid.value = false;
|
||||
isCodeInputEmpty.value = true;
|
||||
return;
|
||||
}
|
||||
const sellerPixKey = props.pixTarget;
|
||||
const transactionValue = props.tokenValue;
|
||||
|
||||
if (sellerPixKey && transactionValue) {
|
||||
const body_req = {
|
||||
e2e_id: e2eId.value,
|
||||
pix_key: sellerPixKey,
|
||||
pix_value: transactionValue,
|
||||
};
|
||||
|
||||
isCodeInputEmpty.value = false;
|
||||
|
||||
try {
|
||||
await api.post("validate_pix", body_req);
|
||||
isPixValid.value = true;
|
||||
} catch (error) {
|
||||
isPixValid.value = false;
|
||||
}
|
||||
} else {
|
||||
isCodeInputEmpty.value = false;
|
||||
isPixValid.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener(
|
||||
"resize",
|
||||
@ -94,7 +44,7 @@ onUnmounted(() => {
|
||||
</span>
|
||||
<span class="text font-medium lg:text-md text-sm max-w-[28rem]">
|
||||
Após realizar o Pix no banco de sua preferência, clique no botão abaixo
|
||||
para gerar a assinatura para liberação dos tokens.
|
||||
para liberação dos tokens.
|
||||
</span>
|
||||
</div>
|
||||
<div class="main-container max-w-md text-black">
|
||||
@ -105,7 +55,7 @@ onUnmounted(() => {
|
||||
<span class="text-center font-bold">Código pix</span>
|
||||
<div class="break-words w-4/5">
|
||||
<span class="text-center text-xs">
|
||||
{{ qrCodePayload }}
|
||||
{{ qrCode }}
|
||||
</span>
|
||||
</div>
|
||||
<img
|
||||
@ -115,17 +65,11 @@ onUnmounted(() => {
|
||||
height="16"
|
||||
class="pt-2 lg:mb-5 cursor-pointer"
|
||||
/>
|
||||
<span class="text-xs text-start hidden sm:inline-block">
|
||||
<strong>ATENÇÃO!</strong> A transação só será processada após inserir
|
||||
o código de autenticação. Caso contrário não conseguiremos comprovar o
|
||||
seu depósito e não será possível transferir os tokens para sua
|
||||
carteira. Confira aqui como encontrar o código no comprovante.
|
||||
</span>
|
||||
</div>
|
||||
<CustomButton
|
||||
:is-disabled="isPixValid == false"
|
||||
:text="'Enviar para a rede'"
|
||||
@button-clicked="emit('pixValidated', e2eId)"
|
||||
@button-clicked="emit('pixValidated', releaseSignature)"
|
||||
/>
|
||||
</div>
|
||||
<CustomModal
|
||||
|
@ -34,6 +34,7 @@ const tokenValue = ref<number>(0);
|
||||
const enableConfirmButton = ref<boolean>(false);
|
||||
const hasLiquidity = ref<boolean>(true);
|
||||
const validDecimals = ref<boolean>(true);
|
||||
const identification = ref<string>("");
|
||||
const selectedDeposits = ref<ValidDeposit[]>();
|
||||
|
||||
import ChevronDown from "@/assets/chevronDown.svg";
|
||||
@ -104,9 +105,17 @@ const verifyLiquidity = (): void => {
|
||||
};
|
||||
|
||||
const enableOrDisableConfirmButton = (): void => {
|
||||
enableConfirmButton.value =
|
||||
!!selectedDeposits.value &&
|
||||
!!selectedDeposits.value.find((d) => d.network === networkName.value);
|
||||
if (!selectedDeposits.value) {
|
||||
enableConfirmButton.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedDeposits.value.find((d) => d.network === networkName.value)) {
|
||||
enableConfirmButton.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
enableConfirmButton.value = true;
|
||||
};
|
||||
|
||||
watch(networkName, (): void => {
|
||||
@ -117,6 +126,18 @@ watch(networkName, (): void => {
|
||||
watch(walletAddress, (): void => {
|
||||
verifyLiquidity();
|
||||
});
|
||||
|
||||
// Add form submission handler
|
||||
const handleSubmit = async (e: Event): Promise<void> => {
|
||||
e.preventDefault();
|
||||
if (!enableConfirmButton.value) return;
|
||||
|
||||
if (walletAddress.value) {
|
||||
await emitConfirmButton();
|
||||
} else {
|
||||
await connectAccount();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -132,7 +153,7 @@ watch(walletAddress, (): void => {
|
||||
tokens após realizar o Pix</span
|
||||
>
|
||||
</div>
|
||||
<div class="main-container">
|
||||
<form class="main-container" @submit="handleSubmit">
|
||||
<div class="backdrop-blur -z-10 w-full h-full"></div>
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-5 rounded-lg border-y-10"
|
||||
@ -140,14 +161,16 @@ watch(walletAddress, (): void => {
|
||||
<div class="flex justify-between sm:w-full items-center">
|
||||
<input
|
||||
type="number"
|
||||
name="tokenAmount"
|
||||
class="border-none outline-none text-lg text-gray-900"
|
||||
v-bind:class="{
|
||||
'font-semibold': tokenValue != undefined,
|
||||
'text-xl': tokenValue != undefined,
|
||||
}"
|
||||
@input="debounce(handleInputEvent, 500)($event)"
|
||||
placeholder="0 "
|
||||
placeholder="0"
|
||||
step=".01"
|
||||
required
|
||||
/>
|
||||
<div class="relative overflow-visible">
|
||||
<button
|
||||
@ -260,18 +283,33 @@ watch(walletAddress, (): void => {
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<CustomButton
|
||||
v-if="!walletAddress"
|
||||
:text="'Conectar carteira'"
|
||||
@buttonClicked="connectAccount()"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
v-model="identification"
|
||||
maxlength="14"
|
||||
:pattern="'^\\d{11}$|^\\d{14}$'"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full"
|
||||
placeholder="Digite seu CPF ou CNPJ (somente números)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Action buttons -->
|
||||
<CustomButton
|
||||
v-if="walletAddress"
|
||||
:text="'Confirmar compra'"
|
||||
:is-disabled="!enableConfirmButton"
|
||||
@buttonClicked="emitConfirmButton()"
|
||||
type="submit"
|
||||
text="Confirmar Oferta"
|
||||
/>
|
||||
</div>
|
||||
<CustomButton
|
||||
v-else
|
||||
text="Conectar carteira"
|
||||
@buttonClicked="connectAccount()"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -306,4 +344,10 @@ input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.custom-button {
|
||||
@apply w-full py-3 px-6 rounded-lg font-semibold text-white bg-indigo-600
|
||||
hover:bg-indigo-700 disabled:bg-gray-400 disabled:cursor-not-allowed
|
||||
transition-colors duration-200;
|
||||
}
|
||||
</style>
|
||||
|
360
src/components/SellerSteps/SellerComponent.vue
Normal file
360
src/components/SellerSteps/SellerComponent.vue
Normal file
@ -0,0 +1,360 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import CustomButton from "../CustomButton/CustomButton.vue";
|
||||
import { pixFormatValidation, postProcessKey } from "@/utils/pixKeyFormat";
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { TokenEnum } from "@/model/NetworkEnum";
|
||||
import { getTokenImage } from "@/utils/imagesPath";
|
||||
import { useOnboard } from "@web3-onboard/vue";
|
||||
import ChevronDown from "@/assets/chevron.svg";
|
||||
|
||||
// Import the bank list
|
||||
import bankList from "@/utils/files/isbpList.json";
|
||||
import type { Participant } from "@/utils/bbPay";
|
||||
|
||||
// Define Bank interface
|
||||
interface Bank {
|
||||
ISPB: string;
|
||||
longName: string;
|
||||
}
|
||||
|
||||
// html references
|
||||
const tokenDropdownRef = ref<any>(null);
|
||||
const formRef = ref<HTMLFormElement | null>(null);
|
||||
|
||||
// Reactive state
|
||||
const etherStore = useEtherStore();
|
||||
const { walletAddress, selectedToken } = storeToRefs(etherStore);
|
||||
|
||||
const fullName = ref<string>("");
|
||||
const offer = ref<string>("");
|
||||
const identification = ref<string>("");
|
||||
const account = ref<string>("");
|
||||
const branch = ref<string>("");
|
||||
const accountType = ref<string>("");
|
||||
const selectTokenToggle = ref<boolean>(false);
|
||||
const savingsVariation = ref<string>("");
|
||||
const errors = ref<{ [key: string]: string }>({});
|
||||
|
||||
// Bank selection
|
||||
const bankSearchQuery = ref<string>("");
|
||||
const showBankList = ref<boolean>(false);
|
||||
const selectedBank = ref<Bank | null>(null);
|
||||
|
||||
const filteredBanks = computed(() => {
|
||||
if (!bankSearchQuery.value) return [];
|
||||
return bankList
|
||||
.filter((bank) =>
|
||||
bank.longName.toLowerCase().includes(bankSearchQuery.value.toLowerCase())
|
||||
)
|
||||
.slice(0, 5);
|
||||
});
|
||||
|
||||
const handleBankSelect = (bank: Bank) => {
|
||||
selectedBank.value = bank;
|
||||
bankSearchQuery.value = bank.longName;
|
||||
showBankList.value = false;
|
||||
};
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["approveTokens"]);
|
||||
|
||||
// Methods
|
||||
const connectAccount = async (): Promise<void> => {
|
||||
const { connectWallet } = useOnboard();
|
||||
await connectWallet();
|
||||
};
|
||||
|
||||
const handleSubmit = (e: Event): void => {
|
||||
e.preventDefault();
|
||||
|
||||
const processedIdentification = postProcessKey(identification.value);
|
||||
|
||||
const data: Participant = {
|
||||
offer: offer.value,
|
||||
fullName: fullName.value,
|
||||
identification: processedIdentification,
|
||||
bankIspb: selectedBank.value?.ISPB,
|
||||
accountType: accountType.value,
|
||||
account: account.value,
|
||||
branch: branch.value,
|
||||
savingsVariation: savingsVariation.value || "",
|
||||
};
|
||||
|
||||
emit("approveTokens", data);
|
||||
};
|
||||
|
||||
// Token selection
|
||||
const openTokenSelection = (): void => {
|
||||
selectTokenToggle.value = true;
|
||||
};
|
||||
|
||||
const handleSelectedToken = (token: TokenEnum): void => {
|
||||
etherStore.setSelectedToken(token);
|
||||
selectTokenToggle.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<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]"
|
||||
>
|
||||
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"
|
||||
>
|
||||
Digite sua oferta, informe a chave Pix, selecione a rede, aprove o envio
|
||||
da transação e confirme sua oferta.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<form ref="formRef" @submit="handleSubmit" class="main-container">
|
||||
<!-- Offer input -->
|
||||
<div
|
||||
class="flex justify-between items-center w-full bg-white sm:px-10 px-6 py-5 rounded-lg border-y-10 gap-4"
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
v-model="offer"
|
||||
class="border-none outline-none text-gray-900 sm:w-fit w-3/4 flex-grow"
|
||||
:class="{
|
||||
'!font-medium': offer !== undefined && offer !== '',
|
||||
'text-xl': offer !== undefined && offer !== '',
|
||||
}"
|
||||
min="0.01"
|
||||
max="999999999.99"
|
||||
pattern="\d+(\.\d{0,2})?"
|
||||
placeholder="Digite sua oferta (mínimo R$0,01)"
|
||||
step=".01"
|
||||
required
|
||||
/>
|
||||
<div class="relative overflow-visible">
|
||||
<button
|
||||
ref="tokenDropdownRef"
|
||||
class="flex flex-row items-center p-2 bg-gray-300 hover:bg-gray-200 focus:outline-indigo-800 focus:outline-2 rounded-3xl min-w-fit gap-2 transition-colors"
|
||||
@click="openTokenSelection()"
|
||||
>
|
||||
<img
|
||||
alt="Token image"
|
||||
class="sm:w-fit w-4"
|
||||
:src="getTokenImage(selectedToken)"
|
||||
/>
|
||||
<span
|
||||
class="text-gray-900 sm:text-lg text-md font-medium"
|
||||
id="token"
|
||||
>
|
||||
{{ selectedToken }}
|
||||
</span>
|
||||
<ChevronDown
|
||||
class="text-gray-900 pr-4 sm:pr-0 transition-all duration-500 ease-in-out"
|
||||
:class="{ 'scale-y-[-1]': selectTokenToggle }"
|
||||
alt="Chevron Down"
|
||||
/>
|
||||
</button>
|
||||
<transition name="dropdown">
|
||||
<div
|
||||
v-if="selectTokenToggle"
|
||||
class="mt-2 text-gray-900 absolute right-0 z-50 w-full min-w-max"
|
||||
>
|
||||
<div
|
||||
class="bg-white rounded-xl z-10 border border-gray-300 drop-shadow-md shadow-md overflow-clip"
|
||||
>
|
||||
<div
|
||||
v-for="token in TokenEnum"
|
||||
:key="token"
|
||||
class="flex menu-button gap-2 px-4 cursor-pointer hover:bg-gray-300 transition-colors"
|
||||
@click="handleSelectedToken(token)"
|
||||
>
|
||||
<img
|
||||
:alt="token + ' logo'"
|
||||
width="20"
|
||||
height="20"
|
||||
:src="getTokenImage(token)"
|
||||
/>
|
||||
<span
|
||||
class="text-gray-900 py-4 text-end font-semibold text-sm"
|
||||
>
|
||||
{{ token }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Full name input -->
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
v-model="fullName"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full"
|
||||
maxlength="60"
|
||||
:class="{ 'text-xl font-medium': fullName }"
|
||||
placeholder="Digite seu nome completo"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- CPF or CNPJ input -->
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
v-model="identification"
|
||||
maxlength="14"
|
||||
:pattern="'^\\d{11}$|^\\d{14}$'"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full"
|
||||
:class="{ 'text-xl font-medium': identification }"
|
||||
placeholder="Digite seu CPF ou CNPJ (somente números)"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<!-- Bank selection -->
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
|
||||
>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
v-model="bankSearchQuery"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full"
|
||||
:class="{ 'text-xl font-medium': bankSearchQuery }"
|
||||
placeholder="Buscar banco"
|
||||
@focus="showBankList = true"
|
||||
required
|
||||
/>
|
||||
<div
|
||||
v-if="showBankList && filteredBanks.length > 0"
|
||||
class="absolute top-full left-0 right-0 mt-1 bg-white border border-gray-200 rounded-md shadow-lg z-50 max-h-60 overflow-y-auto"
|
||||
>
|
||||
<div
|
||||
v-for="bank in filteredBanks"
|
||||
:key="bank.ISPB"
|
||||
class="px-4 py-2 hover:bg-gray-100 cursor-pointer transition-colors"
|
||||
@click="handleBankSelect(bank)"
|
||||
>
|
||||
<div class="text-sm font-medium text-gray-900">
|
||||
{{ bank.longName }}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500">ISPB: {{ bank.ISPB }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span v-if="errors.bank" class="text-red-500 text-sm mt-2">{{
|
||||
errors.bank
|
||||
}}</span>
|
||||
</div>
|
||||
<!-- Account and Branch inputs -->
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
|
||||
>
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-1">
|
||||
<input
|
||||
type="text"
|
||||
v-model="account"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full"
|
||||
:class="{ 'text-xl font-medium': account }"
|
||||
placeholder="Número da conta"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<input
|
||||
type="text"
|
||||
v-model="branch"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full"
|
||||
:class="{ 'text-xl font-medium': branch }"
|
||||
placeholder="Agência"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Account Type Selection -->
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
|
||||
>
|
||||
<div class="flex gap-4">
|
||||
<div class="flex-1">
|
||||
<select
|
||||
v-model="accountType"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full"
|
||||
required
|
||||
>
|
||||
<option value="" disabled selected>Tipo de conta</option>
|
||||
<option value="1">Conta Corrente</option>
|
||||
<option value="2">Conta Poupança</option>
|
||||
<option value="3">Conta Salário</option>
|
||||
<option value="4">Conta Pré-Paga</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Savings Account Variation -->
|
||||
<Transition name="resize">
|
||||
<input
|
||||
v-if="accountType === '2'"
|
||||
type="text"
|
||||
v-model="savingsVariation"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
|
||||
:class="{ 'text-xl font-medium': savingsVariation }"
|
||||
placeholder="Variação da poupança"
|
||||
required
|
||||
/>
|
||||
</Transition>
|
||||
<!-- Action buttons -->
|
||||
<CustomButton v-if="walletAddress" type="submit" text="Aprovar tokens" />
|
||||
<CustomButton
|
||||
v-else
|
||||
text="Conectar carteira"
|
||||
@buttonClicked="connectAccount()"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.custom-divide {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #d1d5db;
|
||||
}
|
||||
.bottom-position {
|
||||
top: -20px;
|
||||
right: 50%;
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
.page {
|
||||
@apply flex flex-col items-center justify-center w-full mt-16;
|
||||
}
|
||||
|
||||
.text-container {
|
||||
@apply flex flex-col items-center justify-center gap-4;
|
||||
}
|
||||
|
||||
.text {
|
||||
@apply text-white text-center;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply sm:text-lg text-sm;
|
||||
}
|
||||
</style>
|
@ -6,7 +6,7 @@ const emit = defineEmits(["sendNetwork"]);
|
||||
|
||||
// props and store references
|
||||
const props = defineProps({
|
||||
pixKey: String,
|
||||
sellerId: String,
|
||||
offer: Number,
|
||||
selectedToken: String,
|
||||
});
|
||||
@ -39,7 +39,7 @@ const props = defineProps({
|
||||
<div class="my-3">
|
||||
<p>Chave Pix</p>
|
||||
<p class="text-xl text-gray-900 break-words">
|
||||
{{ props.pixKey }}
|
||||
{{ props.sellerId }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
|
@ -1,263 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
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";
|
||||
import { TokenEnum } from "@/model/NetworkEnum";
|
||||
import { getTokenImage } from "@/utils/imagesPath";
|
||||
import { onClickOutside } from "@vueuse/core";
|
||||
import { useOnboard } from "@web3-onboard/vue";
|
||||
|
||||
import ChevronDown from "@/assets/chevron.svg";
|
||||
|
||||
// html references
|
||||
const tokenDropdownRef = ref<any>(null);
|
||||
|
||||
// Reactive state
|
||||
const etherStore = useEtherStore();
|
||||
const { walletAddress, selectedToken } = storeToRefs(etherStore);
|
||||
|
||||
const offer = ref<string>("");
|
||||
const pixKey = ref<string>("");
|
||||
const selectTokenToggle = ref<boolean>(false);
|
||||
|
||||
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"]);
|
||||
|
||||
// Blockchain methods
|
||||
const connectAccount = async (): Promise<void> => {
|
||||
const { connectWallet } = useOnboard();
|
||||
await connectWallet();
|
||||
};
|
||||
|
||||
// Debounce methods
|
||||
const handleInputEvent = (event: any): void => {
|
||||
const { value } = event.target;
|
||||
|
||||
offer.value = value;
|
||||
|
||||
if (decimalCount(offer.value) > 2) {
|
||||
validDecimals.value = false;
|
||||
enableSelectButton.value = false;
|
||||
return;
|
||||
}
|
||||
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 openTokenSelection = (): void => {
|
||||
selectTokenToggle.value = true;
|
||||
};
|
||||
|
||||
onClickOutside(tokenDropdownRef, () => {
|
||||
selectTokenToggle.value = false;
|
||||
});
|
||||
|
||||
const handleSelectedToken = (token: TokenEnum): void => {
|
||||
etherStore.setSelectedToken(token);
|
||||
selectTokenToggle.value = false;
|
||||
};
|
||||
|
||||
const handleSellClick = async (
|
||||
offer: string,
|
||||
pixKey: string
|
||||
): Promise<void> => {
|
||||
const postProcessedPixKey = postProcessKey(pixKey);
|
||||
emit("approveTokens", { offer, postProcessedPixKey });
|
||||
};
|
||||
</script>
|
||||
|
||||
<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]"
|
||||
>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"
|
||||
>Digite sua oferta, informe a chave Pix, selecione a rede, aprove o
|
||||
envio da transação e confirme sua oferta.</span
|
||||
>
|
||||
</div>
|
||||
<div class="main-container">
|
||||
<div class="backdrop-blur -z-10 w-full h-full"></div>
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-5 rounded-lg border-y-10"
|
||||
>
|
||||
<div class="flex justify-between items-center">
|
||||
<input
|
||||
type="number"
|
||||
v-model="offer"
|
||||
class="border-none outline-none text-gray-900 sm:w-fit w-3/4"
|
||||
:class="{
|
||||
'!font-medium': offer !== undefined && offer !== '',
|
||||
'text-xl': offer !== undefined && offer !== '',
|
||||
}"
|
||||
@input="debounce(handleInputEvent, 500)($event)"
|
||||
placeholder="Digite sua oferta"
|
||||
step=".01"
|
||||
/>
|
||||
<div class="relative overflow-visible">
|
||||
<button
|
||||
ref="tokenDropdownRef"
|
||||
class="flex flex-row items-center p-2 bg-gray-300 hover:bg-gray-200 focus:outline-indigo-800 focus:outline-2 rounded-3xl min-w-fit gap-2 transition-colors"
|
||||
@click="openTokenSelection()"
|
||||
>
|
||||
<img
|
||||
alt="Token image"
|
||||
class="sm:w-fit w-4"
|
||||
:src="getTokenImage(selectedToken)"
|
||||
/>
|
||||
<span
|
||||
class="text-gray-900 sm:text-lg text-md font-medium"
|
||||
id="token"
|
||||
>
|
||||
{{ selectedToken }}
|
||||
</span>
|
||||
<ChevronDown
|
||||
class="text-gray-900 pr-4 sm:pr-0 transition-all duration-500 ease-in-out"
|
||||
:class="{ 'scale-y-[-1]': selectTokenToggle }"
|
||||
alt="Chevron Down"
|
||||
/>
|
||||
</button>
|
||||
<transition name="dropdown">
|
||||
<div
|
||||
v-if="selectTokenToggle"
|
||||
class="mt-2 text-gray-900 absolute right-0 z-50 w-full min-w-max"
|
||||
>
|
||||
<div
|
||||
class="bg-white rounded-xl z-10 border border-gray-300 drop-shadow-md shadow-md overflow-clip"
|
||||
>
|
||||
<div
|
||||
v-for="token in TokenEnum"
|
||||
:key="token"
|
||||
class="flex menu-button gap-2 px-4 cursor-pointer hover:bg-gray-300 transition-colors"
|
||||
@click="handleSelectedToken(token)"
|
||||
>
|
||||
<img
|
||||
:alt="token + ' logo'"
|
||||
width="20"
|
||||
height="20"
|
||||
:src="getTokenImage(token)"
|
||||
/>
|
||||
<span
|
||||
class="text-gray-900 py-4 text-end font-semibold text-sm"
|
||||
>
|
||||
{{ token }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex pt-2 justify-center" v-if="!validDecimals">
|
||||
<span class="text-red-500 font-normal text-sm"
|
||||
>Por favor utilize no máximo 2 casas decimais</span
|
||||
>
|
||||
</div>
|
||||
<div class="flex pt-2 justify-center" v-else-if="!hasLiquidity">
|
||||
<span class="text-red-500 font-normal text-sm"
|
||||
>Atualmente não há liquidez nas redes para sua demanda</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col w-full bg-white sm:px-10 px-6 py-8 rounded-lg border-y-10"
|
||||
>
|
||||
<div class="flex justify-between w-full items-center">
|
||||
<input
|
||||
@input="debounce(handlePixKeyInputEvent, 500)($event)"
|
||||
type="text"
|
||||
v-model="pixKey"
|
||||
class="border-none outline-none sm:text-lg text-sm text-gray-900 w-fit"
|
||||
:class="{
|
||||
'!font-medium': pixKey !== undefined && pixKey !== '',
|
||||
'text-xl': pixKey !== undefined && pixKey !== '',
|
||||
}"
|
||||
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
|
||||
v-if="walletAddress"
|
||||
:text="'Aprovar tokens'"
|
||||
:isDisabled="!validDecimals || !validPixFormat"
|
||||
@buttonClicked="handleSellClick(offer, pixKey)"
|
||||
/>
|
||||
<CustomButton
|
||||
v-if="!walletAddress"
|
||||
:text="'Conectar carteira'"
|
||||
@buttonClicked="connectAccount()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.custom-divide {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid #d1d5db;
|
||||
}
|
||||
.bottom-position {
|
||||
top: -20px;
|
||||
right: 50%;
|
||||
transform: translateX(50%);
|
||||
}
|
||||
|
||||
.page {
|
||||
@apply flex flex-col items-center justify-center w-full mt-16;
|
||||
}
|
||||
|
||||
.text-container {
|
||||
@apply flex flex-col items-center justify-center gap-4;
|
||||
}
|
||||
|
||||
.text {
|
||||
@apply text-white text-center;
|
||||
}
|
||||
|
||||
input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
appearance: textfield;
|
||||
}
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply sm:text-lg text-sm;
|
||||
}
|
||||
</style>
|
5
src/model/Bank.ts
Normal file
5
src/model/Bank.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface Bank {
|
||||
COMPE: string;
|
||||
ISPB: string;
|
||||
longName: string;
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
import type { Event } from "ethers";
|
||||
import { vi } from "vitest";
|
||||
|
||||
export const MockEvents: Event[] = [
|
||||
export const MockEvents = [
|
||||
{
|
||||
blockNumber: 1,
|
||||
blockHash: "0x8",
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { ValidDeposit } from "../ValidDeposit";
|
||||
import { NetworkEnum } from "@/model/NetworkEnum";
|
||||
|
||||
export const MockValidDeposits: ValidDeposit[] = [
|
||||
{
|
||||
@ -7,6 +8,7 @@ export const MockValidDeposits: ValidDeposit[] = [
|
||||
remaining: 70,
|
||||
seller: "mockedSellerAddress",
|
||||
pixKey: "123456789",
|
||||
network: NetworkEnum.sepolia,
|
||||
},
|
||||
{
|
||||
blockNumber: 2,
|
||||
@ -14,6 +16,7 @@ export const MockValidDeposits: ValidDeposit[] = [
|
||||
remaining: 200,
|
||||
seller: "mockedSellerAddress",
|
||||
pixKey: "123456789",
|
||||
network: NetworkEnum.sepolia,
|
||||
},
|
||||
{
|
||||
blockNumber: 3,
|
||||
@ -21,6 +24,7 @@ export const MockValidDeposits: ValidDeposit[] = [
|
||||
remaining: 1250,
|
||||
seller: "mockedSellerAddress",
|
||||
pixKey: "123456789",
|
||||
network: NetworkEnum.sepolia,
|
||||
},
|
||||
{
|
||||
blockNumber: 4,
|
||||
@ -28,6 +32,7 @@ export const MockValidDeposits: ValidDeposit[] = [
|
||||
remaining: 4000,
|
||||
seller: "mockedSellerAddress",
|
||||
pixKey: "123456789",
|
||||
network: NetworkEnum.sepolia,
|
||||
},
|
||||
{
|
||||
blockNumber: 5,
|
||||
@ -35,5 +40,6 @@ export const MockValidDeposits: ValidDeposit[] = [
|
||||
remaining: 2000,
|
||||
seller: "mockedSellerAddress",
|
||||
pixKey: "123456789",
|
||||
network: NetworkEnum.sepolia,
|
||||
},
|
||||
];
|
||||
|
@ -1,14 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
import axios from "axios";
|
||||
|
||||
const defaultConfig = {
|
||||
"Content-Type": "application/json",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
};
|
||||
|
||||
const api = axios.create({
|
||||
...defaultConfig,
|
||||
baseURL: import.meta.env.VITE_API_URL,
|
||||
});
|
||||
|
||||
export default api;
|
@ -1,5 +1,6 @@
|
||||
import { NetworkEnum, TokenEnum } from "../model/NetworkEnum";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
import type { Participant } from "../utils/bbPay";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useEtherStore = defineStore("ether", {
|
||||
@ -13,6 +14,8 @@ export const useEtherStore = defineStore("ether", {
|
||||
depositsValidList: [] as ValidDeposit[],
|
||||
loadingWalletTransactions: false,
|
||||
loadingNetworkLiquidity: false,
|
||||
seller: {} as Participant,
|
||||
sellerId: "",
|
||||
}),
|
||||
actions: {
|
||||
setWalletAddress(walletAddress: string) {
|
||||
@ -42,6 +45,12 @@ export const useEtherStore = defineStore("ether", {
|
||||
setLoadingNetworkLiquidity(isLoadingNetworkLiquidity: boolean) {
|
||||
this.loadingNetworkLiquidity = isLoadingNetworkLiquidity;
|
||||
},
|
||||
setSeller(seller: Participant) {
|
||||
this.seller = seller;
|
||||
},
|
||||
setSellerId(sellerId: string) {
|
||||
this.sellerId = sellerId;
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
getValidDepositByWalletAddress: (state) => {
|
||||
|
57
src/utils/bbPay.ts
Normal file
57
src/utils/bbPay.ts
Normal file
@ -0,0 +1,57 @@
|
||||
export interface Participant {
|
||||
offer: string;
|
||||
fullName: string;
|
||||
identification: string;
|
||||
bankIspb?: string;
|
||||
accountType: string;
|
||||
account: string;
|
||||
branch: string;
|
||||
savingsVariation?: string;
|
||||
}
|
||||
|
||||
export interface ParticipantWithID extends Participant {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Offer {
|
||||
amount: number;
|
||||
lockId: string;
|
||||
sellerId: string;
|
||||
}
|
||||
|
||||
// Specs for BB Pay Sandbox
|
||||
// https://apoio.developers.bb.com.br/sandbox/spec/665797498bb48200130fc32c
|
||||
|
||||
export const createParticipant = async (participant: Participant) => {
|
||||
const response = await fetch(`${process.env.VUE_APP_API_URL}/participants`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(participant),
|
||||
});
|
||||
const data = await response.json();
|
||||
return { ...participant, id: data.id } as ParticipantWithID;
|
||||
};
|
||||
|
||||
export const createSolicitation = async (offer: Offer) => {
|
||||
const response = await fetch(`${process.env.VUE_APP_API_URL}/solicitation`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(offer),
|
||||
});
|
||||
return response.json();
|
||||
};
|
||||
|
||||
export const getSolicitation = async (id: string) => {
|
||||
const response = await fetch(
|
||||
`${process.env.VUE_APP_API_URL}/solicitation/${id}`
|
||||
);
|
||||
|
||||
const obj: any = response.json();
|
||||
|
||||
return {
|
||||
id: obj.numeroSolicitacao,
|
||||
lockId: obj.codigoConciliacaoSolicitacao,
|
||||
amount: obj.valorSolicitacao,
|
||||
qrcode: obj.pix.textoQrCode,
|
||||
status: obj.valorSomatorioPagamentosEfetivados >= obj.valorSolicitacao,
|
||||
signature: obj.assinatura,
|
||||
};
|
||||
};
|
2142
src/utils/files/isbpList.json
Normal file
2142
src/utils/files/isbpList.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,7 @@ import { getNetworksLiquidity } from "@/blockchain/events";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
import { getUnreleasedLockById } from "@/blockchain/events";
|
||||
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
|
||||
import { getSolicitation } from "@/utils/bbPay";
|
||||
|
||||
enum Step {
|
||||
Search,
|
||||
@ -59,18 +60,15 @@ const confirmBuyClick = async (
|
||||
}
|
||||
};
|
||||
|
||||
const releaseTransaction = async (e2eId: string) => {
|
||||
const releaseTransaction = async (lockId: string) => {
|
||||
flowStep.value = Step.List;
|
||||
showBuyAlert.value = true;
|
||||
loadingRelease.value = true;
|
||||
|
||||
if (lockID.value && tokenAmount.value && pixTarget.value) {
|
||||
const release = await releaseLock(
|
||||
pixTarget.value,
|
||||
tokenAmount.value,
|
||||
e2eId,
|
||||
lockID.value
|
||||
);
|
||||
const solicitation = await getSolicitation(lockId);
|
||||
|
||||
if (solicitation.status) {
|
||||
const release = await releaseLock(solicitation);
|
||||
await release.wait();
|
||||
|
||||
await updateWalletStatus();
|
||||
@ -140,8 +138,8 @@ onMounted(async () => {
|
||||
/>
|
||||
<div v-if="flowStep == Step.Buy">
|
||||
<QrCodeComponent
|
||||
:pixTarget="String(pixTarget)"
|
||||
:tokenValue="tokenAmount"
|
||||
:sellerId="String(pixTarget)"
|
||||
:amount="tokenAmount"
|
||||
@pix-validated="releaseTransaction"
|
||||
v-if="!loadingLock"
|
||||
/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import WantSellComponent from "@/components/SellerSteps/WantSellComponent.vue";
|
||||
import SellerComponent from "@/components/SellerSteps/SellerComponent.vue";
|
||||
import SendNetwork from "@/components/SellerSteps/SendNetwork.vue";
|
||||
import LoadingComponent from "@/components/LoadingComponent/LoadingComponent.vue";
|
||||
import { approveTokens, addDeposit } from "@/blockchain/sellerMethods";
|
||||
@ -7,6 +7,7 @@ import { approveTokens, addDeposit } from "@/blockchain/sellerMethods";
|
||||
import { ref } from "vue";
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
|
||||
import type { Participant } from "@/utils/bbPay";
|
||||
|
||||
enum Step {
|
||||
Search,
|
||||
@ -20,20 +21,13 @@ etherStore.setSellerView(true);
|
||||
const flowStep = ref<Step>(Step.Sell);
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const offerValue = ref<string>("");
|
||||
const pixKeyBuyer = ref<string>("");
|
||||
const showAlert = ref<boolean>(false);
|
||||
|
||||
// Verificar tipagem
|
||||
const approveOffer = async (args: {
|
||||
offer: string;
|
||||
postProcessedPixKey: string;
|
||||
}) => {
|
||||
const approveOffer = async (args: Participant) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
offerValue.value = args.offer;
|
||||
pixKeyBuyer.value = args.postProcessedPixKey;
|
||||
await approveTokens(args.offer);
|
||||
await approveTokens(args);
|
||||
flowStep.value = Step.Network;
|
||||
loading.value = false;
|
||||
} catch (err) {
|
||||
@ -46,8 +40,8 @@ const approveOffer = async (args: {
|
||||
const sendNetwork = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (offerValue.value && pixKeyBuyer.value) {
|
||||
await addDeposit(String(offerValue.value), pixKeyBuyer.value);
|
||||
if (etherStore.seller) {
|
||||
await addDeposit();
|
||||
flowStep.value = Step.Sell;
|
||||
loading.value = false;
|
||||
showAlert.value = true;
|
||||
@ -63,7 +57,7 @@ const sendNetwork = async () => {
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="flowStep == Step.Sell">
|
||||
<WantSellComponent v-if="!loading" @approve-tokens="approveOffer" />
|
||||
<SellerComponent v-if="!loading" @approve-tokens="approveOffer" />
|
||||
<LoadingComponent
|
||||
v-if="loading"
|
||||
:message="'A transação está sendo enviada para a rede.'"
|
||||
@ -76,8 +70,8 @@ const sendNetwork = async () => {
|
||||
/>
|
||||
<div v-if="flowStep == Step.Network">
|
||||
<SendNetwork
|
||||
:pixKey="pixKeyBuyer"
|
||||
:offer="Number(offerValue)"
|
||||
:sellerId="etherStore.sellerId"
|
||||
:offer="Number(etherStore.seller.offer)"
|
||||
:selected-token="etherStore.selectedToken"
|
||||
v-if="!loading"
|
||||
@send-network="sendNetwork"
|
||||
|
@ -3,7 +3,8 @@
|
||||
"include": [
|
||||
"env.d.ts",
|
||||
"src/**/*",
|
||||
"src/**/*.vue"
|
||||
"src/**/*.vue",
|
||||
"scripts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
@ -24,6 +25,9 @@
|
||||
"esnext",
|
||||
"dom"
|
||||
],
|
||||
"preserveValueImports": false,
|
||||
"importsNotUsedAsValues": "remove",
|
||||
"verbatimModuleSyntax": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
|
@ -10,6 +10,17 @@ export default defineConfig({
|
||||
build: {
|
||||
target: "esnext",
|
||||
},
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
target: "esnext",
|
||||
define: {
|
||||
global: "globalThis",
|
||||
},
|
||||
supported: {
|
||||
bigint: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
|
198
yarn.lock
198
yarn.lock
@ -242,11 +242,21 @@
|
||||
resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz"
|
||||
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
|
||||
|
||||
"@babel/helper-string-parser@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
|
||||
integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
|
||||
version "7.19.1"
|
||||
resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz"
|
||||
integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.25.9":
|
||||
version "7.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
|
||||
integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
|
||||
|
||||
"@babel/helper-validator-option@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz"
|
||||
@ -290,6 +300,13 @@
|
||||
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz"
|
||||
integrity sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==
|
||||
|
||||
"@babel/parser@^7.25.3":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5"
|
||||
integrity sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==
|
||||
dependencies:
|
||||
"@babel/types" "^7.26.9"
|
||||
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz"
|
||||
@ -963,6 +980,14 @@
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.26.9":
|
||||
version "7.26.9"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.9.tgz#08b43dec79ee8e682c2ac631c010bdcac54a21ce"
|
||||
integrity sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.25.9"
|
||||
"@babel/helper-validator-identifier" "^7.25.9"
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
|
||||
@ -1973,50 +1998,26 @@
|
||||
picocolors "^1.0.0"
|
||||
pretty-format "^27.5.1"
|
||||
|
||||
"@volar/language-core@1.0.9":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.npmjs.org/@volar/language-core/-/language-core-1.0.9.tgz"
|
||||
integrity sha512-5Fty3slLet6svXiJw2YxhYeo6c7wFdtILrql5bZymYLM+HbiZtJbryW1YnUEKAP7MO9Mbeh+TNH4Z0HFxHgIqw==
|
||||
"@volar/language-core@2.4.11", "@volar/language-core@~2.4.11":
|
||||
version "2.4.11"
|
||||
resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.4.11.tgz#d95a9ec4f14fbdb41a6a64f9f321d11d23a5291c"
|
||||
integrity sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==
|
||||
dependencies:
|
||||
"@volar/source-map" "1.0.9"
|
||||
"@vue/reactivity" "^3.2.40"
|
||||
muggle-string "^0.1.0"
|
||||
"@volar/source-map" "2.4.11"
|
||||
|
||||
"@volar/source-map@1.0.9":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.npmjs.org/@volar/source-map/-/source-map-1.0.9.tgz"
|
||||
integrity sha512-fazB/vy5ZEJ3yKx4fabJyGNI3CBkdLkfEIRVu6+1P3VixK0Mn+eqyUIkLBrzGYaeFM3GybhCLCvsVdNz0Fu/CQ==
|
||||
dependencies:
|
||||
muggle-string "^0.1.0"
|
||||
"@volar/source-map@2.4.11":
|
||||
version "2.4.11"
|
||||
resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.4.11.tgz#5876d4531508129724c2755e295db1df98bd5895"
|
||||
integrity sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==
|
||||
|
||||
"@volar/typescript@1.0.9":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.npmjs.org/@volar/typescript/-/typescript-1.0.9.tgz"
|
||||
integrity sha512-dVziu+ShQUWuMukM6bvK2v2O446/gG6l1XkTh2vfkccw1IzjfbiP1TWQoNo1ipTfZOtu5YJGYAx+o5HNrGXWfQ==
|
||||
"@volar/typescript@~2.4.11":
|
||||
version "2.4.11"
|
||||
resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.4.11.tgz#aafbfa413337654db211bf4d8fb6670c89f6fa57"
|
||||
integrity sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==
|
||||
dependencies:
|
||||
"@volar/language-core" "1.0.9"
|
||||
|
||||
"@volar/vue-language-core@1.0.9":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.npmjs.org/@volar/vue-language-core/-/vue-language-core-1.0.9.tgz"
|
||||
integrity sha512-tofNoR8ShPFenHT1YVMuvoXtXWwoQE+fiXVqSmW0dSKZqEDjWQ3YeXSd0a6aqyKaIbvR7kWWGp34WbpQlwf9Ww==
|
||||
dependencies:
|
||||
"@volar/language-core" "1.0.9"
|
||||
"@volar/source-map" "1.0.9"
|
||||
"@vue/compiler-dom" "^3.2.40"
|
||||
"@vue/compiler-sfc" "^3.2.40"
|
||||
"@vue/reactivity" "^3.2.40"
|
||||
"@vue/shared" "^3.2.40"
|
||||
minimatch "^5.1.0"
|
||||
vue-template-compiler "^2.7.10"
|
||||
|
||||
"@volar/vue-typescript@1.0.9":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.npmjs.org/@volar/vue-typescript/-/vue-typescript-1.0.9.tgz"
|
||||
integrity sha512-ZLe4y9YNbviACa7uAMCilzxA76gbbSlKfjspXBzk6fCobd8QCIig+VyDYcjANIlm2HhgSCX8jYTzhCKlegh4mw==
|
||||
dependencies:
|
||||
"@volar/typescript" "1.0.9"
|
||||
"@volar/vue-language-core" "1.0.9"
|
||||
"@volar/language-core" "2.4.11"
|
||||
path-browserify "^1.0.1"
|
||||
vscode-uri "^3.0.8"
|
||||
|
||||
"@vue/babel-helper-vue-transform-on@^1.0.2":
|
||||
version "1.0.2"
|
||||
@ -2048,7 +2049,18 @@
|
||||
estree-walker "^2.0.2"
|
||||
source-map "^0.6.1"
|
||||
|
||||
"@vue/compiler-dom@3.2.41", "@vue/compiler-dom@^3.2.40":
|
||||
"@vue/compiler-core@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.13.tgz#b0ae6c4347f60c03e849a05d34e5bf747c9bda05"
|
||||
integrity sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.25.3"
|
||||
"@vue/shared" "3.5.13"
|
||||
entities "^4.5.0"
|
||||
estree-walker "^2.0.2"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
"@vue/compiler-dom@3.2.41":
|
||||
version "3.2.41"
|
||||
resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.41.tgz"
|
||||
integrity sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==
|
||||
@ -2056,6 +2068,14 @@
|
||||
"@vue/compiler-core" "3.2.41"
|
||||
"@vue/shared" "3.2.41"
|
||||
|
||||
"@vue/compiler-dom@^3.5.0":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz#bb1b8758dbc542b3658dda973b98a1c9311a8a58"
|
||||
integrity sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==
|
||||
dependencies:
|
||||
"@vue/compiler-core" "3.5.13"
|
||||
"@vue/shared" "3.5.13"
|
||||
|
||||
"@vue/compiler-sfc@2.7.14":
|
||||
version "2.7.14"
|
||||
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.14.tgz"
|
||||
@ -2065,7 +2085,7 @@
|
||||
postcss "^8.4.14"
|
||||
source-map "^0.6.1"
|
||||
|
||||
"@vue/compiler-sfc@3.2.41", "@vue/compiler-sfc@^3.2.40":
|
||||
"@vue/compiler-sfc@3.2.41":
|
||||
version "3.2.41"
|
||||
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.41.tgz"
|
||||
integrity sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==
|
||||
@ -2089,6 +2109,14 @@
|
||||
"@vue/compiler-dom" "3.2.41"
|
||||
"@vue/shared" "3.2.41"
|
||||
|
||||
"@vue/compiler-vue2@^2.7.16":
|
||||
version "2.7.16"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz#2ba837cbd3f1b33c2bc865fbe1a3b53fb611e249"
|
||||
integrity sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==
|
||||
dependencies:
|
||||
de-indent "^1.0.2"
|
||||
he "^1.2.0"
|
||||
|
||||
"@vue/devtools-api@^6.4.4", "@vue/devtools-api@^6.4.5":
|
||||
version "6.4.5"
|
||||
resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.4.5.tgz"
|
||||
@ -2111,6 +2139,20 @@
|
||||
"@typescript-eslint/parser" "^5.0.0"
|
||||
vue-eslint-parser "^9.0.0"
|
||||
|
||||
"@vue/language-core@2.2.8":
|
||||
version "2.2.8"
|
||||
resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-2.2.8.tgz#05befa390399fbd4409bc703ee0520b8ac1b7088"
|
||||
integrity sha512-rrzB0wPGBvcwaSNRriVWdNAbHQWSf0NlGqgKHK5mEkXpefjUlVRP62u03KvwZpvKVjRnBIQ/Lwre+Mx9N6juUQ==
|
||||
dependencies:
|
||||
"@volar/language-core" "~2.4.11"
|
||||
"@vue/compiler-dom" "^3.5.0"
|
||||
"@vue/compiler-vue2" "^2.7.16"
|
||||
"@vue/shared" "^3.5.0"
|
||||
alien-signals "^1.0.3"
|
||||
minimatch "^9.0.3"
|
||||
muggle-string "^0.4.1"
|
||||
path-browserify "^1.0.1"
|
||||
|
||||
"@vue/reactivity-transform@3.2.41":
|
||||
version "3.2.41"
|
||||
resolved "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.41.tgz"
|
||||
@ -2122,7 +2164,7 @@
|
||||
estree-walker "^2.0.2"
|
||||
magic-string "^0.25.7"
|
||||
|
||||
"@vue/reactivity@3.2.41", "@vue/reactivity@^3.2.40":
|
||||
"@vue/reactivity@3.2.41":
|
||||
version "3.2.41"
|
||||
resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.41.tgz"
|
||||
integrity sha512-9JvCnlj8uc5xRiQGZ28MKGjuCoPhhTwcoAdv3o31+cfGgonwdPNuvqAXLhlzu4zwqavFEG5tvaoINQEfxz+l6g==
|
||||
@ -2154,11 +2196,16 @@
|
||||
"@vue/compiler-ssr" "3.2.41"
|
||||
"@vue/shared" "3.2.41"
|
||||
|
||||
"@vue/shared@3.2.41", "@vue/shared@^3.2.40":
|
||||
"@vue/shared@3.2.41":
|
||||
version "3.2.41"
|
||||
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.41.tgz"
|
||||
integrity sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==
|
||||
|
||||
"@vue/shared@3.5.13", "@vue/shared@^3.5.0":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.13.tgz#87b309a6379c22b926e696893237826f64339b6f"
|
||||
integrity sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==
|
||||
|
||||
"@vue/test-utils@^2.2.7":
|
||||
version "2.2.7"
|
||||
resolved "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.2.7.tgz"
|
||||
@ -2376,6 +2423,11 @@ alchemy-sdk@^2.3.0:
|
||||
sturdy-websocket "^0.2.1"
|
||||
websocket "^1.0.34"
|
||||
|
||||
alien-signals@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/alien-signals/-/alien-signals-1.0.4.tgz#c696a5dc9963fc648ae97093411d7e74b0a81ac0"
|
||||
integrity sha512-DJqqQD3XcsaQcQ1s+iE2jDUZmmQpXwHiR6fCAim/w87luaW+vmLY8fMlrdkmRwzaFXhkxf3rqPCR59tKVv1MDw==
|
||||
|
||||
ansi-regex@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
|
||||
@ -3125,7 +3177,7 @@ encode-utf8@^1.0.3:
|
||||
resolved "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz"
|
||||
integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==
|
||||
|
||||
entities@^4.2.0:
|
||||
entities@^4.2.0, entities@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
|
||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||
@ -4615,10 +4667,10 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimatch@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz"
|
||||
integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==
|
||||
minimatch@^9.0.3:
|
||||
version "9.0.5"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
|
||||
integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
|
||||
dependencies:
|
||||
brace-expansion "^2.0.1"
|
||||
|
||||
@ -4652,10 +4704,10 @@ ms@2.1.2:
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
muggle-string@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmjs.org/muggle-string/-/muggle-string-0.1.0.tgz"
|
||||
integrity sha512-Tr1knR3d2mKvvWthlk7202rywKbiOm4rVFLsfAaSIhJ6dt9o47W4S+JMtWhd/PW9Wrdew2/S2fSvhz3E2gkfEg==
|
||||
muggle-string@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/muggle-string/-/muggle-string-0.4.1.tgz#3b366bd43b32f809dc20659534dd30e7c8a0d328"
|
||||
integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==
|
||||
|
||||
nanoid@^3.3.1:
|
||||
version "3.3.7"
|
||||
@ -4862,6 +4914,11 @@ parse5@^7.1.1:
|
||||
dependencies:
|
||||
entities "^4.4.0"
|
||||
|
||||
path-browserify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
|
||||
integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
|
||||
|
||||
path-exists@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
|
||||
@ -5374,7 +5431,7 @@ slice-ansi@^5.0.0:
|
||||
ansi-styles "^6.0.0"
|
||||
is-fullwidth-code-point "^4.0.0"
|
||||
|
||||
source-map-js@^1.0.1:
|
||||
source-map-js@^1.0.1, source-map-js@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
|
||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||
@ -5757,10 +5814,10 @@ typedarray-to-buffer@^3.1.5:
|
||||
dependencies:
|
||||
is-typedarray "^1.0.0"
|
||||
|
||||
typescript@~4.7.4:
|
||||
version "4.7.4"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz"
|
||||
integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
|
||||
typescript@~5.8.2:
|
||||
version "5.8.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4"
|
||||
integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==
|
||||
|
||||
uc.micro@^1.0.1:
|
||||
version "1.0.6"
|
||||
@ -6015,6 +6072,11 @@ vitest@^0.28.1:
|
||||
vite-node "0.28.1"
|
||||
why-is-node-running "^2.2.2"
|
||||
|
||||
vscode-uri@^3.0.8:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c"
|
||||
integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==
|
||||
|
||||
vue-demi@*, vue-demi@^0.13.11:
|
||||
version "0.13.11"
|
||||
resolved "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz"
|
||||
@ -6064,21 +6126,13 @@ vue-router@^4.1.5:
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.4.5"
|
||||
|
||||
vue-template-compiler@^2.7.10:
|
||||
version "2.7.13"
|
||||
resolved "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.13.tgz"
|
||||
integrity sha512-jYM6TClwDS9YqP48gYrtAtaOhRKkbYmbzE+Q51gX5YDr777n7tNI/IZk4QV4l/PjQPNh/FVa/E92sh/RqKMrog==
|
||||
vue-tsc@^2.2.8:
|
||||
version "2.2.8"
|
||||
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-2.2.8.tgz#7c8e1bd9333d25241a7f9988eedf08c65483158c"
|
||||
integrity sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ==
|
||||
dependencies:
|
||||
de-indent "^1.0.2"
|
||||
he "^1.2.0"
|
||||
|
||||
vue-tsc@^1.0.8:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.0.9.tgz"
|
||||
integrity sha512-vRmHD1K6DmBymNhoHjQy/aYKTRQNLGOu2/ESasChG9Vy113K6CdP0NlhR0bzgFJfv2eFB9Ez/9L5kIciUajBxQ==
|
||||
dependencies:
|
||||
"@volar/vue-language-core" "1.0.9"
|
||||
"@volar/vue-typescript" "1.0.9"
|
||||
"@volar/typescript" "~2.4.11"
|
||||
"@vue/language-core" "2.2.8"
|
||||
|
||||
vue@^2.5.16:
|
||||
version "2.7.14"
|
||||
|
Loading…
x
Reference in New Issue
Block a user