Updated buy flux. Already able to lock.

This commit is contained in:
Filipe Soccol 2025-06-18 12:01:42 -03:00
parent fa2def812c
commit c7b2f1643c
10 changed files with 4157 additions and 3444 deletions

View File

@ -109,3 +109,10 @@ Backend Repo: `https://gitea.kosmos.org/hueso/helpix`
Backend Endpoint: `https://api.p2pix.co/release/1279331`
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {api-key}" \
-d '{"query": "{ depositAddeds { id seller token amount } }"}' \
https://api.studio.thegraph.com/query/113713/p-2-pix/sepolia
https://api.studio.thegraph.com/query/113713/p-2-pix/1

View File

@ -26,7 +26,7 @@
"ethers": "^6.13.4",
"marked": "^4.2.12",
"qrcode": "^1.5.1",
"viem": "^2.30.6",
"viem": "^2.31.3",
"vite-svg-loader": "^5.1.0",
"vue": "^3.2.41",
"vue-markdown": "^2.2.4",

View File

@ -8,18 +8,17 @@ export const addLock = async (
tokenAddress: string,
amount: number
): Promise<string> => {
const { address, abi, client } = await getContract();
const { address, abi, wallet, client } = await getContract();
const parsedAmount = parseEther(amount.toString());
const { request } = await client.simulateContract({
address,
abi,
functionName: "addLock",
args: [sellerAddress, tokenAddress, parsedAmount],
functionName: "lock",
args: [sellerAddress, tokenAddress, parsedAmount, [], []],
});
const hash = await client.writeContract(request);
console.log(wallet);
const hash = await wallet.writeContract(request);
const receipt = await client.waitForTransactionReceipt({ hash });
return receipt.status ? receipt.logs[0].topics[2] : "";
@ -29,33 +28,33 @@ export const withdrawDeposit = async (
amount: string,
token: TokenEnum
): Promise<boolean> => {
const { address, abi, client } = await getContract();
const { address, abi, wallet, client } = await getContract();
const tokenAddress = getTokenAddress(token);
const { request } = await client.simulateContract({
address,
abi,
functionName: "withdrawDeposit",
args: [tokenAddress, parseEther(amount)],
functionName: "withdraw",
args: [tokenAddress, parseEther(amount), []],
});
const hash = await client.writeContract(request);
const hash = await wallet.writeContract(request);
const receipt = await client.waitForTransactionReceipt({ hash });
return receipt.status;
};
export const releaseLock = async (solicitation: any): Promise<any> => {
const { address, abi, client } = await getContract();
const { address, abi, wallet, client } = await getContract();
const { request } = await client.simulateContract({
address,
abi,
functionName: "releaseLock",
functionName: "release",
args: [solicitation.lockId, solicitation.e2eId],
});
const hash = await client.writeContract(request);
const hash = await wallet.writeContract(request);
return client.waitForTransactionReceipt({ hash });
};

View File

@ -5,7 +5,7 @@ import p2pix from "@/utils/smart_contract_files/P2PIX.json";
import { getContract } from "./provider";
import type { ValidDeposit } from "@/model/ValidDeposit";
import { getP2PixAddress, getTokenAddress } from "./addresses";
import { NetworkEnum } from "@/model/NetworkEnum";
import { getNetworkSubgraphURL, NetworkEnum } from "@/model/NetworkEnum";
import type { UnreleasedLock } from "@/model/UnreleasedLock";
import type { Pix } from "@/model/Pix";
@ -18,7 +18,6 @@ const getNetworksLiquidity = async (): Promise<void> => {
for (const network of Object.values(NetworkEnum).filter(
(v) => !isNaN(Number(v))
)) {
console.log("getNetworksLiquidity", network);
const deposits = await getValidDeposits(
getTokenAddress(user.selectedToken.value),
Number(network)
@ -70,6 +69,7 @@ const getValidDeposits = async (
({ address, abi, client } = await getContract(true));
}
// TODO: Remove this once we have a subgraph for rootstock
if (network === NetworkEnum.rootstock) return [];
const body = {
@ -85,16 +85,13 @@ const getValidDeposits = async (
`,
};
const depositLogs = await fetch(
"https://subgraph.satsuma-prod.com/0c3d7b832269/gavins-team--383150/p2pix/version/v0.0.2/api",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
const depositLogs = await fetch(getNetworkSubgraphURL(network), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
// remove doubles from sellers list
const depositData = await depositLogs.json();
@ -140,7 +137,6 @@ const getValidDeposits = async (
network,
pixKey: "",
};
depositList[seller + token] = validDeposit;
}
});

View File

@ -7,14 +7,15 @@ import {
custom,
http,
PublicClient,
WalletClient,
} from "viem";
import { sepolia, rootstock } from "viem/chains";
import { useUser } from "@/composables/useUser";
let publicClient = null;
let walletClient = null;
let publicClient: PublicClient | null = null;
let walletClient: WalletClient | null = null;
const getPublicClient: PublicClient = (onlyRpcProvider = false) => {
const getPublicClient: PublicClient | null = (onlyRpcProvider = false) => {
if (onlyRpcProvider) {
const user = useUser();
const rpcUrl = getProviderUrl();
@ -27,7 +28,7 @@ const getPublicClient: PublicClient = (onlyRpcProvider = false) => {
return publicClient;
};
const getWalletClient = () => {
const getWalletClient: WalletClient | null = () => {
return walletClient;
};
@ -35,12 +36,15 @@ const getContract = async (onlyRpcProvider = false) => {
const client = getPublicClient(onlyRpcProvider);
const address = getP2PixAddress();
const abi = p2pix.abi;
const wallet = getWalletClient();
return { address, abi, client };
const [account] = wallet ? await wallet.getAddresses() : [""];
return { address, abi, client, wallet, account };
};
const connectProvider = async (p: any): Promise<void> => {
console.log("Connecting to provider...");
console.log("Connecting to wallet provider...");
const user = useUser();
const chain =
Number(user.networkName.value) === sepolia.id ? sepolia : rootstock;
@ -50,7 +54,10 @@ const connectProvider = async (p: any): Promise<void> => {
transport: custom(p),
});
const [account] = await p!.request({ method: "eth_requestAccounts" });
walletClient = createWalletClient({
account,
chain,
transport: custom(p),
});

View File

@ -1,4 +1,4 @@
import { decodeEventLog, formatEther, type Log, parseAbi } from "viem";
import { decodeEventLog, formatEther, type Log } from "viem";
import { useUser } from "@/composables/useUser";
import { getPublicClient, getWalletClient, getContract } from "./provider";
@ -12,6 +12,7 @@ import type { ValidDeposit } from "@/model/ValidDeposit";
import type { WalletTransaction } from "@/model/WalletTransaction";
import type { UnreleasedLock } from "@/model/UnreleasedLock";
import type { Pix } from "@/model/Pix";
import { getNetworkSubgraphURL } from "@/model/NetworkEnum";
export const updateWalletStatus = async (): Promise<void> => {
const user = useUser();
@ -107,107 +108,205 @@ const filterLockStatus = async (
export const listAllTransactionByWalletAddress = async (
walletAddress: string
): Promise<WalletTransaction[]> => {
const { address, client } = await getContract(true);
const user = useUser();
// Get deposits
const depositLogs = await client.getLogs({
address,
event: parseAbi([
"event DepositAdded(address indexed seller, address token, uint256 amount)",
])[0],
args: {
seller: walletAddress,
// Get the current network for the subgraph URL
const network = user.networkName.value;
// Query subgraph for all relevant transactions
const subgraphQuery = {
query: `
{
depositAddeds(where: {seller: "${walletAddress.toLowerCase()}"}) {
seller
token
amount
blockTimestamp
blockNumber
transactionHash
}
lockAddeds(where: {buyer: "${walletAddress.toLowerCase()}"}) {
buyer
lockID
seller
token
amount
blockTimestamp
blockNumber
transactionHash
}
lockReleaseds(where: {buyer: "${walletAddress.toLowerCase()}"}) {
buyer
lockId
e2eId
blockTimestamp
blockNumber
transactionHash
}
depositWithdrawns(where: {seller: "${walletAddress.toLowerCase()}"}) {
seller
token
amount
blockTimestamp
blockNumber
transactionHash
}
}
`,
};
console.log("Fetching transactions from subgraph");
const response = await fetch(getNetworkSubgraphURL(network), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
fromBlock: 0n,
toBlock: "latest",
});
console.log("Fetched all wallet deposits");
// Get locks
const lockLogs = await client.getLogs({
address,
event: parseAbi([
"event LockAdded(address indexed buyer, uint256 indexed lockID, address seller, address token, uint256 amount)",
])[0],
args: {
buyer: walletAddress,
},
fromBlock: 0n,
toBlock: "latest",
});
console.log("Fetched all wallet locks");
// Get released locks
const releasedLogs = await client.getLogs({
address,
event: parseAbi([
"event LockReleased(address indexed buyer, uint256 indexed lockID, string e2eId)",
])[0],
args: {
buyer: walletAddress,
},
fromBlock: 0n,
toBlock: "latest",
});
console.log("Fetched all wallet released locks");
// Get withdrawn deposits
const withdrawnLogs = await client.getLogs({
address,
event: parseAbi([
"event DepositWithdrawn(address indexed seller, address token, uint256 amount)",
])[0],
args: {
seller: walletAddress,
},
fromBlock: 0n,
toBlock: "latest",
});
console.log("Fetched all wallet withdrawn deposits");
const allLogs = [
...depositLogs,
...lockLogs,
...releasedLogs,
...withdrawnLogs,
].sort((a: Log, b: Log) => {
return Number(b.blockNumber) - Number(a.blockNumber);
body: JSON.stringify(subgraphQuery),
});
return await filterLockStatus(allLogs);
const data = await response.json();
console.log("Subgraph data fetched:", data);
// Convert all transactions to common WalletTransaction format
const transactions: WalletTransaction[] = [];
// Process deposit added events
if (data.data?.depositAddeds) {
console.log("Processing deposit events");
for (const deposit of data.data.depositAddeds) {
transactions.push({
token: deposit.token,
blockNumber: parseInt(deposit.blockNumber),
amount: parseFloat(formatEther(BigInt(deposit.amount))),
seller: deposit.seller,
buyer: "",
event: "DepositAdded",
lockStatus: -1,
transactionHash: deposit.transactionHash,
});
}
}
// Process lock added events
if (data.data?.lockAddeds) {
console.log("Processing lock events");
for (const lock of data.data.lockAddeds) {
// Get lock status from the contract
const lockStatus = await getLockStatus(BigInt(lock.lockID));
transactions.push({
token: lock.token,
blockNumber: parseInt(lock.blockNumber),
amount: parseFloat(formatEther(BigInt(lock.amount))),
seller: lock.seller,
buyer: lock.buyer,
event: "LockAdded",
lockStatus: lockStatus,
transactionHash: lock.transactionHash,
transactionID: lock.lockID.toString(),
});
}
}
// Process lock released events
if (data.data?.lockReleaseds) {
console.log("Processing release events");
for (const release of data.data.lockReleaseds) {
transactions.push({
token: "", // Subgraph doesn't provide token in this event, we could enhance this later
blockNumber: parseInt(release.blockNumber),
amount: -1, // Amount not available in this event
seller: "",
buyer: release.buyer,
event: "LockReleased",
lockStatus: -1,
transactionHash: release.transactionHash,
transactionID: release.lockId.toString(),
});
}
}
// Process deposit withdrawn events
if (data.data?.depositWithdrawns) {
console.log("Processing withdrawal events");
for (const withdrawal of data.data.depositWithdrawns) {
transactions.push({
token: withdrawal.token,
blockNumber: parseInt(withdrawal.blockNumber),
amount: parseFloat(formatEther(BigInt(withdrawal.amount))),
seller: withdrawal.seller,
buyer: "",
event: "DepositWithdrawn",
lockStatus: -1,
transactionHash: withdrawal.transactionHash,
});
}
}
// Sort transactions by block number (newest first)
return transactions.sort((a, b) => b.blockNumber - a.blockNumber);
};
// get wallet's release transactions
export const listReleaseTransactionByWalletAddress = async (
walletAddress: string
) => {
const { address, client } = await getContract(true);
const user = useUser();
const network = user.networkName.value;
const releasedLogs = await client.getLogs({
address,
event: parseAbi([
"event LockReleased(address indexed buyer, uint256 indexed lockID, string e2eId)",
])[0],
args: {
buyer: walletAddress,
// Query subgraph for release transactions
const subgraphQuery = {
query: `
{
lockReleaseds(where: {buyer: "${walletAddress.toLowerCase()}"}) {
buyer
lockId
e2eId
blockTimestamp
blockNumber
transactionHash
}
}
`,
};
// Fetch data from subgraph
const response = await fetch(getNetworkSubgraphURL(network), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
fromBlock: 0n,
toBlock: "latest",
body: JSON.stringify(subgraphQuery),
});
return releasedLogs
.sort((a: Log, b: Log) => {
return Number(b.blockNumber) - Number(a.blockNumber);
const data = await response.json();
// Process the subgraph response into the same format as the previous implementation
if (!data.data?.lockReleaseds) {
return [];
}
// Transform the subgraph data to match the event log decode format
return data.data.lockReleaseds
.sort((a: any, b: any) => {
return parseInt(b.blockNumber) - parseInt(a.blockNumber);
})
.map((log: Log) => {
.map((release: any) => {
try {
return decodeEventLog({
abi: p2pix.abi,
data: log.data,
topics: log.topics,
});
// Create a structure similar to the decoded event log
return {
eventName: "LockReleased",
args: {
buyer: release.buyer,
lockID: BigInt(release.lockId),
e2eId: release.e2eId,
},
// Add any other necessary fields to match the original return format
blockNumber: BigInt(release.blockNumber),
transactionHash: release.transactionHash,
};
} catch (error) {
console.error("Error decoding log", error);
console.error("Error processing subgraph data", error);
return null;
}
})
@ -215,72 +314,145 @@ export const listReleaseTransactionByWalletAddress = async (
};
const listLockTransactionByWalletAddress = async (walletAddress: string) => {
const { address, client } = await getContract(true);
const user = useUser();
const network = user.networkName.value;
const lockLogs = await client.getLogs({
address,
event: parseAbi([
"event LockAdded(address indexed buyer, uint256 indexed lockID, address seller, address token, uint256 amount)",
])[0],
args: {
buyer: walletAddress,
},
fromBlock: 0n,
toBlock: "latest",
});
return lockLogs
.sort((a: Log, b: Log) => {
return Number(b.blockNumber) - Number(a.blockNumber);
})
.map((log: Log) => {
try {
return decodeEventLog({
abi: p2pix.abi,
data: log.data,
topics: log.topics,
});
} catch (error) {
console.error("Error decoding log", error);
return null;
// Query subgraph for lock added transactions
const subgraphQuery = {
query: `
{
lockAddeds(where: {buyer: "${walletAddress.toLowerCase()}"}) {
buyer
lockID
seller
token
amount
blockTimestamp
blockNumber
transactionHash
}
}
})
.filter((decoded: any) => decoded !== null);
`,
};
try {
// Fetch data from subgraph
const response = await fetch(getNetworkSubgraphURL(network), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(subgraphQuery),
});
const data = await response.json();
if (!data.data?.lockAddeds) {
return [];
}
// Transform the subgraph data to match the event log decode format
return data.data.lockAddeds
.sort((a: any, b: any) => {
return parseInt(b.blockNumber) - parseInt(a.blockNumber);
})
.map((lock: any) => {
try {
// Create a structure similar to the decoded event log
return {
eventName: "LockAdded",
args: {
buyer: lock.buyer,
lockID: BigInt(lock.lockID),
seller: lock.seller,
token: lock.token,
amount: BigInt(lock.amount),
},
// Add other necessary fields to match the original format
blockNumber: BigInt(lock.blockNumber),
transactionHash: lock.transactionHash,
};
} catch (error) {
console.error("Error processing subgraph data", error);
return null;
}
})
.filter((decoded: any) => decoded !== null);
} catch (error) {
console.error("Error fetching from subgraph:", error);
}
};
const listLockTransactionBySellerAddress = async (sellerAddress: string) => {
const { address, client } = await getContract(true);
const user = useUser();
const network = user.networkName.value;
console.log("Will get locks as seller", sellerAddress);
const lockLogs = await client.getLogs({
address,
event: parseAbi([
"event LockAdded(address indexed buyer, uint256 indexed lockID, address seller, address token, uint256 amount)",
])[0],
fromBlock: 0n,
toBlock: "latest",
});
return lockLogs
.map((log: Log) => {
try {
return decodeEventLog({
abi: p2pix.abi,
data: log.data,
topics: log.topics,
});
} catch (error) {
console.error("Error decoding log", error);
return null;
// Query subgraph for lock added transactions where seller matches
const subgraphQuery = {
query: `
{
lockAddeds(where: {seller: "${sellerAddress.toLowerCase()}"}) {
buyer
lockID
seller
token
amount
blockTimestamp
blockNumber
transactionHash
}
}
})
.filter((decoded: any) => decoded !== null)
.filter(
(decoded: any) =>
decoded.args &&
decoded.args.seller &&
decoded.args.seller.toLowerCase() === sellerAddress.toLowerCase()
);
`,
};
try {
// Fetch data from subgraph
const response = await fetch(getNetworkSubgraphURL(network), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(subgraphQuery),
});
const data = await response.json();
if (!data.data?.lockAddeds) {
return [];
}
// Transform the subgraph data to match the event log decode format
return data.data.lockAddeds
.sort((a: any, b: any) => {
return parseInt(b.blockNumber) - parseInt(a.blockNumber);
})
.map((lock: any) => {
try {
// Create a structure similar to the decoded event log
return {
eventName: "LockAdded",
args: {
buyer: lock.buyer,
lockID: BigInt(lock.lockID),
seller: lock.seller,
token: lock.token,
amount: BigInt(lock.amount),
},
// Add other necessary fields to match the original format
blockNumber: BigInt(lock.blockNumber),
transactionHash: lock.transactionHash,
};
} catch (error) {
console.error("Error processing subgraph data", error);
return null;
}
})
.filter((decoded: any) => decoded !== null);
} catch (error) {
console.error("Error fetching from subgraph:", error);
return [];
}
};
export const checkUnreleasedLock = async (
@ -347,19 +519,23 @@ export const getActiveLockAmount = async (
args: [lockIds],
});
let activeLockAmount = 0;
for (let i = 0; i < lockStatus[1].length; i++) {
if (lockStatus[1][i] === 1) {
const lockId = lockStatus[0][i];
const lock = await client.readContract({
address,
abi,
functionName: "mapLocks",
args: [lockId],
});
activeLockAmount += Number(formatEther(lock.amount));
}
}
const mapLocksRequests = lockStatus[0].map((id: bigint) =>
client.readContract({
address,
abi,
functionName: "mapLocks",
args: [id],
})
);
return activeLockAmount;
const mapLocksResults = await client.multicall({
contracts: mapLocksRequests as any,
});
return mapLocksResults.reduce((total: number, lock: any, index: number) => {
if (lockStatus[1][index] === 1) {
return total + Number(formatEther(lock.amount));
}
return total;
}, 0);
};

View File

@ -51,7 +51,7 @@ const connectAccount = async (): Promise<void> => {
const emitConfirmButton = async (): Promise<void> => {
const deposit = selectedDeposits.value?.find(
(d) => d.network === networkName.value
(d) => d.network === Number(networkName.value)
);
if (!deposit) return;
deposit.pixKey = await getPixKey(deposit.seller, deposit.token);
@ -95,10 +95,9 @@ const verifyLiquidity = (): void => {
walletAddress.value,
depositsValidList.value
);
selectedDeposits.value = selDeposits;
hasLiquidity.value = !!selDeposits.find(
(d) => d.network === networkName.value
(d) => d.network === Number(networkName.value)
);
enableOrDisableConfirmButton();
};
@ -129,8 +128,6 @@ watch(walletAddress, (): void => {
// Add form submission handler
const handleSubmit = async (e: Event): Promise<void> => {
e.preventDefault();
if (!enableConfirmButton.value) return;
if (walletAddress.value) {
await emitConfirmButton();
} else {
@ -274,7 +271,9 @@ const handleSubmit = async (e: Event): Promise<void> => {
</div>
<div
class="flex justify-center"
v-else-if="!hasLiquidity && !loadingNetworkLiquidity"
v-else-if="
!hasLiquidity && !loadingNetworkLiquidity && tokenValue > 0
"
>
<span class="text-red-500 font-normal text-sm"
>Atualmente não liquidez nas rede selecionada para sua

View File

@ -3,6 +3,15 @@ export enum NetworkEnum {
rootstock = 31,
}
export const getNetworkSubgraphURL = (network: NetworkEnum | number) => {
const networkMap: Record<number, string> = {
[NetworkEnum.sepolia]: import.meta.env.VITE_SEPOLIA_SUBGRAPH_URL || "",
[NetworkEnum.rootstock]: import.meta.env.VITE_RSK_SUBGRAPH_URL || "",
};
return networkMap[typeof network === "number" ? network : network] || "";
};
export enum TokenEnum {
BRZ = "BRZ",
// BRX = 'BRX'

View File

@ -74,7 +74,6 @@ const releaseTransaction = async (lockId: string) => {
};
const checkForUnreleasedLocks = async (): Promise<void> => {
console.log("Checking for unreleased locks");
const walletLocks = await checkUnreleasedLock(walletAddress.value);
if (walletLocks) {
lockID.value = walletLocks.lockID;

7015
yarn.lock

File diff suppressed because it is too large Load Diff