Merge branch 'develop' of https://github.com/liftlearning/P2Pix-Front-End into faq
This commit is contained in:
commit
80e3296131
@ -1 +1,3 @@
|
||||
VITE_API_URL=http://localhost:8000/
|
||||
VITE_GOERLI_API_URL={GOERLI_API_URL_ALCHEMY}
|
||||
VITE_MUMBAI_API_URL={MUMBAI_API_URL_ALCHEMY}
|
29
README.md
29
README.md
@ -6,9 +6,30 @@
|
||||
This application aims to create a democratic and secure solution for the purchase and sale of ERC20 tokens, through the PIX, integrating the functionalities of smart contracts (smart contracts) of the blockchain with a receipt by digital signature. Allowing the integration of national financial system transactions to public blockchains, dispensing with custody through intermediaries.
|
||||
|
||||
# Table of Contents
|
||||
* [Metamask Tutorial](#metamask-tutorial)
|
||||
* [Recommended IDE Setup](#recommended-ide-setup)
|
||||
* [Dependencies](#dependencies)
|
||||
* [Build Setup](#build-setup)
|
||||
## Metamask Tutorial
|
||||
### Installation
|
||||
|
||||
Install the Metamask extension at https://metamask.io/download/
|
||||
|
||||
### Enable Testnets on Metamask
|
||||
|
||||
Go to Settings -> Advanced -> Show Testnets
|
||||
|
||||
Now you can select the Goerli testnet.
|
||||
|
||||
### Add Polygon Mumbai to your Metamask
|
||||
|
||||
To add the Mumbai network, follow the instructions at:
|
||||
https://www.youtube.com/watch?v=Jegmru0Q0j4
|
||||
|
||||
### Import the MBRL token
|
||||
|
||||
Go to Import Tokens and paste the following address: `0x294003F602c321627152c6b7DED3EAb5bEa853Ee`
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||
@ -31,12 +52,14 @@ See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Smart Contract
|
||||
It is necessary to be running the smart contract locally to have access to all the functionalities of the application. The smart contract repository and instructions on how to run it can be found at [https://github.com/doiim/p2pix-smart-contracts](https://github.com/doiim/p2pix-smart-contracts)
|
||||
|
||||
### API
|
||||
For full operation of the application, it is necessary to correctly configure the variable that points to the api in the .env file, in the repository there is an .env.example file, just rename it to just .env and modify the variable `VITE_API_URL`. The api can be run locally see [https://github.com/liftlearning/Pix-Explorer-Back-End](https://github.com/liftlearning/Pix-Explorer-Back-End), or it can be pointed to just her staging address: [https://p2pix-block-explorer-api-staging.vercel.app/](https://p2pix-block-explorer-api-staging.vercel.app/)
|
||||
|
||||
### Alchemy Keys
|
||||
In the .env file, set `VITE_GOERLI_API_URL=https://eth-goerli.g.alchemy.com/v2/Zu9m4b2U_EzVU_zd-vgZDOleY8OF1DNP` and `VITE_MUMBAI_API_URL=https://polygon-mumbai.g.alchemy.com/v2/ZANeCqfj6VsXGpOH6gWAP6SIVIgD9Pwv`
|
||||
|
||||
You can also replace it with your own Alchemy Keys if you have one.
|
||||
|
||||
## Build Setup
|
||||
|
||||
The application can be tested by its trial version [https://p2pix-staging.vercel.app/](https://p2pix-staging.vercel.app/), the only requirement is to be running the smart contract of local way. To run the application locally, there are two different ways:
|
||||
|
10686
package-lock.json
generated
10686
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@
|
||||
"dependencies": {
|
||||
"@headlessui/vue": "^1.7.3",
|
||||
"@heroicons/vue": "^2.0.12",
|
||||
"alchemy-sdk": "^2.3.0",
|
||||
"axios": "^1.2.1",
|
||||
"crc": "^3.8.0",
|
||||
"marked": "^4.2.12",
|
||||
|
64
src/blockchain/addresses.ts
Normal file
64
src/blockchain/addresses.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { NetworkEnum } from "@/model/NetworkEnum";
|
||||
|
||||
const getTokenAddress = (): string => {
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const possibleTokenAddresses: { [key: string]: string } = {
|
||||
Ethereum: "0x294003F602c321627152c6b7DED3EAb5bEa853Ee",
|
||||
Polygon: "0x294003F602c321627152c6b7DED3EAb5bEa853Ee",
|
||||
};
|
||||
|
||||
return possibleTokenAddresses[etherStore.networkName];
|
||||
};
|
||||
|
||||
const getP2PixAddress = (): string => {
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const possibleP2PixAddresses: { [key: string]: string } = {
|
||||
Ethereum: "0x5f3EFA9A90532914545CEf527C530658af87e196",
|
||||
Polygon: "0x5f3EFA9A90532914545CEf527C530658af87e196",
|
||||
};
|
||||
|
||||
return possibleP2PixAddresses[etherStore.networkName];
|
||||
};
|
||||
|
||||
const getProviderUrl = (): string => {
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const possibleProvidersUrls: { [key: string]: string } = {
|
||||
Ethereum: import.meta.env.VITE_GOERLI_API_URL,
|
||||
Polygon: import.meta.env.VITE_MUMBAI_API_URL,
|
||||
};
|
||||
|
||||
return possibleProvidersUrls[etherStore.networkName];
|
||||
};
|
||||
|
||||
const possibleChains: { [key: string]: NetworkEnum } = {
|
||||
"0x5": NetworkEnum.ethereum,
|
||||
"5": NetworkEnum.ethereum,
|
||||
"0x13881": NetworkEnum.polygon,
|
||||
"80001": NetworkEnum.polygon,
|
||||
};
|
||||
|
||||
const network2Chain: { [key: string]: string } = {
|
||||
Ethereum: "0x5",
|
||||
Polygon: "0x13881",
|
||||
Localhost: "0x7a69",
|
||||
};
|
||||
|
||||
const isPossibleNetwork = (networkChain: string): boolean => {
|
||||
if (Object.keys(possibleChains).includes(networkChain)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
export {
|
||||
getTokenAddress,
|
||||
getProviderUrl,
|
||||
possibleChains,
|
||||
network2Chain,
|
||||
isPossibleNetwork,
|
||||
getP2PixAddress,
|
||||
};
|
94
src/blockchain/buyerMethods.ts
Normal file
94
src/blockchain/buyerMethods.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
|
||||
import { getContract, getProvider } from "./provider";
|
||||
import { getP2PixAddress } from "./addresses";
|
||||
|
||||
import p2pix from "../utils/smart_contract_files/P2PIX.json";
|
||||
|
||||
import { BigNumber, ethers } from "ethers";
|
||||
import { parseEther } from "ethers/lib/utils";
|
||||
|
||||
const addLock = async (
|
||||
depositId: BigNumber,
|
||||
amount: number
|
||||
): Promise<string> => {
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const p2pContract = getContract();
|
||||
|
||||
const lock = await p2pContract.lock(
|
||||
depositId, // BigNumber
|
||||
etherStore.walletAddress, // String "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (Example)
|
||||
ethers.constants.AddressZero, // String "0x0000000000000000000000000000000000000000"
|
||||
0,
|
||||
parseEther(String(amount)), // BigNumber
|
||||
[],
|
||||
[]
|
||||
);
|
||||
|
||||
const lock_rec = await lock.wait();
|
||||
const [t] = lock_rec.events;
|
||||
|
||||
return t.args.lockID;
|
||||
};
|
||||
|
||||
const releaseLock = async (
|
||||
pixKey: string,
|
||||
amount: number,
|
||||
e2eId: string,
|
||||
lockId: string
|
||||
): Promise<any> => {
|
||||
const mockBacenSigner = new ethers.Wallet(
|
||||
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
||||
);
|
||||
|
||||
const messageToSign = ethers.utils.solidityKeccak256(
|
||||
["string", "uint256", "bytes32"],
|
||||
[
|
||||
pixKey,
|
||||
parseEther(String(amount)),
|
||||
ethers.utils.formatBytes32String(e2eId),
|
||||
]
|
||||
);
|
||||
|
||||
const messageHashBytes = ethers.utils.arrayify(messageToSign);
|
||||
const flatSig = await mockBacenSigner.signMessage(messageHashBytes);
|
||||
const provider = getProvider();
|
||||
|
||||
const sig = ethers.utils.splitSignature(flatSig);
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(getP2PixAddress(), p2pix.abi, signer);
|
||||
|
||||
const release = await p2pContract.release(
|
||||
lockId,
|
||||
ethers.constants.AddressZero,
|
||||
ethers.utils.formatBytes32String(e2eId),
|
||||
sig.r,
|
||||
sig.s,
|
||||
sig.v
|
||||
);
|
||||
await release.wait();
|
||||
|
||||
return release;
|
||||
};
|
||||
|
||||
const cancelDeposit = async (depositId: BigNumber): Promise<any> => {
|
||||
const contract = getContract();
|
||||
|
||||
const cancel = await contract.cancelDeposit(depositId);
|
||||
await cancel.wait();
|
||||
|
||||
return cancel;
|
||||
};
|
||||
|
||||
const withdrawDeposit = async (depositId: BigNumber): Promise<any> => {
|
||||
const contract = getContract();
|
||||
|
||||
const withdraw = await contract.withdraw(depositId, []);
|
||||
await withdraw.wait();
|
||||
|
||||
return withdraw;
|
||||
};
|
||||
|
||||
export { cancelDeposit, withdrawDeposit, addLock, releaseLock };
|
84
src/blockchain/events.ts
Normal file
84
src/blockchain/events.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { Contract, ethers } from "ethers";
|
||||
|
||||
import p2pix from "../utils/smart_contract_files/P2PIX.json";
|
||||
import { formatEther } from "ethers/lib/utils";
|
||||
import { getContract } from "./provider";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
|
||||
const getNetworksLiquidity = async (): Promise<void> => {
|
||||
const etherStore = useEtherStore();
|
||||
console.log("Loading events");
|
||||
|
||||
const goerliProvider = new ethers.providers.JsonRpcProvider(
|
||||
import.meta.env.VITE_GOERLI_API_URL,
|
||||
5
|
||||
); // goerli provider
|
||||
const mumbaiProvider = new ethers.providers.JsonRpcProvider(
|
||||
import.meta.env.VITE_MUMBAI_API_URL,
|
||||
80001
|
||||
); // mumbai provider
|
||||
|
||||
const p2pContractGoerli = new ethers.Contract(
|
||||
"0x5f3EFA9A90532914545CEf527C530658af87e196",
|
||||
p2pix.abi,
|
||||
goerliProvider
|
||||
);
|
||||
const p2pContractMumbai = new ethers.Contract(
|
||||
"0x5f3EFA9A90532914545CEf527C530658af87e196",
|
||||
p2pix.abi,
|
||||
mumbaiProvider
|
||||
);
|
||||
|
||||
const depositListGoerli = await getValidDeposits(p2pContractGoerli);
|
||||
|
||||
const depositListMumbai = await getValidDeposits(p2pContractMumbai);
|
||||
|
||||
etherStore.setDepositsValidListGoerli(depositListGoerli);
|
||||
console.log(depositListGoerli);
|
||||
|
||||
etherStore.setDepositsValidListMumbai(depositListMumbai);
|
||||
console.log(depositListMumbai);
|
||||
};
|
||||
|
||||
const getValidDeposits = async (
|
||||
contract?: Contract
|
||||
): Promise<ValidDeposit[]> => {
|
||||
let p2pContract: Contract;
|
||||
|
||||
if (contract) {
|
||||
p2pContract = contract;
|
||||
} else {
|
||||
p2pContract = getContract(true);
|
||||
}
|
||||
|
||||
const filterDeposits = p2pContract.filters.DepositAdded(null);
|
||||
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
|
||||
|
||||
p2pContract = getContract(); // get metamask provider contract
|
||||
|
||||
const depositList = await Promise.all(
|
||||
eventsDeposits.map(async (deposit) => {
|
||||
const mappedDeposit = await p2pContract.mapDeposits(
|
||||
deposit.args?.depositID
|
||||
);
|
||||
let validDeposit: ValidDeposit | null = null;
|
||||
|
||||
if (mappedDeposit.valid) {
|
||||
validDeposit = {
|
||||
blockNumber: deposit.blockNumber,
|
||||
depositID: deposit.args?.depositID,
|
||||
remaining: Number(formatEther(mappedDeposit.remaining)),
|
||||
seller: mappedDeposit.seller,
|
||||
pixKey: mappedDeposit.pixTarget,
|
||||
};
|
||||
}
|
||||
|
||||
return validDeposit;
|
||||
})
|
||||
);
|
||||
|
||||
return depositList.filter((deposit) => deposit) as ValidDeposit[];
|
||||
};
|
||||
|
||||
export { getValidDeposits, getNetworksLiquidity };
|
95
src/blockchain/provider.ts
Normal file
95
src/blockchain/provider.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
|
||||
import p2pix from "../utils/smart_contract_files/P2PIX.json";
|
||||
|
||||
import { updateWalletStatus } from "./wallet";
|
||||
import {
|
||||
getProviderUrl,
|
||||
isPossibleNetwork,
|
||||
possibleChains,
|
||||
network2Chain,
|
||||
getP2PixAddress,
|
||||
} from "./addresses";
|
||||
|
||||
import { ethers } from "ethers";
|
||||
|
||||
const getProvider = (
|
||||
onlyAlchemyProvider: boolean = false
|
||||
): ethers.providers.Web3Provider | ethers.providers.JsonRpcProvider => {
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
|
||||
if (!connection || onlyAlchemyProvider)
|
||||
return new ethers.providers.JsonRpcProvider(getProviderUrl()); // alchemy provider
|
||||
|
||||
return new ethers.providers.Web3Provider(connection); // metamask provider
|
||||
};
|
||||
|
||||
const getContract = (onlyAlchemyProvider: boolean = false) => {
|
||||
const provider = getProvider(onlyAlchemyProvider);
|
||||
const signer = provider.getSigner();
|
||||
return new ethers.Contract(getP2PixAddress(), p2pix.abi, signer);
|
||||
};
|
||||
|
||||
const connectProvider = async (): Promise<void> => {
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
const provider = getProvider();
|
||||
|
||||
if (!(provider instanceof ethers.providers.Web3Provider)) {
|
||||
window.alert("Please, connect to metamask extension");
|
||||
return;
|
||||
}
|
||||
|
||||
await updateWalletStatus();
|
||||
|
||||
listenToNetworkChange(connection);
|
||||
listenToWalletChange(connection);
|
||||
};
|
||||
|
||||
const listenToWalletChange = (connection: any): void => {
|
||||
connection.on("accountsChanged", async () => {
|
||||
console.log("Changed account!");
|
||||
updateWalletStatus();
|
||||
});
|
||||
};
|
||||
|
||||
const listenToNetworkChange = (connection: any) => {
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
connection.on("chainChanged", (networkChain: string) => {
|
||||
console.log("Changed network!");
|
||||
|
||||
if (isPossibleNetwork(networkChain)) {
|
||||
etherStore.setNetworkName(possibleChains[networkChain]);
|
||||
updateWalletStatus();
|
||||
} else {
|
||||
window.alert("Invalid chain!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const requestNetworkChange = async (network: string): Promise<boolean> => {
|
||||
const etherStore = useEtherStore();
|
||||
if (!etherStore.walletAddress) return true;
|
||||
|
||||
try {
|
||||
const window_ = window as any;
|
||||
await window_.ethereum.request({
|
||||
method: "wallet_switchEthereumChain",
|
||||
params: [{ chainId: network2Chain[network] }], // chainId must be in hexadecimal numbers
|
||||
});
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export {
|
||||
getProvider,
|
||||
getContract,
|
||||
connectProvider,
|
||||
listenToNetworkChange,
|
||||
requestNetworkChange,
|
||||
};
|
44
src/blockchain/sellerMethods.ts
Normal file
44
src/blockchain/sellerMethods.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { getContract, getProvider } from "./provider";
|
||||
import { getTokenAddress, getP2PixAddress } from "./addresses";
|
||||
import { parseEther } from "ethers/lib/utils";
|
||||
|
||||
import { ethers } from "ethers";
|
||||
|
||||
import mockToken from "../utils/smart_contract_files/MockToken.json";
|
||||
|
||||
const approveTokens = async (tokenQty: string): Promise<any> => {
|
||||
const provider = getProvider();
|
||||
const signer = provider.getSigner();
|
||||
|
||||
const tokenContract = new ethers.Contract(
|
||||
getTokenAddress(),
|
||||
mockToken.abi,
|
||||
signer
|
||||
);
|
||||
|
||||
const apprv = await tokenContract.approve(
|
||||
getP2PixAddress(),
|
||||
parseEther(tokenQty)
|
||||
);
|
||||
|
||||
await apprv.wait();
|
||||
console.log(apprv);
|
||||
return apprv;
|
||||
};
|
||||
|
||||
const addDeposit = async (tokenQty: string, pixKey: string): Promise<any> => {
|
||||
const p2pContract = getContract();
|
||||
|
||||
const deposit = await p2pContract.deposit(
|
||||
getTokenAddress(),
|
||||
parseEther(tokenQty),
|
||||
pixKey,
|
||||
ethers.utils.formatBytes32String("")
|
||||
);
|
||||
|
||||
await deposit.wait();
|
||||
|
||||
return deposit;
|
||||
};
|
||||
|
||||
export { approveTokens, addDeposit };
|
95
src/blockchain/wallet.ts
Normal file
95
src/blockchain/wallet.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
|
||||
import { getContract, getProvider } from "./provider";
|
||||
import { getTokenAddress, possibleChains } from "./addresses";
|
||||
|
||||
import mockToken from "../utils/smart_contract_files/MockToken.json";
|
||||
|
||||
import { ethers, type Event } from "ethers";
|
||||
import { formatEther } from "ethers/lib/utils";
|
||||
import { getValidDeposits } from "./events";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
|
||||
const updateWalletStatus = async (): Promise<void> => {
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const provider = getProvider();
|
||||
const signer = provider.getSigner();
|
||||
|
||||
const { chainId } = await provider.getNetwork();
|
||||
etherStore.setNetworkName(possibleChains[chainId]);
|
||||
|
||||
const mockTokenContract = new ethers.Contract(
|
||||
getTokenAddress(),
|
||||
mockToken.abi,
|
||||
signer
|
||||
);
|
||||
|
||||
const walletAddress = await provider.send("eth_requestAccounts", []);
|
||||
const balance = await mockTokenContract.balanceOf(walletAddress[0]);
|
||||
|
||||
etherStore.setBalance(formatEther(balance));
|
||||
etherStore.setWalletAddress(ethers.utils.getAddress(walletAddress[0]));
|
||||
};
|
||||
|
||||
const listValidDepositTransactionsByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<ValidDeposit[]> => {
|
||||
const walletDeposits = await getValidDeposits();
|
||||
|
||||
if (walletDeposits) {
|
||||
return walletDeposits
|
||||
.filter((deposit) => deposit.seller == walletAddress)
|
||||
.sort((a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
});
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
const listAllTransactionByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<Event[]> => {
|
||||
const p2pContract = getContract();
|
||||
|
||||
const filterDeposits = p2pContract.filters.DepositAdded([walletAddress]);
|
||||
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
|
||||
|
||||
const filterAddedLocks = p2pContract.filters.LockAdded([walletAddress]);
|
||||
const eventsAddedLocks = await p2pContract.queryFilter(filterAddedLocks);
|
||||
|
||||
const filterReleasedLocks = p2pContract.filters.LockReleased([walletAddress]);
|
||||
const eventsReleasedLocks = await p2pContract.queryFilter(
|
||||
filterReleasedLocks
|
||||
);
|
||||
|
||||
return [...eventsDeposits, ...eventsAddedLocks, ...eventsReleasedLocks].sort(
|
||||
(a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// get wallet's release transactions
|
||||
const listReleaseTransactionByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<Event[]> => {
|
||||
const p2pContract = getContract();
|
||||
|
||||
const filterReleasedLocks = p2pContract.filters.LockReleased([walletAddress]);
|
||||
const eventsReleasedLocks = await p2pContract.queryFilter(
|
||||
filterReleasedLocks
|
||||
);
|
||||
|
||||
return eventsReleasedLocks.sort((a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
updateWalletStatus,
|
||||
listValidDepositTransactionsByWalletAddress,
|
||||
listAllTransactionByWalletAddress,
|
||||
listReleaseTransactionByWalletAddress,
|
||||
};
|
@ -1,11 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import CustomButton from "@/components/CustomButton.vue";
|
||||
import ListingComponent from "@/components/ListingComponent.vue";
|
||||
import type { Event } from "ethers";
|
||||
|
||||
// props
|
||||
const props = defineProps<{
|
||||
lastWalletReleaseTransactions: any[];
|
||||
tokenAmount: Number | undefined;
|
||||
lastWalletReleaseTransactions: Event[];
|
||||
tokenAmount: number | undefined;
|
||||
}>();
|
||||
|
||||
// Emits
|
||||
|
@ -1,42 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import blockchain from "@/utils/blockchain";
|
||||
import { NetworkEnum } from "@/model/NetworkEnum";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { formatEther } from "@ethersproject/units";
|
||||
import type { Event } from "ethers";
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
// props
|
||||
const props = defineProps<{
|
||||
walletTransactions: any[];
|
||||
walletTransactions: (Event | ValidDeposit)[];
|
||||
isManageMode: boolean;
|
||||
}>();
|
||||
|
||||
const itemsToShow = ref<any[]>([]);
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const itemsToShow = ref<(Event | ValidDeposit)[]>([]);
|
||||
|
||||
// Methods
|
||||
const showInitialItems = () => {
|
||||
const isValidDeposit = (
|
||||
deposit: Event | ValidDeposit
|
||||
): deposit is ValidDeposit => {
|
||||
return (deposit as ValidDeposit).depositID !== undefined;
|
||||
};
|
||||
|
||||
const showInitialItems = (): void => {
|
||||
itemsToShow.value = props.walletTransactions.slice(0, 3);
|
||||
};
|
||||
|
||||
const formatEventsAmount = (amount: any) => {
|
||||
try {
|
||||
const formated = blockchain.formatBigNumber(amount);
|
||||
return formated;
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const openEtherscanUrl = (url: string) => {
|
||||
const openEtherscanUrl = (transactionHash: string): void => {
|
||||
const networkUrl =
|
||||
etherStore.networkName == NetworkEnum.ethereum
|
||||
? "goerli.etherscan.io"
|
||||
: "mumbai.polygonscan.com";
|
||||
const url = `https://${networkUrl}/tx/${transactionHash}`;
|
||||
window.open(url, "_blank");
|
||||
};
|
||||
|
||||
const loadMore = () => {
|
||||
const loadMore = (): void => {
|
||||
const itemsShowing = itemsToShow.value.length;
|
||||
itemsToShow.value?.push(
|
||||
...props.walletTransactions.slice(itemsShowing, itemsShowing + 3)
|
||||
);
|
||||
};
|
||||
|
||||
const getEventName = (event: string | undefined): string => {
|
||||
if (!event) return "Desconhecido";
|
||||
|
||||
const possibleEventName: { [key: string]: string } = {
|
||||
DepositAdded: "Oferta",
|
||||
LockAdded: "Compra",
|
||||
LockReleased: "Reserva",
|
||||
};
|
||||
|
||||
return possibleEventName[event];
|
||||
};
|
||||
|
||||
// watch props changes
|
||||
watch(props, async () => {
|
||||
watch(props, async (): Promise<void> => {
|
||||
const itemsToShowQty = itemsToShow.value.length;
|
||||
if (itemsToShowQty == 0) showInitialItems();
|
||||
else
|
||||
@ -75,11 +95,11 @@ showInitialItems();
|
||||
<div
|
||||
class="grid grid-cols-4 grid-flow-row w-full bg-white px-6 py-4 rounded-lg"
|
||||
v-for="(item, index) in itemsToShow"
|
||||
:key="item.depositID"
|
||||
:key="item.blockNumber"
|
||||
>
|
||||
<span class="last-release-info">
|
||||
{{
|
||||
item?.args ? formatEventsAmount(item?.args.amount) : item?.remaining
|
||||
isValidDeposit(item) ? item.remaining : formatEther(item.args?.amount)
|
||||
}}
|
||||
BRZ
|
||||
</span>
|
||||
@ -87,55 +107,38 @@ showInitialItems();
|
||||
<!-- TODO: change this hardcoded date -->
|
||||
<span class="last-release-info"> 20 out 2022 </span>
|
||||
|
||||
<span class="last-release-info" v-if="!props.isManageMode">
|
||||
{{ getEventName((item as Event).event) }}
|
||||
</span>
|
||||
|
||||
<div
|
||||
v-if="!props.isManageMode"
|
||||
class="flex gap-2 cursor-pointer items-center justify-self-center"
|
||||
@click="openEtherscanUrl((item as Event)?.transactionHash)"
|
||||
>
|
||||
<span class="last-release-info">Etherscan</span>
|
||||
<img alt="Redirect image" src="@/assets/redirect.svg" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="props.isManageMode"
|
||||
class="flex gap-2 cursor-pointer items-center justify-self-center"
|
||||
@click="emit('cancelDeposit', item.depositID, index)"
|
||||
@click="emit('cancelDeposit', (item as ValidDeposit).depositID, index)"
|
||||
>
|
||||
<span class="last-release-info">Cancelar</span>
|
||||
<img alt="Cancel image" src="@/assets/cancel.svg" />
|
||||
</div>
|
||||
|
||||
<span
|
||||
class="last-release-info"
|
||||
v-if="item.event == 'DepositAdded' && !props.isManageMode"
|
||||
>
|
||||
{{ "Oferta" }}
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="last-release-info"
|
||||
v-if="item.event == 'LockAdded' && !props.isManageMode"
|
||||
>
|
||||
{{ "Reserva" }}
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="last-release-info"
|
||||
v-if="item.event == 'LockReleased' && !props.isManageMode"
|
||||
>
|
||||
{{ "Compra" }}
|
||||
</span>
|
||||
|
||||
<div
|
||||
v-if="props.isManageMode"
|
||||
class="flex gap-2 cursor-pointer items-center justify-self-center"
|
||||
@click="emit('withdrawDeposit', item.depositID, index)"
|
||||
@click="
|
||||
emit('withdrawDeposit', (item as ValidDeposit).depositID, index)
|
||||
"
|
||||
>
|
||||
<span class="last-release-info">Retirar</span>
|
||||
<img alt="Cancel image" src="@/assets/withdraw.svg" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="!props.isManageMode"
|
||||
class="flex gap-2 cursor-pointer items-center justify-self-center"
|
||||
@click="
|
||||
openEtherscanUrl(`https://etherscan.io/tx/${item?.transactionHash}`)
|
||||
"
|
||||
>
|
||||
<span class="last-release-info">Etherscan</span>
|
||||
<img alt="Redirect image" src="@/assets/redirect.svg" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col justify-center items-center w-full mt-2 gap-2"
|
||||
|
@ -24,19 +24,20 @@ const pixQrCode = pix({
|
||||
pixKey: props.pixTarget ?? "",
|
||||
value: props.tokenValue,
|
||||
});
|
||||
|
||||
pixQrCode.base64QrCode().then((code: string) => {
|
||||
qrCode.value = code;
|
||||
});
|
||||
|
||||
qrCodePayload.value = pixQrCode.payload();
|
||||
|
||||
const handleInputEvent = (event: any) => {
|
||||
const handleInputEvent = async (event: any): Promise<void> => {
|
||||
const { value } = event.target;
|
||||
e2eId.value = value;
|
||||
validatePix();
|
||||
await validatePix();
|
||||
};
|
||||
|
||||
const validatePix = async () => {
|
||||
const validatePix = async (): Promise<void> => {
|
||||
if (e2eId.value == "") {
|
||||
isPixValid.value = false;
|
||||
isCodeInputEmpty.value = true;
|
||||
@ -146,7 +147,7 @@ const validatePix = async () => {
|
||||
<CustomButton
|
||||
:is-disabled="isPixValid == false"
|
||||
:text="'Enviar para a rede'"
|
||||
@button-clicked="emit('pixValidated', { e2eId })"
|
||||
@button-clicked="emit('pixValidated', e2eId)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,41 +1,61 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import CustomButton from "../components/CustomButton.vue";
|
||||
import { debounce } from "@/utils/debounce";
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { storeToRefs } from "pinia";
|
||||
import blockchain from "../utils/blockchain";
|
||||
import { connectProvider } from "@/blockchain/provider";
|
||||
import { verifyNetworkLiquidity } from "@/utils/networkLiquidity";
|
||||
import { NetworkEnum } from "@/model/NetworkEnum";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
import { decimalCount } from "@/utils/decimalCount";
|
||||
|
||||
// Store reference
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const { walletAddress, depositsValidList } = storeToRefs(etherStore);
|
||||
const {
|
||||
walletAddress,
|
||||
networkName,
|
||||
depositsValidListGoerli,
|
||||
depositsValidListMumbai,
|
||||
} = storeToRefs(etherStore);
|
||||
|
||||
// Reactive state
|
||||
const tokenValue = ref(0);
|
||||
const enableSelectButton = ref(false);
|
||||
const hasLiquidity = ref(true);
|
||||
const validDecimals = ref(true);
|
||||
const selectedDeposit = ref();
|
||||
const tokenValue = ref<number>(0);
|
||||
const enableConfirmButton = ref<boolean>(false);
|
||||
const enableWalletButton = ref<boolean>(false);
|
||||
const hasLiquidity = ref<boolean>(true);
|
||||
const validDecimals = ref<boolean>(true);
|
||||
const selectedGoerliDeposit = ref<ValidDeposit>();
|
||||
const selectedMumbaiDeposit = ref<ValidDeposit>();
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["tokenBuy"]);
|
||||
|
||||
// Blockchain methods
|
||||
const connectAccount = async () => {
|
||||
await blockchain.connectProvider();
|
||||
verifyLiquidity();
|
||||
const connectAccount = async (): Promise<void> => {
|
||||
await connectProvider();
|
||||
|
||||
enableOrDisableConfirmButton();
|
||||
};
|
||||
|
||||
const emitConfirmButton = (): void => {
|
||||
const selectedDeposit =
|
||||
networkName.value == NetworkEnum.ethereum
|
||||
? selectedGoerliDeposit.value
|
||||
: selectedMumbaiDeposit.value;
|
||||
emit("tokenBuy", selectedDeposit, tokenValue.value);
|
||||
};
|
||||
|
||||
// Debounce methods
|
||||
const handleInputEvent = (event: any) => {
|
||||
const handleInputEvent = (event: any): void => {
|
||||
const { value } = event.target;
|
||||
|
||||
tokenValue.value = Number(value);
|
||||
|
||||
if (decimalCount(tokenValue.value) > 2) {
|
||||
if (decimalCount(String(tokenValue.value)) > 2) {
|
||||
validDecimals.value = false;
|
||||
enableSelectButton.value = false;
|
||||
enableConfirmButton.value = false;
|
||||
return;
|
||||
}
|
||||
validDecimals.value = true;
|
||||
@ -43,41 +63,52 @@ const handleInputEvent = (event: any) => {
|
||||
verifyLiquidity();
|
||||
};
|
||||
|
||||
// Enable button methods
|
||||
// Check if has more than 2 decimal places
|
||||
const decimalCount = (num: Number) => {
|
||||
const numStr = String(num);
|
||||
if (numStr.includes(".")) {
|
||||
return numStr.split(".")[1].length;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Verify if there is a valid deposit to buy
|
||||
const verifyLiquidity = () => {
|
||||
enableSelectButton.value = false;
|
||||
selectedDeposit.value = null;
|
||||
if (!walletAddress.value || tokenValue.value <= 0) return;
|
||||
const verifyLiquidity = (): void => {
|
||||
enableConfirmButton.value = false;
|
||||
selectedGoerliDeposit.value = undefined;
|
||||
selectedMumbaiDeposit.value = undefined;
|
||||
|
||||
depositsValidList.value.find((element) => {
|
||||
const remaining = element.remaining;
|
||||
if (
|
||||
tokenValue.value!! <= remaining &&
|
||||
tokenValue.value!! != 0 &&
|
||||
element.seller !== walletAddress.value
|
||||
) {
|
||||
enableSelectButton.value = true;
|
||||
hasLiquidity.value = true;
|
||||
selectedDeposit.value = element;
|
||||
return true;
|
||||
if (tokenValue.value <= 0) {
|
||||
enableWalletButton.value = false;
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!enableSelectButton.value) {
|
||||
selectedGoerliDeposit.value = verifyNetworkLiquidity(
|
||||
tokenValue.value,
|
||||
walletAddress.value,
|
||||
depositsValidListGoerli.value
|
||||
);
|
||||
selectedMumbaiDeposit.value = verifyNetworkLiquidity(
|
||||
tokenValue.value,
|
||||
walletAddress.value,
|
||||
depositsValidListMumbai.value
|
||||
);
|
||||
|
||||
enableOrDisableConfirmButton();
|
||||
if (selectedGoerliDeposit.value || selectedMumbaiDeposit.value) {
|
||||
hasLiquidity.value = true;
|
||||
enableWalletButton.value = true;
|
||||
} else {
|
||||
hasLiquidity.value = false;
|
||||
enableWalletButton.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const enableOrDisableConfirmButton = (): void => {
|
||||
if (selectedGoerliDeposit.value && networkName.value == NetworkEnum.ethereum)
|
||||
enableConfirmButton.value = true;
|
||||
else if (
|
||||
selectedMumbaiDeposit.value &&
|
||||
networkName.value == NetworkEnum.polygon
|
||||
)
|
||||
enableConfirmButton.value = true;
|
||||
else enableConfirmButton.value = false;
|
||||
};
|
||||
|
||||
watch(networkName, (): void => {
|
||||
enableOrDisableConfirmButton();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -126,12 +157,14 @@ const verifyLiquidity = () => {
|
||||
src="@/assets/polygon.svg"
|
||||
width="24"
|
||||
height="24"
|
||||
v-if="selectedMumbaiDeposit"
|
||||
/>
|
||||
<img
|
||||
alt="Ethereum image"
|
||||
src="@/assets/ethereum.svg"
|
||||
width="24"
|
||||
height="24"
|
||||
v-if="selectedGoerliDeposit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -149,13 +182,14 @@ const verifyLiquidity = () => {
|
||||
<CustomButton
|
||||
v-if="!walletAddress"
|
||||
:text="'Conectar carteira'"
|
||||
:is-disabled="!enableWalletButton"
|
||||
@buttonClicked="connectAccount()"
|
||||
/>
|
||||
<CustomButton
|
||||
v-if="walletAddress"
|
||||
:text="'Confirmar compra'"
|
||||
:is-disabled="!enableSelectButton"
|
||||
@buttonClicked="emit('tokenBuy', { selectedDeposit, tokenValue })"
|
||||
:is-disabled="!enableConfirmButton"
|
||||
@buttonClicked="emitConfirmButton()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,39 +2,30 @@
|
||||
import { ref } from "vue";
|
||||
import CustomButton from "../../components/CustomButton.vue";
|
||||
import { debounce } from "@/utils/debounce";
|
||||
import { decimalCount } from "@/utils/decimalCount";
|
||||
|
||||
// Reactive state
|
||||
const tokenValue = ref(0);
|
||||
const enableSelectButton = ref(false);
|
||||
const hasLiquidity = ref(true);
|
||||
const validDecimals = ref(true);
|
||||
const tokenValue = ref<number>(0);
|
||||
const enableSelectButton = ref<boolean>(false);
|
||||
const hasLiquidity = ref<boolean>(true);
|
||||
const validDecimals = ref<boolean>(true);
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["tokenBuy"]);
|
||||
|
||||
// Debounce methods
|
||||
const handleInputEvent = (event: any) => {
|
||||
const handleInputEvent = (event: any): void => {
|
||||
const { value } = event.target;
|
||||
|
||||
tokenValue.value = Number(value);
|
||||
|
||||
if (decimalCount(tokenValue.value) > 2) {
|
||||
if (decimalCount(String(tokenValue.value)) > 2) {
|
||||
validDecimals.value = false;
|
||||
enableSelectButton.value = false;
|
||||
return;
|
||||
}
|
||||
validDecimals.value = true;
|
||||
};
|
||||
|
||||
// Enable button methods
|
||||
// Check if has more than 2 decimal places
|
||||
const decimalCount = (num: Number) => {
|
||||
const numStr = String(num);
|
||||
if (numStr.includes(".")) {
|
||||
return numStr.split(".")[1].length;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -2,23 +2,30 @@
|
||||
import { ref } from "vue";
|
||||
import CustomButton from "../CustomButton.vue";
|
||||
import { debounce } from "@/utils/debounce";
|
||||
import { decimalCount } from "@/utils/decimalCount";
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { connectProvider } from "@/blockchain/provider";
|
||||
|
||||
// Reactive state
|
||||
const offer = ref<string | number>("");
|
||||
const etherStore = useEtherStore();
|
||||
const { walletAddress } = storeToRefs(etherStore);
|
||||
|
||||
const offer = ref<string>("");
|
||||
const pixKey = ref<string>("");
|
||||
|
||||
const enableSelectButton = ref(false);
|
||||
const hasLiquidity = ref(true);
|
||||
const validDecimals = ref(true);
|
||||
const enableSelectButton = ref<boolean>(false);
|
||||
const hasLiquidity = ref<boolean>(true);
|
||||
const validDecimals = ref<boolean>(true);
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits(["approveTokens"]);
|
||||
|
||||
// Debounce methods
|
||||
const handleInputEvent = (event: any) => {
|
||||
const handleInputEvent = (event: any): void => {
|
||||
const { value } = event.target;
|
||||
|
||||
offer.value = Number(value);
|
||||
offer.value = value;
|
||||
|
||||
if (decimalCount(offer.value) > 2) {
|
||||
validDecimals.value = false;
|
||||
@ -28,14 +35,12 @@ const handleInputEvent = (event: any) => {
|
||||
validDecimals.value = true;
|
||||
};
|
||||
|
||||
// Enable button methods
|
||||
// Check if has more than 2 decimal places
|
||||
const decimalCount = (num: Number) => {
|
||||
const numStr = String(num);
|
||||
if (numStr.includes(".")) {
|
||||
return numStr.split(".")[1].length;
|
||||
}
|
||||
return 0;
|
||||
const handleButtonClick = async (
|
||||
offer: string,
|
||||
pixKey: string
|
||||
): Promise<void> => {
|
||||
if (walletAddress.value) emit("approveTokens", { offer, pixKey });
|
||||
else await connectProvider();
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -99,8 +104,8 @@ const decimalCount = (num: Number) => {
|
||||
</div>
|
||||
</div>
|
||||
<CustomButton
|
||||
:text="'Aprovar tokens'"
|
||||
@buttonClicked="emit('approveTokens', { offer, pixKey })"
|
||||
:text="walletAddress ? 'Aprovar tokens' : 'Conectar Carteira'"
|
||||
@buttonClicked="handleButtonClick(offer, pixKey)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,12 +2,15 @@
|
||||
import { storeToRefs } from "pinia";
|
||||
import { useEtherStore } from "../store/ether";
|
||||
import { ref } from "vue";
|
||||
import blockchain from "../utils/blockchain";
|
||||
import { NetworkEnum } from "@/model/NetworkEnum";
|
||||
import { connectProvider, requestNetworkChange } from "../blockchain/provider";
|
||||
import ethereumImage from "../assets/ethereum.svg";
|
||||
import polygonImage from "../assets/polygon.svg";
|
||||
|
||||
// Store reference
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const { walletAddress, balance, sellerView } = storeToRefs(etherStore);
|
||||
const { walletAddress, sellerView } = storeToRefs(etherStore);
|
||||
|
||||
const menuOpenToggle = ref<boolean>(false);
|
||||
const menuHoverToggle = ref<boolean>(false);
|
||||
@ -16,8 +19,8 @@ const currencyMenuOpenToggle = ref<boolean>(false);
|
||||
const currencyMenuHoverToggle = ref<boolean>(false);
|
||||
|
||||
//Methods
|
||||
const connectMetaMask = () => {
|
||||
blockchain.connectProvider();
|
||||
const connectMetaMask = async (): Promise<void> => {
|
||||
await connectProvider();
|
||||
};
|
||||
|
||||
const formatWalletAddress = (): string => {
|
||||
@ -30,20 +33,31 @@ const formatWalletAddress = (): string => {
|
||||
return `${initialText}...${finalText}`;
|
||||
};
|
||||
|
||||
const formatWalletBalance = (): String => {
|
||||
const fixed = Number(balance.value);
|
||||
return fixed.toFixed(2);
|
||||
};
|
||||
|
||||
const disconnectUser = () => {
|
||||
const disconnectUser = (): void => {
|
||||
etherStore.setWalletAddress("");
|
||||
closeMenu();
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
const closeMenu = () => {
|
||||
const closeMenu = (): void => {
|
||||
menuOpenToggle.value = false;
|
||||
};
|
||||
|
||||
const networkChange = async (network: NetworkEnum): Promise<void> => {
|
||||
currencyMenuOpenToggle.value = false;
|
||||
const change = await requestNetworkChange(network);
|
||||
if (change) etherStore.setNetworkName(network);
|
||||
};
|
||||
|
||||
const getNetworkImage = (networkName: NetworkEnum): string => {
|
||||
let validImages = {
|
||||
Ethereum: ethereumImage,
|
||||
Polygon: polygonImage,
|
||||
Localhost: ethereumImage,
|
||||
};
|
||||
|
||||
return validImages[networkName];
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -63,16 +77,7 @@ const closeMenu = () => {
|
||||
<RouterLink :to="sellerView ? '/' : '/seller'" class="default-button">
|
||||
{{ sellerView ? "Quero comprar" : "Quero vender" }}
|
||||
</RouterLink>
|
||||
<button
|
||||
type="button"
|
||||
v-if="!walletAddress"
|
||||
class="border-amber-500 border-2 rounded default-button"
|
||||
@click="connectMetaMask()"
|
||||
>
|
||||
Conectar carteira
|
||||
</button>
|
||||
<div v-if="walletAddress" class="account-info">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col" v-if="walletAddress">
|
||||
<div
|
||||
class="group top-bar-info cursor-pointer hover:bg-white"
|
||||
@click="
|
||||
@ -91,7 +96,10 @@ const closeMenu = () => {
|
||||
: 'transparent',
|
||||
}"
|
||||
>
|
||||
<img alt="Ethereum image" src="@/assets/ethereum.svg" />
|
||||
<img
|
||||
alt="Choosed network image"
|
||||
:src="getNetworkImage(etherStore.networkName)"
|
||||
/>
|
||||
<span
|
||||
class="default-text group-hover:text-gray-900"
|
||||
:style="{
|
||||
@ -102,7 +110,7 @@ const closeMenu = () => {
|
||||
: 'rgb(249 250 251)',
|
||||
}"
|
||||
>
|
||||
Ethereum
|
||||
{{ etherStore.networkName }}
|
||||
</span>
|
||||
<img
|
||||
class="text-gray-900"
|
||||
@ -127,40 +135,53 @@ const closeMenu = () => {
|
||||
>
|
||||
<div class="mt-2">
|
||||
<div class="bg-white rounded-md z-10">
|
||||
<div class="menu-button gap-2 px-4 rounded-md cursor-pointer">
|
||||
<div
|
||||
class="menu-button gap-2 px-4 rounded-md cursor-pointer"
|
||||
@click="networkChange(NetworkEnum.ethereum)"
|
||||
>
|
||||
<img
|
||||
alt="Ethereum image"
|
||||
width="20"
|
||||
height="20"
|
||||
src="@/assets/ethereum.svg"
|
||||
/>
|
||||
<span
|
||||
class="text-gray-900 py-4 text-end font-semibold text-sm"
|
||||
>
|
||||
<span class="text-gray-900 py-4 text-end font-semibold text-sm">
|
||||
Ethereum
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-full flex justify-center">
|
||||
<hr class="w-4/5" />
|
||||
</div>
|
||||
<div class="menu-button gap-2 px-4 rounded-md cursor-pointer">
|
||||
<div
|
||||
class="menu-button gap-2 px-4 rounded-md cursor-pointer"
|
||||
@click="networkChange(NetworkEnum.polygon)"
|
||||
>
|
||||
<img
|
||||
alt="Polygon image"
|
||||
width="20"
|
||||
height="20"
|
||||
src="@/assets/polygon.svg"
|
||||
/>
|
||||
<span
|
||||
class="text-gray-900 py-4 text-end font-semibold text-sm"
|
||||
>
|
||||
<span class="text-gray-900 py-4 text-end font-semibold text-sm">
|
||||
Polygon
|
||||
</span>
|
||||
<hr />
|
||||
</div>
|
||||
<div class="w-full flex justify-center">
|
||||
<hr class="w-4/5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
v-if="!walletAddress"
|
||||
class="border-amber-500 border-2 rounded default-button"
|
||||
@click="connectMetaMask()"
|
||||
>
|
||||
Conectar carteira
|
||||
</button>
|
||||
<div v-if="walletAddress" class="account-info">
|
||||
<div class="flex flex-col">
|
||||
<div
|
||||
class="top-bar-info cursor-pointer"
|
||||
@ -241,12 +262,6 @@ const closeMenu = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-bar-info">
|
||||
<span class="default-text text-sm">
|
||||
MBRZ: {{ formatWalletBalance() }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Temporary div, just to show a wallet's balance -->
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
4
src/model/NetworkEnum.ts
Normal file
4
src/model/NetworkEnum.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum NetworkEnum {
|
||||
ethereum = "Ethereum",
|
||||
polygon = "Polygon",
|
||||
}
|
10
src/model/ValidDeposit.ts
Normal file
10
src/model/ValidDeposit.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import type { BigNumber } from "ethers";
|
||||
|
||||
export type ValidDeposit = {
|
||||
depositID: BigNumber;
|
||||
blockNumber: number;
|
||||
remaining: number;
|
||||
seller: string;
|
||||
pixKey: string;
|
||||
pixTarget?: string;
|
||||
};
|
@ -1,6 +1,5 @@
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import HomeView from "../views/HomeView.vue";
|
||||
import MockView from "../views/MockView.vue";
|
||||
import TransactionHistoryView from "../views/TransactionHistoryView.vue";
|
||||
import FaqView from "../views/FaqView.vue";
|
||||
import ManageBidsView from "../views/ManageBidsView.vue";
|
||||
@ -19,11 +18,6 @@ const router = createRouter({
|
||||
name: "seller",
|
||||
component: SellerView,
|
||||
},
|
||||
{
|
||||
path: "/mock",
|
||||
name: "mock",
|
||||
component: MockView,
|
||||
},
|
||||
{
|
||||
path: "/transaction_history",
|
||||
name: "transaction history",
|
||||
|
@ -1,23 +1,18 @@
|
||||
import { NetworkEnum } from "@/model/NetworkEnum";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useEtherStore = defineStore("ether", {
|
||||
state: () => ({
|
||||
walletAddress: "",
|
||||
balance: "",
|
||||
networkName: NetworkEnum.ethereum,
|
||||
loadingLock: false,
|
||||
sellerView: false,
|
||||
// Depósitos válidos para compra
|
||||
depositsValidList: [] as any[],
|
||||
// Depósitos adicionados na blockchain
|
||||
depositsAddedList: [] as any[],
|
||||
// Depósitos expirados na blockchain
|
||||
depositsExpiredList: [] as any[],
|
||||
// Locks adicionados na blockchain
|
||||
locksAddedList: [] as any[],
|
||||
// Locks 'released' na blockchain
|
||||
locksReleasedList: [] as any[],
|
||||
// Locks expirados na blockchain
|
||||
locksExpiredList: [] as any[],
|
||||
// Depósitos válidos para compra GOERLI
|
||||
depositsValidListGoerli: [] as ValidDeposit[],
|
||||
// Depósitos válidos para compra MUMBAI
|
||||
depositsValidListMumbai: [] as ValidDeposit[],
|
||||
}),
|
||||
actions: {
|
||||
setWalletAddress(walletAddress: string) {
|
||||
@ -26,35 +21,27 @@ export const useEtherStore = defineStore("ether", {
|
||||
setBalance(balance: string) {
|
||||
this.balance = balance;
|
||||
},
|
||||
setNetworkName(networkName: NetworkEnum) {
|
||||
this.networkName = networkName;
|
||||
},
|
||||
setLoadingLock(isLoadingLock: boolean) {
|
||||
this.loadingLock = isLoadingLock;
|
||||
},
|
||||
setSellerView(sellerView: boolean) {
|
||||
this.sellerView = sellerView;
|
||||
},
|
||||
setDepositsValidList(depositsValidList: any[]) {
|
||||
this.depositsValidList = depositsValidList;
|
||||
setDepositsValidListGoerli(depositsValidList: ValidDeposit[]) {
|
||||
this.depositsValidListGoerli = depositsValidList;
|
||||
},
|
||||
setDepositsAddedList(depositsAddedList: any[]) {
|
||||
this.depositsAddedList = depositsAddedList;
|
||||
},
|
||||
setDepositsExpiredList(depositsExpiredList: any[]) {
|
||||
this.depositsExpiredList = depositsExpiredList;
|
||||
},
|
||||
setLocksAddedList(locksAddedList: any[]) {
|
||||
this.locksAddedList = locksAddedList;
|
||||
},
|
||||
setLocksReleasedList(locksReleasedList: any[]) {
|
||||
this.locksReleasedList = locksReleasedList;
|
||||
},
|
||||
setLocksExpiredList(locksExpiredList: any[]) {
|
||||
this.locksExpiredList = locksExpiredList;
|
||||
setDepositsValidListMumbai(depositsValidList: ValidDeposit[]) {
|
||||
this.depositsValidListMumbai = depositsValidList;
|
||||
},
|
||||
},
|
||||
// Alterar para integrar com mumbai
|
||||
getters: {
|
||||
getValidDepositByWalletAddress: (state) => {
|
||||
return (walletAddress: string) =>
|
||||
state.depositsValidList
|
||||
state.depositsValidListGoerli
|
||||
.filter((deposit) => deposit.seller == walletAddress)
|
||||
.sort((a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
|
@ -1,531 +0,0 @@
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { BigNumber, ethers } from "ethers";
|
||||
|
||||
// Smart contract imports
|
||||
import mockToken from "./smart_contract_files/MockToken.json";
|
||||
import p2pix from "./smart_contract_files/P2PIX.json";
|
||||
import addresses from "./smart_contract_files/localhost.json";
|
||||
// Mock wallets import
|
||||
import { wallets } from "./smart_contract_files/wallets.json";
|
||||
|
||||
// Wallet methods
|
||||
// Update wallet state (balance and address)
|
||||
const updateWalletStatus = async () => {
|
||||
const etherStore = useEtherStore();
|
||||
const provider = getProvider();
|
||||
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(addresses.token, mockToken.abi, signer);
|
||||
|
||||
const walletAddress = await provider.send("eth_requestAccounts", []);
|
||||
|
||||
const balance = await contract.balanceOf(walletAddress[0]);
|
||||
etherStore.setBalance(formatBigNumber(balance));
|
||||
etherStore.setWalletAddress(ethers.utils.getAddress(walletAddress[0]));
|
||||
};
|
||||
|
||||
const updateWalletBalance = async () => {
|
||||
const etherStore = useEtherStore();
|
||||
const provider = getProvider();
|
||||
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(addresses.token, mockToken.abi, signer);
|
||||
|
||||
const walletAddress = await provider.send("eth_requestAccounts", []);
|
||||
|
||||
const balance = await contract.balanceOf(walletAddress[0]);
|
||||
etherStore.setBalance(formatBigNumber(balance));
|
||||
};
|
||||
|
||||
// Split tokens between wallets in wallets.json
|
||||
const splitTokens = async () => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const tokenContract = new ethers.Contract(
|
||||
addresses.token,
|
||||
mockToken.abi,
|
||||
signer
|
||||
);
|
||||
|
||||
for (let i = 0; i < wallets.length; i++) {
|
||||
const tx = await tokenContract.transfer(
|
||||
wallets[i],
|
||||
ethers.utils.parseEther("4000000.0")
|
||||
);
|
||||
await tx.wait();
|
||||
updateWalletStatus();
|
||||
}
|
||||
};
|
||||
|
||||
// get all wallet transactions
|
||||
const listAllTransactionByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<any[] | undefined> => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterDeposits = p2pContract.filters.DepositAdded([walletAddress]);
|
||||
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
|
||||
|
||||
const filterAddedLocks = p2pContract.filters.LockAdded([walletAddress]);
|
||||
const eventsAddedLocks = await p2pContract.queryFilter(filterAddedLocks);
|
||||
|
||||
const filterReleasedLocks = p2pContract.filters.LockReleased([walletAddress]);
|
||||
const eventsReleasedLocks = await p2pContract.queryFilter(
|
||||
filterReleasedLocks
|
||||
);
|
||||
|
||||
return [...eventsDeposits, ...eventsAddedLocks, ...eventsReleasedLocks].sort(
|
||||
(a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// get wallet's deposit transactions
|
||||
const listDepositTransactionByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<any[]> => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return [];
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterDeposits = p2pContract.filters.DepositAdded([walletAddress]);
|
||||
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
|
||||
|
||||
return eventsDeposits.sort((a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
});
|
||||
};
|
||||
|
||||
// get wallet's deposit transactions
|
||||
const listValidDepositTransactionsByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<any[]> => {
|
||||
const walletDeposits = await getValidDeposits();
|
||||
if (walletDeposits) {
|
||||
return walletDeposits
|
||||
.filter((deposit) => deposit.seller == walletAddress)
|
||||
.sort((a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
});
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
// get wallet's lock transactions
|
||||
const listLockTransactionByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<any[] | undefined> => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterAddedLocks = p2pContract.filters.LockAdded([walletAddress]);
|
||||
const eventsAddedLocks = await p2pContract.queryFilter(filterAddedLocks);
|
||||
|
||||
return eventsAddedLocks.sort((a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
});
|
||||
};
|
||||
|
||||
// get wallet's release transactions
|
||||
const listReleaseTransactionByWalletAddress = async (
|
||||
walletAddress: string
|
||||
): Promise<any[] | undefined> => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterReleasedLocks = p2pContract.filters.LockReleased([walletAddress]);
|
||||
const eventsReleasedLocks = await p2pContract.queryFilter(
|
||||
filterReleasedLocks
|
||||
);
|
||||
|
||||
return eventsReleasedLocks.sort((a, b) => {
|
||||
return b.blockNumber - a.blockNumber;
|
||||
});
|
||||
};
|
||||
|
||||
//get valid deposits
|
||||
const getValidDeposits = async (): Promise<any[] | undefined> => {
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
let provider: ethers.providers.Web3Provider | null = null;
|
||||
|
||||
if (!connection) return [];
|
||||
|
||||
provider = new ethers.providers.Web3Provider(connection);
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterDeposits = p2pContract.filters.DepositAdded(null);
|
||||
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
|
||||
|
||||
const depositList: any[] = await Promise.all(
|
||||
eventsDeposits
|
||||
.map(async (deposit) => {
|
||||
const mappedDeposit = await mapDeposits(deposit.args?.depositID);
|
||||
let validDeposit = {};
|
||||
|
||||
if (mappedDeposit.valid) {
|
||||
validDeposit = {
|
||||
blockNumber: deposit.blockNumber,
|
||||
depositID: deposit.args?.depositID,
|
||||
remaining: formatBigNumber(mappedDeposit.remaining),
|
||||
seller: mappedDeposit.seller,
|
||||
pixKey: mappedDeposit.pixTarget,
|
||||
};
|
||||
}
|
||||
|
||||
return validDeposit;
|
||||
})
|
||||
.filter((deposit) => deposit)
|
||||
);
|
||||
|
||||
return depositList;
|
||||
};
|
||||
// Update events at store methods
|
||||
const updateValidDeposits = async () => {
|
||||
const etherStore = useEtherStore();
|
||||
const deposits = await getValidDeposits();
|
||||
if (deposits) etherStore.setDepositsValidList(deposits);
|
||||
};
|
||||
|
||||
const updateDepositAddedEvents = async () => {
|
||||
const etherStore = useEtherStore();
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
let provider: ethers.providers.Web3Provider | null = null;
|
||||
|
||||
if (!connection) return;
|
||||
provider = new ethers.providers.Web3Provider(connection);
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterDeposits = p2pContract.filters.DepositAdded(null);
|
||||
const eventsDeposits = await p2pContract.queryFilter(filterDeposits);
|
||||
|
||||
etherStore.setDepositsAddedList(eventsDeposits);
|
||||
console.log("DEPOSITS", eventsDeposits);
|
||||
};
|
||||
|
||||
const updateLockAddedEvents = async () => {
|
||||
const etherStore = useEtherStore();
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
let provider: ethers.providers.Web3Provider | null = null;
|
||||
|
||||
if (!connection) return;
|
||||
provider = new ethers.providers.Web3Provider(connection);
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterLocks = p2pContract.filters.LockAdded(null);
|
||||
const eventsLocks = await p2pContract.queryFilter(filterLocks);
|
||||
etherStore.setLocksAddedList(eventsLocks);
|
||||
console.log("LOCKS", eventsLocks);
|
||||
};
|
||||
|
||||
const updateLockReleasedEvents = async () => {
|
||||
const etherStore = useEtherStore();
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
let provider: ethers.providers.Web3Provider | null = null;
|
||||
|
||||
if (!connection) return;
|
||||
provider = new ethers.providers.Web3Provider(connection);
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const filterReleases = p2pContract.filters.LockReleased(null);
|
||||
const eventsReleases = await p2pContract.queryFilter(filterReleases);
|
||||
etherStore.setLocksReleasedList(eventsReleases);
|
||||
console.log("RELEASES", eventsReleases);
|
||||
};
|
||||
|
||||
// Provider methods
|
||||
const connectProvider = async () => {
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
|
||||
await updateWalletStatus();
|
||||
await updateValidDeposits();
|
||||
await updateDepositAddedEvents();
|
||||
await updateLockAddedEvents();
|
||||
await updateLockReleasedEvents();
|
||||
|
||||
connection.on("accountsChanged", async () => {
|
||||
await updateWalletStatus();
|
||||
});
|
||||
};
|
||||
|
||||
const getProvider = (): ethers.providers.Web3Provider | null => {
|
||||
const window_ = window as any;
|
||||
const connection = window_.ethereum;
|
||||
|
||||
if (!connection) return null;
|
||||
|
||||
return new ethers.providers.Web3Provider(connection);
|
||||
};
|
||||
|
||||
// Deposit methods
|
||||
const approveTokens = async (tokenQty: Number) => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
|
||||
const tokenContract = new ethers.Contract(
|
||||
addresses.token,
|
||||
mockToken.abi,
|
||||
signer
|
||||
);
|
||||
|
||||
const apprv = await tokenContract.approve(
|
||||
addresses.p2pix,
|
||||
formatEther(String(tokenQty))
|
||||
);
|
||||
await apprv.wait();
|
||||
return apprv;
|
||||
};
|
||||
|
||||
// Gets value and pix key from user's form to create a deposit in the blockchain
|
||||
const addDeposit = async (tokenQty: Number, pixKey: String) => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const deposit = await p2pContract.deposit(
|
||||
addresses.token,
|
||||
formatEther(String(tokenQty)),
|
||||
pixKey,
|
||||
ethers.utils.formatBytes32String("")
|
||||
);
|
||||
await deposit.wait();
|
||||
|
||||
await updateWalletStatus();
|
||||
await updateDepositAddedEvents();
|
||||
await updateValidDeposits();
|
||||
};
|
||||
|
||||
const mockDeposit = async (tokenQty: Number, pixKey: String) => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
|
||||
const tokenContract = new ethers.Contract(
|
||||
addresses.token,
|
||||
mockToken.abi,
|
||||
signer
|
||||
);
|
||||
|
||||
const apprv = await tokenContract.approve(
|
||||
addresses.p2pix,
|
||||
formatEther(String(tokenQty))
|
||||
);
|
||||
await apprv.wait();
|
||||
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const deposit = await p2pContract.deposit(
|
||||
addresses.token,
|
||||
formatEther(String(tokenQty)),
|
||||
pixKey,
|
||||
ethers.utils.formatBytes32String("")
|
||||
);
|
||||
await deposit.wait();
|
||||
|
||||
await updateWalletStatus();
|
||||
await updateValidDeposits();
|
||||
await updateDepositAddedEvents();
|
||||
};
|
||||
|
||||
// cancel a deposit by its Id
|
||||
const cancelDeposit = async (depositId: BigNumber): Promise<Boolean> => {
|
||||
const provider = getProvider();
|
||||
|
||||
if (!provider) return false;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
await contract.cancelDeposit(depositId);
|
||||
|
||||
await updateWalletBalance();
|
||||
await updateValidDeposits();
|
||||
return true;
|
||||
};
|
||||
|
||||
// withdraw a deposit by its Id
|
||||
const withdrawDeposit = async (depositId: BigNumber): Promise<Boolean> => {
|
||||
const provider = getProvider();
|
||||
|
||||
if (!provider) return false;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
await contract.withdraw(depositId, []);
|
||||
|
||||
await updateWalletBalance();
|
||||
await updateValidDeposits();
|
||||
return true;
|
||||
};
|
||||
|
||||
// Get specific deposit data by its ID
|
||||
const mapDeposits = async (depositId: BigNumber): Promise<any> => {
|
||||
const provider = getProvider();
|
||||
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
const deposit = await contract.mapDeposits(depositId);
|
||||
|
||||
return deposit;
|
||||
};
|
||||
|
||||
// Lock methods
|
||||
// Gets value from user's form to create a lock in the blockchain
|
||||
const addLock = async (depositId: BigNumber, amount: Number) => {
|
||||
const etherStore = useEtherStore();
|
||||
const provider = getProvider();
|
||||
|
||||
if (!provider) return;
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
// Make lock
|
||||
const oldEventsLen = etherStore.locksAddedList.length;
|
||||
const lock = await p2pContract.lock(
|
||||
depositId, // BigNumber
|
||||
etherStore.walletAddress, // String "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" (Example)
|
||||
ethers.constants.AddressZero, // String "0x0000000000000000000000000000000000000000"
|
||||
0,
|
||||
formatEther(String(amount)), // BigNumber
|
||||
[],
|
||||
[]
|
||||
);
|
||||
lock.wait();
|
||||
|
||||
while (etherStore.locksAddedList.length === oldEventsLen) {
|
||||
await updateLockAddedEvents();
|
||||
await updateValidDeposits();
|
||||
}
|
||||
|
||||
return lock;
|
||||
};
|
||||
|
||||
// Get specific lock data by its ID
|
||||
const mapLocks = async (lockId: string) => {
|
||||
const provider = getProvider();
|
||||
|
||||
if (!provider) return;
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const contract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
const lock = await contract.mapLocks(lockId);
|
||||
|
||||
return lock;
|
||||
};
|
||||
|
||||
// Releases lock by specific ID and other additional data
|
||||
const releaseLock = async (
|
||||
pixKey: string,
|
||||
amount: Number,
|
||||
e2eId: string,
|
||||
lockId: string
|
||||
) => {
|
||||
const provider = getProvider();
|
||||
if (!provider) return;
|
||||
|
||||
const mockBacenSigner = new ethers.Wallet(
|
||||
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
||||
);
|
||||
|
||||
const messageToSign = ethers.utils.solidityKeccak256(
|
||||
["string", "uint256", "bytes32"],
|
||||
[
|
||||
pixKey,
|
||||
formatEther(String(amount)),
|
||||
ethers.utils.formatBytes32String(e2eId),
|
||||
]
|
||||
);
|
||||
|
||||
const messageHashBytes = ethers.utils.arrayify(messageToSign);
|
||||
const flatSig = await mockBacenSigner.signMessage(messageHashBytes);
|
||||
const sig = ethers.utils.splitSignature(flatSig);
|
||||
|
||||
const signer = provider.getSigner();
|
||||
const p2pContract = new ethers.Contract(addresses.p2pix, p2pix.abi, signer);
|
||||
|
||||
const release = await p2pContract.release(
|
||||
lockId,
|
||||
ethers.constants.AddressZero,
|
||||
ethers.utils.formatBytes32String(e2eId),
|
||||
sig.r,
|
||||
sig.s,
|
||||
sig.v
|
||||
);
|
||||
release.wait();
|
||||
await updateLockReleasedEvents();
|
||||
await updateValidDeposits();
|
||||
|
||||
return release;
|
||||
};
|
||||
|
||||
// Formatting methods
|
||||
const formatEther = (num: string) => {
|
||||
const formattedNum = ethers.utils.parseEther(num);
|
||||
return formattedNum;
|
||||
};
|
||||
|
||||
const formatBigNumber = (num: BigNumber) => {
|
||||
const formattedNum = ethers.utils.formatEther(num);
|
||||
return formattedNum;
|
||||
};
|
||||
|
||||
export default {
|
||||
connectProvider,
|
||||
formatEther,
|
||||
updateWalletStatus,
|
||||
splitTokens,
|
||||
listValidDepositTransactionsByWalletAddress,
|
||||
listAllTransactionByWalletAddress,
|
||||
listReleaseTransactionByWalletAddress,
|
||||
listDepositTransactionByWalletAddress,
|
||||
listLockTransactionByWalletAddress,
|
||||
approveTokens,
|
||||
addDeposit,
|
||||
cancelDeposit,
|
||||
withdrawDeposit,
|
||||
mockDeposit,
|
||||
mapDeposits,
|
||||
formatBigNumber,
|
||||
addLock,
|
||||
mapLocks,
|
||||
releaseLock,
|
||||
updateLockAddedEvents,
|
||||
updateValidDeposits,
|
||||
getValidDeposits,
|
||||
};
|
6
src/utils/decimalCount.ts
Normal file
6
src/utils/decimalCount.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export const decimalCount = (numStr: string): number => {
|
||||
if (numStr.includes(".")) {
|
||||
return numStr.split(".")[1].length;
|
||||
}
|
||||
return 0;
|
||||
};
|
23
src/utils/networkLiquidity.ts
Normal file
23
src/utils/networkLiquidity.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
|
||||
const verifyNetworkLiquidity = (
|
||||
tokenValue: number,
|
||||
walletAddress: string,
|
||||
validDepositList: ValidDeposit[]
|
||||
): ValidDeposit | undefined => {
|
||||
const element = validDepositList.find((element) => {
|
||||
const remaining = element.remaining;
|
||||
if (
|
||||
tokenValue!! <= remaining &&
|
||||
tokenValue!! != 0 &&
|
||||
element.seller !== walletAddress
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
return element;
|
||||
};
|
||||
|
||||
export { verifyNetworkLiquidity };
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
8
src/utils/smart_contract_files/goerli.json
Normal file
8
src/utils/smart_contract_files/goerli.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"signers": [
|
||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
||||
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
||||
],
|
||||
"p2pix": "0x5f3EFA9A90532914545CEf527C530658af87e196",
|
||||
"token": "0x294003F602c321627152c6b7DED3EAb5bEa853Ee"
|
||||
}
|
8
src/utils/smart_contract_files/polygon-mumbai.json
Normal file
8
src/utils/smart_contract_files/polygon-mumbai.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"signers": [
|
||||
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
||||
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
|
||||
],
|
||||
"p2pix": "0x5f3EFA9A90532914545CEf527C530658af87e196",
|
||||
"token": "0x294003F602c321627152c6b7DED3EAb5bEa853Ee"
|
||||
}
|
@ -2,12 +2,17 @@
|
||||
import SearchComponent from "../components/SearchComponent.vue";
|
||||
import ValidationComponent from "../components/LoadingComponent.vue";
|
||||
import BuyConfirmedComponent from "@/components/BuyConfirmedComponent.vue";
|
||||
import blockchain from "../utils/blockchain";
|
||||
import { ref } from "vue";
|
||||
import { ref, onMounted } from "vue";
|
||||
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import QrCodeComponent from "../components/QrCodeComponent.vue";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { addLock, releaseLock } from "@/blockchain/buyerMethods";
|
||||
import { updateWalletStatus } from "@/blockchain/wallet";
|
||||
import { getNetworksLiquidity } from "@/blockchain/events";
|
||||
import { listReleaseTransactionByWalletAddress } from "@/blockchain/wallet";
|
||||
import type { Event } from "ethers";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
|
||||
enum Step {
|
||||
Search,
|
||||
@ -19,33 +24,33 @@ const etherStore = useEtherStore();
|
||||
etherStore.setSellerView(false);
|
||||
|
||||
// States
|
||||
const { loadingLock, walletAddress, locksAddedList } = storeToRefs(etherStore);
|
||||
const { loadingLock, walletAddress } = storeToRefs(etherStore);
|
||||
const flowStep = ref<Step>(Step.Search);
|
||||
const pixTarget = ref<string>("");
|
||||
const tokenAmount = ref<number>();
|
||||
const lockTransactionHash = ref<string>("");
|
||||
const lockId = ref<string>("");
|
||||
const loadingRelease = ref<Boolean>(false);
|
||||
const lastWalletReleaseTransactions = ref<any[]>([]);
|
||||
const _lockID = ref<string>("");
|
||||
const loadingRelease = ref<boolean>(false);
|
||||
const lastWalletReleaseTransactions = ref<Event[]>([]);
|
||||
|
||||
const confirmBuyClick = async ({ selectedDeposit, tokenValue }: any) => {
|
||||
const confirmBuyClick = async (
|
||||
selectedDeposit: ValidDeposit,
|
||||
tokenValue: number
|
||||
) => {
|
||||
// finish buy screen
|
||||
const depositDetail = selectedDeposit;
|
||||
const depositId = selectedDeposit.depositID;
|
||||
pixTarget.value = selectedDeposit.pixKey;
|
||||
tokenAmount.value = tokenValue;
|
||||
|
||||
// Makes lock with deposit ID and the Amount
|
||||
if (depositDetail) {
|
||||
if (selectedDeposit) {
|
||||
flowStep.value = Step.Buy;
|
||||
etherStore.setLoadingLock(true);
|
||||
|
||||
await blockchain
|
||||
.addLock(depositId, tokenValue)
|
||||
.then((lock) => {
|
||||
lockTransactionHash.value = lock.hash;
|
||||
await addLock(selectedDeposit.depositID, tokenValue)
|
||||
.then((lockID) => {
|
||||
_lockID.value = lockID;
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
flowStep.value = Step.Search;
|
||||
});
|
||||
|
||||
@ -53,38 +58,34 @@ const confirmBuyClick = async ({ selectedDeposit, tokenValue }: any) => {
|
||||
}
|
||||
};
|
||||
|
||||
const releaseTransaction = async ({ e2eId }: any) => {
|
||||
const releaseTransaction = async (e2eId: string) => {
|
||||
flowStep.value = Step.List;
|
||||
loadingRelease.value = true;
|
||||
|
||||
const findLock = locksAddedList.value.find((element) => {
|
||||
if (element.transactionHash === lockTransactionHash.value) {
|
||||
lockId.value = element.args.lockID;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (findLock && tokenAmount.value) {
|
||||
const release = await blockchain.releaseLock(
|
||||
if (_lockID.value && tokenAmount.value) {
|
||||
const release = await releaseLock(
|
||||
pixTarget.value,
|
||||
tokenAmount.value,
|
||||
e2eId,
|
||||
lockId.value
|
||||
_lockID.value
|
||||
);
|
||||
release.wait();
|
||||
|
||||
await blockchain
|
||||
.listReleaseTransactionByWalletAddress(walletAddress.value.toLowerCase())
|
||||
.then((releaseTransactions) => {
|
||||
await listReleaseTransactionByWalletAddress(
|
||||
walletAddress.value.toLowerCase()
|
||||
).then((releaseTransactions) => {
|
||||
if (releaseTransactions)
|
||||
lastWalletReleaseTransactions.value = releaseTransactions;
|
||||
});
|
||||
|
||||
await blockchain.updateWalletStatus();
|
||||
await updateWalletStatus();
|
||||
loadingRelease.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await getNetworksLiquidity();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,28 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { storeToRefs } from "pinia";
|
||||
import blockchain from "../utils/blockchain";
|
||||
import ListingComponent from "@/components/ListingComponent.vue";
|
||||
import type { BigNumber } from "ethers";
|
||||
import { ref, watch } from "vue";
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import { cancelDeposit, withdrawDeposit } from "@/blockchain/buyerMethods";
|
||||
import { listValidDepositTransactionsByWalletAddress } from "@/blockchain/wallet";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
|
||||
const etherStore = useEtherStore();
|
||||
|
||||
const { walletAddress } = storeToRefs(etherStore);
|
||||
const depositList = ref<any[]>([]);
|
||||
const { walletAddress, networkName } = storeToRefs(etherStore);
|
||||
const depositList = ref<ValidDeposit[]>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
if (walletAddress.value) {
|
||||
const walletDeposits =
|
||||
await blockchain.listValidDepositTransactionsByWalletAddress(
|
||||
const walletDeposits = await listValidDepositTransactionsByWalletAddress(
|
||||
walletAddress.value
|
||||
);
|
||||
if (walletDeposits) {
|
||||
depositList.value = walletDeposits;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const handleCancelDeposit = async (depositID: BigNumber, index: number) => {
|
||||
const response = await blockchain.cancelDeposit(depositID);
|
||||
const response = await cancelDeposit(depositID);
|
||||
if (response == true) {
|
||||
console.log("Depósito cancelado com sucesso.");
|
||||
depositList.value.splice(index, 1);
|
||||
@ -30,7 +33,7 @@ const handleCancelDeposit = async (depositID: BigNumber, index: number) => {
|
||||
};
|
||||
|
||||
const handleWithDrawDeposit = async (depositID: BigNumber, index: number) => {
|
||||
const response = await blockchain.withdrawDeposit(depositID);
|
||||
const response = await withdrawDeposit(depositID);
|
||||
if (response == true) {
|
||||
console.log("Token retirado com sucesso.");
|
||||
depositList.value.splice(index, 1);
|
||||
@ -38,13 +41,23 @@ const handleWithDrawDeposit = async (depositID: BigNumber, index: number) => {
|
||||
};
|
||||
|
||||
watch(walletAddress, async () => {
|
||||
const walletDeposits =
|
||||
await blockchain.listValidDepositTransactionsByWalletAddress(
|
||||
walletAddress.value
|
||||
);
|
||||
if (walletDeposits) {
|
||||
depositList.value = walletDeposits;
|
||||
}
|
||||
await listValidDepositTransactionsByWalletAddress(walletAddress.value)
|
||||
.then((res) => {
|
||||
if (res) depositList.value = res;
|
||||
})
|
||||
.catch(() => {
|
||||
depositList.value = [];
|
||||
});
|
||||
});
|
||||
|
||||
watch(networkName, async () => {
|
||||
await listValidDepositTransactionsByWalletAddress(walletAddress.value)
|
||||
.then((res) => {
|
||||
if (res) depositList.value = res;
|
||||
})
|
||||
.catch(() => {
|
||||
depositList.value = [];
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -1,142 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { BigNumber } from "ethers";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import { useEtherStore } from "../store/ether";
|
||||
import blockchain from "../utils/blockchain";
|
||||
|
||||
// Blockchain Data
|
||||
const etherStore = useEtherStore();
|
||||
const { depositsValidList } = storeToRefs(etherStore);
|
||||
const { depositsAddedList } = storeToRefs(etherStore);
|
||||
const { locksAddedList } = storeToRefs(etherStore);
|
||||
|
||||
// Buyer's flow Data
|
||||
const depositValue = ref<Number>();
|
||||
const depositPixKey = ref<string>("");
|
||||
|
||||
// Split tokens between wallets in wallets.json
|
||||
const splitTokens = async () => {
|
||||
blockchain.splitTokens();
|
||||
};
|
||||
|
||||
// Formatting methods
|
||||
// Formats wallet address in 0x000...0000 format
|
||||
const formatWalletAddress = (wallet: string): string => {
|
||||
const walletAddressLength = wallet.length;
|
||||
const initialText = wallet.substring(0, 5);
|
||||
const finalText = wallet.substring(
|
||||
walletAddressLength - 4,
|
||||
walletAddressLength
|
||||
);
|
||||
return `${initialText}...${finalText}`;
|
||||
};
|
||||
|
||||
// Deposit methods
|
||||
// Gets value and pix key from user's form to create a deposit in the blockchain
|
||||
const mockDeposit = () => {
|
||||
if (!depositValue.value || !depositPixKey.value) return;
|
||||
blockchain.mockDeposit(depositValue.value, depositPixKey.value);
|
||||
};
|
||||
|
||||
// Get specific deposit data by its ID
|
||||
const mapDeposit = (depositId: BigNumber) => {
|
||||
const deposit = blockchain.mapDeposits(depositId);
|
||||
return deposit;
|
||||
};
|
||||
|
||||
// Lock methods
|
||||
// Get specific lock data by its ID
|
||||
const mapLock = (lockId: string) => {
|
||||
const lock = blockchain.mapLocks(lockId);
|
||||
return lock;
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="page">
|
||||
<div class="flex flex-col gap-4 justify-start items-start w-2/3">
|
||||
<div class="flex gap-4 w-full justify-between">
|
||||
<input
|
||||
type="number"
|
||||
class="default-input"
|
||||
placeholder="Quantidade de tokens"
|
||||
v-model="depositValue"
|
||||
/>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
class="default-input"
|
||||
placeholder="Chave pix"
|
||||
v-model="depositPixKey"
|
||||
/>
|
||||
|
||||
<button type="button" class="default-button" @click="mockDeposit()">
|
||||
Mockar depósitos
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button" class="default-button" @click="splitTokens()">
|
||||
Dividir tokens
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul class="flex flex-col justify-center items-center gap-4">
|
||||
<li
|
||||
class="text-gray-900 font-semibold text-lg cursor-pointer border-2 border-amber-400 p-2 rounded-md bg-amber-200"
|
||||
v-for="deposit in depositsAddedList"
|
||||
:key="deposit.blockNumber"
|
||||
@click="mapDeposit(deposit.args.depositID)"
|
||||
>
|
||||
Seller:<br />{{ formatWalletAddress(deposit.args.seller) }}<br />
|
||||
MRBZ: {{ blockchain.formatBigNumber(deposit.args.amount) }}
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex flex-col justify-center items-center gap-4">
|
||||
<li
|
||||
class="text-gray-900 font-semibold text-lg cursor-pointer border-2 border-amber-400 p-2 rounded-md bg-amber-200"
|
||||
v-for="lock in locksAddedList"
|
||||
:key="lock.blockNumber"
|
||||
@click="mapLock(lock.args.lockID)"
|
||||
>
|
||||
Buyer:<br />{{ formatWalletAddress(lock.args.buyer) }}<br />
|
||||
MRBZ: {{ blockchain.formatBigNumber(lock.args.amount) }}
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="flex flex-col justify-center items-center gap-4">
|
||||
<li
|
||||
class="text-gray-900 font-semibold text-lg cursor-pointer border-2 border-amber-400 p-2 rounded-md bg-amber-200"
|
||||
v-for="valid in depositsValidList"
|
||||
:key="valid.depositID"
|
||||
@click="mapDeposit(valid.depositID)"
|
||||
>
|
||||
Buyer:<br />{{ formatWalletAddress(valid.seller) }}<br />
|
||||
MRBZ: {{ valid.remaining }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
@apply flex flex-row justify-between w-full items-center;
|
||||
}
|
||||
|
||||
.default-button {
|
||||
@apply p-2 rounded border-2 border-amber-400 text-gray-50 font-extrabold text-base w-full;
|
||||
}
|
||||
|
||||
.default-input {
|
||||
@apply border-none outline-none text-lg text-gray-900 w-64 p-2 rounded-lg;
|
||||
}
|
||||
|
||||
.page {
|
||||
@apply flex gap-8 mt-24;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.page {
|
||||
@apply flex-wrap;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -2,7 +2,7 @@
|
||||
import WantSellComponent from "../components/SellerSteps/WantSellComponent.vue";
|
||||
import SendNetwork from "../components/SellerSteps/SendNetwork.vue";
|
||||
import ValidationComponent from "../components/LoadingComponent.vue";
|
||||
import blockchain from "../utils/blockchain";
|
||||
import { approveTokens, addDeposit } from "../blockchain/sellerMethods";
|
||||
|
||||
import { ref } from "vue";
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
@ -19,19 +19,20 @@ etherStore.setSellerView(true);
|
||||
const flowStep = ref<Step>(Step.Sell);
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const offerValue = ref<number>();
|
||||
const offerValue = ref<string>("");
|
||||
const pixKeyBuyer = ref<string>("");
|
||||
|
||||
// Verificar tipagem
|
||||
const approveOffer = async ({ offer, pixKey }: any) => {
|
||||
const approveOffer = async (args: { offer: string; pixKey: string }) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
offerValue.value = offer;
|
||||
pixKeyBuyer.value = pixKey;
|
||||
await blockchain.approveTokens(Number(offerValue.value));
|
||||
offerValue.value = args.offer;
|
||||
pixKeyBuyer.value = args.pixKey;
|
||||
await approveTokens(args.offer);
|
||||
flowStep.value = Step.Network;
|
||||
loading.value = false;
|
||||
} catch {
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
flowStep.value = Step.Sell;
|
||||
loading.value = false;
|
||||
}
|
||||
@ -41,7 +42,7 @@ const sendNetwork = async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
if (offerValue.value && pixKeyBuyer.value) {
|
||||
await blockchain.addDeposit(offerValue.value, pixKeyBuyer.value);
|
||||
await addDeposit(String(offerValue.value), pixKeyBuyer.value);
|
||||
flowStep.value = Step.Sell;
|
||||
loading.value = false;
|
||||
}
|
||||
|
@ -1,34 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import { useEtherStore } from "@/store/ether";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { ref, watch } from "vue";
|
||||
import { ref, watch, onMounted } from "vue";
|
||||
import ListingComponent from "@/components/ListingComponent.vue";
|
||||
import blockchain from "../utils/blockchain";
|
||||
import { listAllTransactionByWalletAddress } from "@/blockchain/wallet";
|
||||
import type { Event } from "ethers";
|
||||
import type { ValidDeposit } from "@/model/ValidDeposit";
|
||||
|
||||
const etherStore = useEtherStore();
|
||||
const { walletAddress } = storeToRefs(etherStore);
|
||||
const allUserTransactions = ref<any[]>([]);
|
||||
const { walletAddress, networkName } = storeToRefs(etherStore);
|
||||
const allUserTransactions = ref<(Event | ValidDeposit)[]>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
if (walletAddress.value) {
|
||||
await blockchain
|
||||
.listAllTransactionByWalletAddress(walletAddress.value)
|
||||
.then((res) => {
|
||||
await listAllTransactionByWalletAddress(walletAddress.value).then((res) => {
|
||||
if (res) allUserTransactions.value = res;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
watch(walletAddress, async (newValue) => {
|
||||
await blockchain.listAllTransactionByWalletAddress(newValue).then((res) => {
|
||||
await listAllTransactionByWalletAddress(newValue)
|
||||
.then((res) => {
|
||||
if (res) allUserTransactions.value = res;
|
||||
})
|
||||
.catch(() => {
|
||||
allUserTransactions.value = [];
|
||||
});
|
||||
});
|
||||
|
||||
watch(walletAddress, async (newValue) => {
|
||||
console.log(newValue);
|
||||
watch(networkName, async () => {
|
||||
await listAllTransactionByWalletAddress(walletAddress.value)
|
||||
.then((res) => {
|
||||
if (res) allUserTransactions.value = res;
|
||||
})
|
||||
.catch(() => {
|
||||
allUserTransactions.value = [];
|
||||
});
|
||||
|
||||
watch(allUserTransactions, (newValue) => {
|
||||
console.log(newValue);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user