From a906fa136d614b1f996d2e8e626ab14716c949ff Mon Sep 17 00:00:00 2001 From: hueso Date: Sat, 11 Oct 2025 02:17:07 -0300 Subject: [PATCH] refactored network selection --- src/App.vue | 12 +- src/blockchain/addresses.ts | 54 -------- src/blockchain/buyerMethods.ts | 9 +- src/blockchain/events.ts | 24 ++-- src/blockchain/provider.ts | 15 +-- src/blockchain/sellerMethods.ts | 21 ++-- src/blockchain/wallet.ts | 22 ++-- .../BuyerSteps/BuyConfirmedComponent.vue | 2 +- .../BuyerSteps/BuyerSearchComponent.vue | 17 ++- .../ListingComponent/ListingComponent.vue | 8 +- .../ListingComponent/TransactionCard.vue | 7 +- .../SellerSteps/SellerComponent.vue | 2 +- src/components/TopBar/TopBar.vue | 48 ++++--- src/components/ui/NetworkBadges.vue | 10 +- src/components/ui/NetworkSelector.vue | 24 ++-- src/components/ui/ToasterComponent.vue | 12 +- src/composables/useUser.ts | 41 ++++-- src/config/networks.ts | 117 +++--------------- src/model/NetworkEnum.ts | 21 ++-- src/model/Networks.ts | 28 ----- src/model/ValidDeposit.ts | 4 +- src/views/HomeView.vue | 4 +- src/views/ManageBidsView.vue | 8 +- 23 files changed, 174 insertions(+), 336 deletions(-) delete mode 100644 src/blockchain/addresses.ts delete mode 100644 src/model/Networks.ts diff --git a/src/App.vue b/src/App.vue index 97a041f..e684b8d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -5,21 +5,19 @@ import SpinnerComponent from "@/components/ui/SpinnerComponent.vue"; import ToasterComponent from "@/components/ui/ToasterComponent.vue"; import { init, useOnboard } from "@web3-onboard/vue"; import injectedModule from "@web3-onboard/injected-wallets"; -import { Networks } from "@/model/Networks"; -import { NetworkEnum } from "@/model/NetworkEnum"; +import { Networks, DEFAULT_NETWORK } from "@/config/networks"; import { ref } from "vue"; const route = useRoute(); const injected = injectedModule(); -const targetNetwork = ref(NetworkEnum.sepolia); +const targetNetwork = ref(DEFAULT_NETWORK); const web3Onboard = init({ wallets: [injected], chains: Object.entries(Networks).map(([, network]) => ({ - id: network.chainId, - token: network.token, - label: network.chainName, - rpcUrl: network.rpcUrl, + id: network.id, + label: network.nativeCurrency.symbol, + rpcUrl: network.rpcUrls.default.http[0], })), connect: { autoConnectLastWallet: true, diff --git a/src/blockchain/addresses.ts b/src/blockchain/addresses.ts deleted file mode 100644 index 0fd7e8c..0000000 --- a/src/blockchain/addresses.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { useUser } from "@/composables/useUser"; -import { NetworkEnum, TokenEnum } from "@/model/NetworkEnum"; -import { createPublicClient, http, type Address } from "viem"; -import { getContractAddress, getRpcUrl, getNetworkConfig, getViemChain } from "@/config/networks"; - -export const getTokenByAddress = (address: Address) => { - const user = useUser(); - const networkConfig = getNetworkConfig(user.networkName.value); - - for (const [token, tokenAddress] of Object.entries(networkConfig.contracts.tokenAddresses)) { - if (tokenAddress.toLowerCase() === address.toLowerCase()) { - return token; - } - } - return null; -}; - -export const getTokenAddress = ( - token: TokenEnum, - network?: NetworkEnum -): Address => { - const user = useUser(); - const networkId = network ? network : user.networkName.value; - - const tokenAddress = getContractAddress(networkId, token); - return tokenAddress as Address; -}; - -export const getP2PixAddress = (network?: NetworkEnum): Address => { - const user = useUser(); - const networkId = network ? network : user.networkName.value; - - const p2pixAddress = getContractAddress(networkId, 'p2pix'); - return p2pixAddress as Address; -}; - -export const getProviderUrl = (network?: NetworkEnum): string => { - const user = useUser(); - const networkId = network || user.networkName.value; - - return getRpcUrl(networkId); -}; - -export const getProviderByNetwork = (network: NetworkEnum) => { - const chain = getViemChain(network); - return createPublicClient({ - chain, - transport: http(getProviderUrl(network)), - }); -}; - -export const isPossibleNetwork = (networkChain: NetworkEnum): boolean => { - return Number(networkChain) in NetworkEnum; -}; diff --git a/src/blockchain/buyerMethods.ts b/src/blockchain/buyerMethods.ts index f8400c1..abe93bc 100644 --- a/src/blockchain/buyerMethods.ts +++ b/src/blockchain/buyerMethods.ts @@ -1,11 +1,10 @@ import { getContract } from "./provider"; -import { getTokenAddress } from "./addresses"; +import { ChainContract } from "viem"; import { parseEther, type Address, type TransactionReceipt, } from "viem"; -import type { TokenEnum } from "@/model/NetworkEnum"; export const addLock = async ( sellerAddress: Address, @@ -37,7 +36,7 @@ export const addLock = async ( export const withdrawDeposit = async ( amount: string, - token: TokenEnum + token: Address ): Promise => { const { address, abi, wallet, client, account } = await getContract(); @@ -45,13 +44,11 @@ export const withdrawDeposit = async ( throw new Error("Wallet not connected"); } - const tokenAddress = getTokenAddress(token); - const { request } = await client.simulateContract({ address, abi, functionName: "withdraw", - args: [tokenAddress, parseEther(amount), []], + args: [token, parseEther(amount), []], account }); diff --git a/src/blockchain/events.ts b/src/blockchain/events.ts index 9251421..c5c910a 100644 --- a/src/blockchain/events.ts +++ b/src/blockchain/events.ts @@ -1,14 +1,13 @@ import { useUser } from "@/composables/useUser"; import { formatEther, toHex, stringToHex } from "viem"; import type { PublicClient, Address } from "viem"; - +import { Networks } from "@/config/networks"; import { getContract } from "./provider"; -import { getP2PixAddress, getTokenAddress } from "./addresses"; import { p2PixAbi } from "./abi" import type { ValidDeposit } from "@/model/ValidDeposit"; -import { getNetworkSubgraphURL, NetworkEnum, TokenEnum } from "@/model/NetworkEnum"; +import type { NetworkConfig } from "@/model/NetworkEnum"; import type { UnreleasedLock } from "@/model/UnreleasedLock"; -import type { LockStatus } from "@/model/LockStatus" +import { ChainContract } from "viem"; const getNetworksLiquidity = async (): Promise => { const user = useUser(); @@ -16,12 +15,10 @@ const getNetworksLiquidity = async (): Promise => { const depositLists: ValidDeposit[][] = []; - for (const network of Object.values(NetworkEnum).filter( - (v) => !isNaN(Number(v)) - )) { + for (const network of Object.values(Networks)) { const deposits = await getValidDeposits( - getTokenAddress(user.selectedToken.value), - Number(network) + user.network.value.tokens[user.selectedToken.value].address, + network ); if (deposits) depositLists.push(deposits); } @@ -62,7 +59,7 @@ const getParticipantID = async ( const getValidDeposits = async ( token: Address, - network: NetworkEnum, + network: NetworkConfig, contractInfo?: { client: PublicClient; address: Address } ): Promise => { let client: PublicClient, abi; @@ -74,9 +71,6 @@ const getValidDeposits = async ( ({ abi, client } = await getContract(true)); } - // TODO: Remove this once we have a subgraph for rootstock - if (network === NetworkEnum.rootstock) return []; - const body = { query: ` { @@ -90,7 +84,7 @@ const getValidDeposits = async ( `, }; - const depositLogs = await fetch(getNetworkSubgraphURL(network), { + const depositLogs = await fetch( network.subgraphUrls[0], { method: "POST", headers: { "Content-Type": "application/json", @@ -119,7 +113,7 @@ const getValidDeposits = async ( const sellersList = Object.keys(uniqueSellers) as Address[]; // Use multicall to batch all getBalance requests const balanceCalls = sellersList.map((seller) => ({ - address: getP2PixAddress(network), + address: (network.contracts?.p2pix as ChainContract).address, abi, functionName: "getBalance", args: [seller, token], diff --git a/src/blockchain/provider.ts b/src/blockchain/provider.ts index 949ad94..51b9439 100644 --- a/src/blockchain/provider.ts +++ b/src/blockchain/provider.ts @@ -1,6 +1,5 @@ import { p2PixAbi } from "./abi"; import { updateWalletStatus } from "./wallet"; -import { getProviderUrl, getP2PixAddress } from "./addresses"; import { createPublicClient, createWalletClient, @@ -10,15 +9,16 @@ import { WalletClient, } from "viem"; import { useUser } from "@/composables/useUser"; -import { getViemChain } from "@/config/networks"; +import type { NetworkConfig } from "@/model/NetworkEnum"; +import type { ChainContract } from "viem"; let walletClient: WalletClient | null = null; const getPublicClient = (): PublicClient => { const user = useUser(); - const rpcUrl = getProviderUrl(); - const chain = getViemChain(user.networkName.value); - + const rpcUrl = (user.network.value as NetworkConfig).rpcUrls.default.http[0]; + const chain = user.network.value; + return createPublicClient({ chain, transport: http(rpcUrl), @@ -31,7 +31,8 @@ const getWalletClient = (): WalletClient | null => { const getContract = async (onlyRpcProvider = false) => { const client = getPublicClient(); - const address = getP2PixAddress(); + const user = useUser(); + const address = (user.network.value.contracts?.p2pix as ChainContract).address; const abi = p2PixAbi; const wallet = onlyRpcProvider ? null : getWalletClient(); @@ -46,7 +47,7 @@ const getContract = async (onlyRpcProvider = false) => { const connectProvider = async (p: any): Promise => { const user = useUser(); - const chain = getViemChain(user.networkName.value); + const chain = user.network.value; const [account] = await p!.request({ method: "eth_requestAccounts" }); diff --git a/src/blockchain/sellerMethods.ts b/src/blockchain/sellerMethods.ts index b4f5a5d..f5657f4 100644 --- a/src/blockchain/sellerMethods.ts +++ b/src/blockchain/sellerMethods.ts @@ -1,12 +1,15 @@ import { getContract, getPublicClient, getWalletClient } from "./provider"; -import { getTokenAddress, getP2PixAddress } from "./addresses"; -import { parseEther, toHex } from "viem"; -import { getViemChain } from "@/config/networks"; - +import { parseEther, toHex, ChainContract } from "viem"; import { mockTokenAbi } from "./abi"; import { useUser } from "@/composables/useUser"; import { createParticipant } from "@/utils/bbPay"; import type { Participant } from "@/utils/bbPay"; +import type { Address } from "viem"; + +const getP2PixAddress = (): Address => { + const user = useUser(); + return (user.network.value.contracts?.p2pix as ChainContract).address; +}; const approveTokens = async (participant: Participant): Promise => { const user = useUser(); @@ -21,7 +24,7 @@ const approveTokens = async (participant: Participant): Promise => { const [account] = await walletClient.getAddresses(); // Get token address - const tokenAddress = getTokenAddress(user.selectedToken.value); + const tokenAddress = user.network.value.tokens[user.selectedToken.value].address; // Check if the token is already approved const allowance = await publicClient.readContract({ @@ -33,7 +36,7 @@ const approveTokens = async (participant: Participant): Promise => { if ( allowance < parseEther(participant.offer.toString()) ) { // Approve tokens - const chain = getViemChain(user.networkName.value); + const chain = user.network.value; const hash = await walletClient.writeContract({ address: tokenAddress, abi: mockTokenAbi, @@ -65,15 +68,15 @@ const addDeposit = async (): Promise => { if (!sellerId.id) { throw new Error("Failed to create participant"); } - const chain = getViemChain(user.networkName.value); + const chain = user.network.value; const hash = await walletClient.writeContract({ address, abi, functionName: "deposit", args: [ - user.networkId.value + "-" + sellerId.id, + user.network.value.id + "-" + sellerId.id, toHex("", { size: 32 }), - getTokenAddress(user.selectedToken.value), + user.network.value.tokens[user.selectedToken.value].address, parseEther(user.seller.value.offer.toString()), true, ], diff --git a/src/blockchain/wallet.ts b/src/blockchain/wallet.ts index 77fcf7c..de8b318 100644 --- a/src/blockchain/wallet.ts +++ b/src/blockchain/wallet.ts @@ -2,7 +2,6 @@ import { formatEther, type Address } from "viem"; import { useUser } from "@/composables/useUser"; import { getPublicClient, getWalletClient, getContract } from "./provider"; -import { getTokenAddress } from "./addresses"; import { getValidDeposits, getUnreleasedLockById } from "./events"; @@ -10,7 +9,6 @@ import type { ValidDeposit } from "@/model/ValidDeposit"; import type { WalletTransaction } from "@/model/WalletTransaction"; import type { UnreleasedLock } from "@/model/UnreleasedLock"; import { LockStatus } from "@/model/LockStatus"; -import { getNetworkSubgraphURL } from "@/model/NetworkEnum"; export const updateWalletStatus = async (): Promise => { const user = useUser(); @@ -36,8 +34,8 @@ export const listValidDepositTransactionsByWalletAddress = async ( ): Promise => { const user = useUser(); const walletDeposits = await getValidDeposits( - getTokenAddress(user.selectedToken.value), - user.networkName.value + user.network.value.tokens[user.selectedToken.value].address, + user.network.value ); if (walletDeposits) { return walletDeposits @@ -67,7 +65,7 @@ export const listAllTransactionByWalletAddress = async ( const user = useUser(); // Get the current network for the subgraph URL - const network = user.networkName.value; + const network = user.network.value; // Query subgraph for all relevant transactions const subgraphQuery = { @@ -110,7 +108,7 @@ export const listAllTransactionByWalletAddress = async ( `, }; - const response = await fetch(getNetworkSubgraphURL(network), { + const response = await fetch(network.subgraphUrls[0], { method: "POST", headers: { "Content-Type": "application/json", @@ -200,7 +198,7 @@ export const listReleaseTransactionByWalletAddress = async ( walletAddress: Address ) => { const user = useUser(); - const network = user.networkName.value; + const network = user.network.value; // Query subgraph for release transactions const subgraphQuery = { @@ -219,7 +217,7 @@ export const listReleaseTransactionByWalletAddress = async ( }; // Fetch data from subgraph - const response = await fetch(getNetworkSubgraphURL(network), { + const response = await fetch(network.subgraphUrls[0], { method: "POST", headers: { "Content-Type": "application/json", @@ -263,7 +261,7 @@ export const listReleaseTransactionByWalletAddress = async ( const listLockTransactionByWalletAddress = async (walletAddress: Address) => { const user = useUser(); - const network = user.networkName.value; + const network = user.network.value; // Query subgraph for lock added transactions const subgraphQuery = { @@ -284,7 +282,7 @@ const listLockTransactionByWalletAddress = async (walletAddress: Address) => { try { // Fetch data from subgraph - const response = await fetch(getNetworkSubgraphURL(network), { + const response = await fetch(network.subgraphUrls[0], { method: "POST", headers: { "Content-Type": "application/json", @@ -332,7 +330,7 @@ const listLockTransactionByWalletAddress = async (walletAddress: Address) => { const listLockTransactionBySellerAddress = async (sellerAddress: Address) => { const user = useUser(); - const network = user.networkName.value; + const network = user.network.value; // Query subgraph for lock added transactions where seller matches const subgraphQuery = { @@ -354,7 +352,7 @@ const listLockTransactionBySellerAddress = async (sellerAddress: Address) => { try { // Fetch data from subgraph - const response = await fetch(getNetworkSubgraphURL(network), { + const response = await fetch(network.subgraphUrls[0], { method: "POST", headers: { "Content-Type": "application/json", diff --git a/src/components/BuyerSteps/BuyConfirmedComponent.vue b/src/components/BuyerSteps/BuyConfirmedComponent.vue index 7d2cf9b..5828020 100644 --- a/src/components/BuyerSteps/BuyConfirmedComponent.vue +++ b/src/components/BuyerSteps/BuyConfirmedComponent.vue @@ -53,7 +53,7 @@ const getWalletTransactions = async () => { const callWithdraw = async (amount: string) => { if (amount) { user.setLoadingWalletTransactions(true); - const withdraw = await withdrawDeposit(amount, user.selectedToken.value); + const withdraw = await withdrawDeposit(amount, user.network.value.tokens[user.selectedToken.value].address); if (withdraw) { console.log("Saque realizado!"); await getWalletTransactions(); diff --git a/src/components/BuyerSteps/BuyerSearchComponent.vue b/src/components/BuyerSteps/BuyerSearchComponent.vue index b8ddfd6..2012ba0 100644 --- a/src/components/BuyerSteps/BuyerSearchComponent.vue +++ b/src/components/BuyerSteps/BuyerSearchComponent.vue @@ -5,12 +5,11 @@ import SpinnerComponent from "@/components/ui/SpinnerComponent.vue"; import CustomButton from "@/components/ui/CustomButton.vue"; import { debounce } from "@/utils/debounce"; import { verifyNetworkLiquidity } from "@/utils/networkLiquidity"; -import { NetworkEnum } from "@/model/NetworkEnum"; import type { ValidDeposit } from "@/model/ValidDeposit"; import { decimalCount } from "@/utils/decimalCount"; import { getTokenImage } from "@/utils/imagesPath"; import { onClickOutside } from "@vueuse/core"; - +import { Networks } from "@/config/networks"; import { TokenEnum } from "@/model/NetworkEnum"; // Store reference @@ -19,7 +18,7 @@ const selectTokenToggle = ref(false); const { walletAddress, - networkName, + network, selectedToken, depositsValidList, loadingNetworkLiquidity, @@ -51,7 +50,7 @@ const connectAccount = async (): Promise => { const emitConfirmButton = async (): Promise => { const deposit = selectedDeposits.value?.find( - (d) => d.network === Number(networkName.value) + (d) => d.network === network.value ); if (!deposit) return; deposit.participantID = await getParticipantID(deposit.seller, deposit.token); @@ -99,7 +98,7 @@ const verifyLiquidity = (): void => { ); selectedDeposits.value = selDeposits; hasLiquidity.value = !!selDeposits.find( - (d) => d.network === Number(networkName.value) + (d) => d.network === network.value ); enableOrDisableConfirmButton(); }; @@ -110,7 +109,7 @@ const enableOrDisableConfirmButton = (): void => { return; } - if (!selectedDeposits.value.find((d) => d.network === networkName.value)) { + if (!selectedDeposits.value.find((d) => d.network === network.value)) { enableConfirmButton.value = false; return; } @@ -118,7 +117,7 @@ const enableOrDisableConfirmButton = (): void => { enableConfirmButton.value = true; }; -watch(networkName, (): void => { +watch(network, (): void => { verifyLiquidity(); enableOrDisableConfirmButton(); }); @@ -239,7 +238,7 @@ const handleSubmit = async (e: Event): Promise => { height="24" v-if=" selectedDeposits && - selectedDeposits.find((d) => d.network == NetworkEnum.rootstock) + selectedDeposits.find((d) => d.network == Networks.rootstockTestnet) " /> => { height="24" v-if=" selectedDeposits && - selectedDeposits.find((d) => d.network == NetworkEnum.sepolia) + selectedDeposits.find((d) => d.network == Networks.sepolia) " /> diff --git a/src/components/ListingComponent/ListingComponent.vue b/src/components/ListingComponent/ListingComponent.vue index 14405da..a350054 100644 --- a/src/components/ListingComponent/ListingComponent.vue +++ b/src/components/ListingComponent/ListingComponent.vue @@ -1,5 +1,4 @@ @@ -34,7 +34,7 @@ const networkData = computed(() => {
diff --git a/src/components/ui/NetworkSelector.vue b/src/components/ui/NetworkSelector.vue index 59f0e0a..0920648 100644 --- a/src/components/ui/NetworkSelector.vue +++ b/src/components/ui/NetworkSelector.vue @@ -1,16 +1,16 @@