Correct bugs and adjust Buyer form.

This commit is contained in:
Filipe Soccol 2024-12-03 16:18:10 -03:00
parent c90f468d3c
commit 0f17a67e00
9 changed files with 113 additions and 59 deletions

View File

@ -1,28 +1,22 @@
import { getContract, getProvider } from "./provider"; import { getContract, getProvider } from "./provider";
import { getP2PixAddress, getTokenAddress } from "./addresses"; import { getP2PixAddress, getTokenAddress } from "./addresses";
import { encodeBytes32String, Signature, Contract, parseEther } from "ethers";
import p2pix from "@/utils/smart_contract_files/P2PIX.json"; 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 type { TokenEnum } from "@/model/NetworkEnum";
import { createSolicitation } from "../utils/bbPay";
import type { Offer } from "../utils/bbPay";
const addLock = async ( const addLock = async (
seller: string, sellerId: string,
token: string, token: string,
amount: number amount: number
): Promise<string> => { ): Promise<string> => {
const p2pContract = await getContract(); const p2pContract = await getContract();
const lock = await p2pContract.lock( const lock = await p2pContract.lock(
seller, sellerId,
token, token,
parseEther(String(amount)), // BigNumber parseEther(String(amount)), // BigNumber
[], [],
@ -32,26 +26,29 @@ const addLock = async (
const lock_rec = await lock.wait(); const lock_rec = await lock.wait();
const [t] = lock_rec.events; 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 ( const releaseLock = async (solicitation: any): Promise<any> => {
pixKey: string, // const mockBacenSigner = new Wallet(
amount: number, // "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
e2eId: string, // );
lockId: string
): Promise<any> => {
const mockBacenSigner = new Wallet(
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
);
const messageToSign = solidityPackedKeccak256( // const messageToSign = solidityPackedKeccak256(
["bytes32", "uint256", "bytes32"], // ["bytes32", "uint256", "bytes32"],
[pixKey, parseEther(String(amount)), encodeBytes32String(e2eId)] // [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 provider = getProvider();
const sig = Signature.from(flatSig); const sig = Signature.from(flatSig);

View File

@ -5,7 +5,8 @@ import { encodeBytes32String, Contract, parseEther } from "ethers";
import mockToken from "../utils/smart_contract_files/MockToken.json"; import mockToken from "../utils/smart_contract_files/MockToken.json";
import { useEtherStore } from "@/store/ether"; import { useEtherStore } from "@/store/ether";
import { createParticipant, Participant } from "@/utils/bbPay"; import { createParticipant } from "@/utils/bbPay";
import type { Participant } from "@/utils/bbPay";
const approveTokens = async (participant: Participant): Promise<any> => { const approveTokens = async (participant: Participant): Promise<any> => {
const provider = getProvider(); const provider = getProvider();

View File

@ -1,13 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { pix } from "@/utils/QrCodePix";
import { onMounted, onUnmounted, ref } from "vue"; import { onMounted, onUnmounted, ref } from "vue";
import CustomButton from "@/components/CustomButton/CustomButton.vue"; import CustomButton from "@/components/CustomButton/CustomButton.vue";
import CustomModal from "@/components//CustomModal/CustomModal.vue"; import CustomModal from "@/components//CustomModal/CustomModal.vue";
import QRCode from "qrcode";
// props and store references // props and store references
const props = defineProps({ const props = defineProps({
sellerId: String, sellerId: String,
amount: Number, amount: Number,
qrcode: String,
}); });
const windowSize = ref<number>(window.innerWidth); const windowSize = ref<number>(window.innerWidth);

View File

@ -34,6 +34,7 @@ const tokenValue = ref<number>(0);
const enableConfirmButton = ref<boolean>(false); const enableConfirmButton = ref<boolean>(false);
const hasLiquidity = ref<boolean>(true); const hasLiquidity = ref<boolean>(true);
const validDecimals = ref<boolean>(true); const validDecimals = ref<boolean>(true);
const identification = ref<string>("");
const selectedDeposits = ref<ValidDeposit[]>(); const selectedDeposits = ref<ValidDeposit[]>();
import ChevronDown from "@/assets/chevronDown.svg"; import ChevronDown from "@/assets/chevronDown.svg";
@ -104,9 +105,17 @@ const verifyLiquidity = (): void => {
}; };
const enableOrDisableConfirmButton = (): void => { const enableOrDisableConfirmButton = (): void => {
enableConfirmButton.value = if (!selectedDeposits.value) {
!!selectedDeposits.value && enableConfirmButton.value = false;
!!selectedDeposits.value.find((d) => d.network === networkName.value); return;
}
if (!selectedDeposits.value.find((d) => d.network === networkName.value)) {
enableConfirmButton.value = false;
return;
}
enableConfirmButton.value = true;
}; };
watch(networkName, (): void => { watch(networkName, (): void => {
@ -117,6 +126,18 @@ watch(networkName, (): void => {
watch(walletAddress, (): void => { watch(walletAddress, (): void => {
verifyLiquidity(); 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> </script>
<template> <template>
@ -132,7 +153,7 @@ watch(walletAddress, (): void => {
tokens após realizar o Pix</span tokens após realizar o Pix</span
> >
</div> </div>
<div class="main-container"> <form class="main-container" @submit="handleSubmit">
<div class="backdrop-blur -z-10 w-full h-full"></div> <div class="backdrop-blur -z-10 w-full h-full"></div>
<div <div
class="flex flex-col w-full bg-white sm:px-10 px-6 py-5 rounded-lg border-y-10" class="flex flex-col w-full bg-white sm:px-10 px-6 py-5 rounded-lg border-y-10"
@ -140,14 +161,16 @@ watch(walletAddress, (): void => {
<div class="flex justify-between sm:w-full items-center"> <div class="flex justify-between sm:w-full items-center">
<input <input
type="number" type="number"
name="tokenAmount"
class="border-none outline-none text-lg text-gray-900" class="border-none outline-none text-lg text-gray-900"
v-bind:class="{ v-bind:class="{
'font-semibold': tokenValue != undefined, 'font-semibold': tokenValue != undefined,
'text-xl': tokenValue != undefined, 'text-xl': tokenValue != undefined,
}" }"
@input="debounce(handleInputEvent, 500)($event)" @input="debounce(handleInputEvent, 500)($event)"
placeholder="0 " placeholder="0"
step=".01" step=".01"
required
/> />
<div class="relative overflow-visible"> <div class="relative overflow-visible">
<button <button
@ -260,18 +283,33 @@ watch(walletAddress, (): void => {
> >
</div> </div>
</div> </div>
<CustomButton
v-if="!walletAddress" <div
:text="'Conectar carteira'" class="flex flex-col w-full bg-white sm:px-10 px-6 py-4 rounded-lg border-y-10"
@buttonClicked="connectAccount()" >
/> <input
<CustomButton type="text"
v-if="walletAddress" v-model="identification"
:text="'Confirmar compra'" maxlength="14"
:is-disabled="!enableConfirmButton" :pattern="'^\\d{11}$|^\\d{14}$'"
@buttonClicked="emitConfirmButton()" 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> </div>
<!-- Action buttons -->
<CustomButton
v-if="walletAddress"
type="submit"
text="Confirmar Oferta"
/>
<CustomButton
v-else
text="Conectar carteira"
@buttonClicked="connectAccount()"
/>
</form>
</div> </div>
</template> </template>
@ -306,4 +344,10 @@ input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button { input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none; -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> </style>

View File

@ -9,6 +9,10 @@ import { getTokenImage } from "@/utils/imagesPath";
import { useOnboard } from "@web3-onboard/vue"; import { useOnboard } from "@web3-onboard/vue";
import ChevronDown from "@/assets/chevron.svg"; 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 // Define Bank interface
interface Bank { interface Bank {
ISPB: string; ISPB: string;
@ -38,10 +42,6 @@ const bankSearchQuery = ref<string>("");
const showBankList = ref<boolean>(false); const showBankList = ref<boolean>(false);
const selectedBank = ref<Bank | null>(null); const selectedBank = ref<Bank | null>(null);
// Import the bank list
import bankList from "@/utils/files/isbpList.json";
import { Participant } from "@/utils/bbPay";
const filteredBanks = computed(() => { const filteredBanks = computed(() => {
if (!bankSearchQuery.value) return []; if (!bankSearchQuery.value) return [];
return bankList return bankList

View File

@ -1,6 +1,6 @@
import { NetworkEnum, TokenEnum } from "../model/NetworkEnum"; import { NetworkEnum, TokenEnum } from "../model/NetworkEnum";
import type { ValidDeposit } from "@/model/ValidDeposit"; import type { ValidDeposit } from "@/model/ValidDeposit";
import { Participant } from "@/utils/bbPay"; import type { Participant } from "../utils/bbPay";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
export const useEtherStore = defineStore("ether", { export const useEtherStore = defineStore("ether", {

View File

@ -15,9 +15,13 @@ export interface ParticipantWithID extends Participant {
export interface Offer { export interface Offer {
amount: number; amount: number;
sellerID: string; lockId: string;
sellerId: string;
} }
// Specs for BB Pay Sandbox
// https://apoio.developers.bb.com.br/sandbox/spec/665797498bb48200130fc32c
export const createParticipant = async (participant: Participant) => { export const createParticipant = async (participant: Participant) => {
const response = await fetch(`${process.env.VUE_APP_API_URL}/participants`, { const response = await fetch(`${process.env.VUE_APP_API_URL}/participants`, {
method: "PUT", method: "PUT",
@ -39,5 +43,15 @@ export const getSolicitation = async (id: string) => {
const response = await fetch( const response = await fetch(
`${process.env.VUE_APP_API_URL}/solicitation/${id}` `${process.env.VUE_APP_API_URL}/solicitation/${id}`
); );
return response.json();
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,
};
}; };

View File

@ -59,18 +59,15 @@ const confirmBuyClick = async (
} }
}; };
const releaseTransaction = async (e2eId: string) => { const releaseTransaction = async (lockId: string) => {
flowStep.value = Step.List; flowStep.value = Step.List;
showBuyAlert.value = true; showBuyAlert.value = true;
loadingRelease.value = true; loadingRelease.value = true;
if (lockID.value && tokenAmount.value && pixTarget.value) { const solicitation = await getSolicitation(lockId);
const release = await releaseLock(
pixTarget.value, if (solicitation.confirmed) {
tokenAmount.value, const release = await releaseLock(solicitation);
e2eId,
lockID.value
);
await release.wait(); await release.wait();
await updateWalletStatus(); await updateWalletStatus();

View File

@ -7,7 +7,7 @@ import { approveTokens, addDeposit } from "@/blockchain/sellerMethods";
import { ref } from "vue"; import { ref } from "vue";
import { useEtherStore } from "@/store/ether"; import { useEtherStore } from "@/store/ether";
import CustomAlert from "@/components/CustomAlert/CustomAlert.vue"; import CustomAlert from "@/components/CustomAlert/CustomAlert.vue";
import { Participant } from "@/utils/bbPay"; import type { Participant } from "@/utils/bbPay";
enum Step { enum Step {
Search, Search,