UNPKG

wisdom-sdk

Version:

Core business logic and data access layer for prediction markets

218 lines (216 loc) 7.49 kB
import { fetchCallReadOnlyFunction, Cl, ClarityType } from '@stacks/transactions'; import { STACKS_MAINNET } from '@stacks/network'; import { createClerkClient } from '@clerk/backend'; // src/user-balance-store.ts var CONTRACT_ADDRESS = "SP2ZNGJ85ENDY6QRHQ5P2D4FXKGZWCKTB2T0Z55KS"; var CONTRACT_NAME = "blaze-welsh-v1"; var clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, publishableKey: process.env.CLERK_PUBLISHABLE_KEY }); var userBalanceStore = { /** * Get the user's Stacks address from Clerk's publicMetadata */ async getUserStacksAddress(userId) { try { const user = await clerkClient.users.getUser(userId); if (user.publicMetadata && typeof user.publicMetadata === "object") { const metadata = user.publicMetadata; if (metadata.stacksAddress) { return metadata.stacksAddress; } } console.warn(`No Stacks address found for user ${userId}`); return null; } catch (error) { console.error(`Error getting Stacks address for user ${userId}:`, error); return null; } }, /** * Fetch a user's on-chain balance from the contract */ async fetchContractBalance(user) { try { const result = await fetchCallReadOnlyFunction({ contractAddress: CONTRACT_ADDRESS, contractName: CONTRACT_NAME, functionName: "get-balance", functionArgs: [Cl.principal(user)], network: STACKS_MAINNET, senderAddress: user }); const balance = result.type === ClarityType.UInt ? Number(result.value) : 0; return balance; } catch (error) { console.error("Failed to fetch contract balance:", error); return 0; } }, /** * Get user balance using their Clerk ID * Fetches directly from blockchain if Stacks address is available */ async getUserBalance(userId) { try { if (!userId) return null; const stacksAddress = await this.getUserStacksAddress(userId); let balance = await kvStore.getEntity("USER_BALANCE", userId); if (!balance) { balance = { userId, availableBalance: 0, totalDeposited: 0, totalWithdrawn: 0, inPredictions: 0, lastUpdated: (/* @__PURE__ */ new Date()).toISOString(), stacksAddress: null }; } if (stacksAddress) { balance.stacksAddress = stacksAddress; const contractBalance = await this.fetchContractBalance(stacksAddress); balance.availableBalance = contractBalance; } return balance; } catch (error) { console.error(`Error getting user balance for ${userId}:`, error); return null; } }, // Update user balance when making a prediction async updateBalanceForPrediction(userId, amount) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; if (balance.availableBalance < amount) { throw new Error("Insufficient balance"); } const updatedBalance = { ...balance, availableBalance: balance.availableBalance - amount, inPredictions: balance.inPredictions + amount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error updating balance for prediction, user ${userId}:`, error); throw error; } }, // Update user balance when a prediction is resolved async updateBalanceForResolvedPrediction(userId, originalAmount, winnings = 0) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; const updatedBalance = { ...balance, availableBalance: balance.availableBalance + winnings, inPredictions: balance.inPredictions - originalAmount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error updating balance for resolved prediction, user ${userId}:`, error); throw error; } }, // Add funds to user balance (for deposit functionality) async addFunds(userId, amount) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; const updatedBalance = { ...balance, availableBalance: balance.availableBalance + amount, totalDeposited: balance.totalDeposited + amount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error adding funds for user ${userId}:`, error); throw error; } }, // Withdraw funds from user balance async withdrawFunds(userId, amount) { try { const balance = await this.getUserBalance(userId); if (!balance) return null; if (balance.availableBalance < amount) { throw new Error("Insufficient balance"); } const updatedBalance = { ...balance, availableBalance: balance.availableBalance - amount, totalWithdrawn: balance.totalWithdrawn + amount, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error withdrawing funds for user ${userId}:`, error); throw error; } }, // Force refresh a user's balance from the blockchain async refreshBalance(userId) { try { const stacksAddress = await this.getUserStacksAddress(userId); if (!stacksAddress) { throw new Error(`No Stacks address found for user ${userId}`); } const contractBalance = await this.fetchContractBalance(stacksAddress); const balance = await kvStore.getEntity("USER_BALANCE", userId) || { userId, availableBalance: 0, totalDeposited: 0, totalWithdrawn: 0, inPredictions: 0, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; const updatedBalance = { ...balance, availableBalance: contractBalance, stacksAddress, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() }; await kvStore.storeEntity("USER_BALANCE", userId, updatedBalance); return updatedBalance; } catch (error) { console.error(`Error refreshing balance for user ${userId}:`, error); throw error; } } }; var kvStore = { async getEntity(collection, id) { console.log({ collection, id }); const stacksAddress = await userBalanceStore.getUserStacksAddress(id); let availableBalance = 0; if (stacksAddress) { availableBalance = await userBalanceStore.fetchContractBalance(stacksAddress); } const balance = { userId: id, availableBalance, totalDeposited: 0, totalWithdrawn: 0, inPredictions: 0, lastUpdated: (/* @__PURE__ */ new Date()).toISOString(), stacksAddress }; return balance; }, async storeEntity(collection, id, entity) { console.log({ collection, id, entity }); return null; } }; export { userBalanceStore }; //# sourceMappingURL=chunk-SL5BKWK6.js.map //# sourceMappingURL=chunk-SL5BKWK6.js.map