UNPKG

wisdom-sdk

Version:

Core business logic and data access layer for prediction markets

1 lines 14.8 kB
{"version":3,"sources":["../src/user-balance-store.ts"],"names":["createClerkClient","fetchCallReadOnlyFunction","Cl","STACKS_MAINNET","ClarityType"],"mappings":";;;;;;;AAIA,IAAM,gBAAmB,GAAA,2CAAA;AACzB,IAAM,aAAgB,GAAA,gBAAA;AAEtB,IAAM,cAAcA,yBAAkB,CAAA;AAAA,EACpC,SAAA,EAAW,QAAQ,GAAI,CAAA,gBAAA;AAAA,EACvB,cAAA,EAAgB,QAAQ,GAAI,CAAA;AAC9B,CAAC,CAAA;AAGM,IAAM,gBAAmB,GAAA;AAAA;AAAA;AAAA;AAAA,EAI9B,MAAM,qBAAqB,MAAwC,EAAA;AACjE,IAAI,IAAA;AAEF,MAAA,MAAM,IAAO,GAAA,MAAM,WAAY,CAAA,KAAA,CAAM,QAAQ,MAAM,CAAA;AAGnD,MAAA,IAAI,IAAK,CAAA,cAAA,IAAkB,OAAO,IAAA,CAAK,mBAAmB,QAAU,EAAA;AAClE,QAAA,MAAM,WAAW,IAAK,CAAA,cAAA;AACtB,QAAA,IAAI,SAAS,aAAe,EAAA;AAC1B,UAAA,OAAO,QAAS,CAAA,aAAA;AAAA;AAClB;AAIF,MAAQ,OAAA,CAAA,IAAA,CAAK,CAAoC,iCAAA,EAAA,MAAM,CAAE,CAAA,CAAA;AACzD,MAAO,OAAA,IAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,sCAAA,EAAyC,MAAM,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AACvE,MAAO,OAAA,IAAA;AAAA;AACT,GACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,qBAAqB,IAA+B,EAAA;AACxD,IAAI,IAAA;AACF,MAAM,MAAA,MAAA,GAAS,MAAMC,sCAA0B,CAAA;AAAA,QAC7C,eAAiB,EAAA,gBAAA;AAAA,QACjB,YAAc,EAAA,aAAA;AAAA,QACd,YAAc,EAAA,aAAA;AAAA,QACd,YAAc,EAAA,CAACC,eAAG,CAAA,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,QACjC,OAAS,EAAAC,sBAAA;AAAA,QACT,aAAe,EAAA;AAAA,OAChB,CAAA;AACD,MAAM,MAAA,OAAA,GAAU,OAAO,IAAS,KAAAC,wBAAA,CAAY,OAAO,MAAO,CAAA,MAAA,CAAO,KAAK,CAAI,GAAA,CAAA;AAE1E,MAAO,OAAA,OAAA;AAAA,aACA,KAAgB,EAAA;AACvB,MAAQ,OAAA,CAAA,KAAA,CAAM,qCAAqC,KAAK,CAAA;AACxD,MAAO,OAAA,CAAA;AAAA;AACT,GACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,MAAgB,EAAA;AACnC,IAAI,IAAA;AACF,MAAI,IAAA,CAAC,QAAe,OAAA,IAAA;AAGpB,MAAA,MAAM,aAAgB,GAAA,MAAM,IAAK,CAAA,oBAAA,CAAqB,MAAM,CAAA;AAG5D,MAAA,IAAI,OAAU,GAAA,MAAM,OAAQ,CAAA,SAAA,CAAU,gBAAgB,MAAM,CAAA;AAG5D,MAAA,IAAI,CAAC,OAAS,EAAA;AACZ,QAAU,OAAA,GAAA;AAAA,UACR,MAAA;AAAA,UACA,gBAAkB,EAAA,CAAA;AAAA,UAClB,cAAgB,EAAA,CAAA;AAAA,UAChB,cAAgB,EAAA,CAAA;AAAA,UAChB,aAAe,EAAA,CAAA;AAAA,UACf,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY,EAAA;AAAA,UACpC,aAAe,EAAA;AAAA,SACjB;AAAA;AAIF,MAAA,IAAI,aAAe,EAAA;AACjB,QAAA,OAAA,CAAQ,aAAgB,GAAA,aAAA;AACxB,QAAA,MAAM,eAAkB,GAAA,MAAM,IAAK,CAAA,oBAAA,CAAqB,aAAa,CAAA;AACrE,QAAA,OAAA,CAAQ,gBAAmB,GAAA,eAAA;AAAA;AAG7B,MAAO,OAAA,OAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,+BAAA,EAAkC,MAAM,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAChE,MAAO,OAAA,IAAA;AAAA;AACT,GACF;AAAA;AAAA,EAGA,MAAM,0BAA2B,CAAA,MAAA,EAAgB,MAAgB,EAAA;AAC/D,IAAI,IAAA;AACF,MAAA,MAAM,OAAe,GAAA,MAAM,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA;AACrD,MAAI,IAAA,CAAC,SAAgB,OAAA,IAAA;AAGrB,MAAI,IAAA,OAAA,CAAQ,mBAAmB,MAAQ,EAAA;AACrC,QAAM,MAAA,IAAI,MAAM,sBAAsB,CAAA;AAAA;AAGxC,MAAA,MAAM,cAAiB,GAAA;AAAA,QACrB,GAAG,OAAA;AAAA,QACH,gBAAA,EAAkB,QAAQ,gBAAmB,GAAA,MAAA;AAAA,QAC7C,aAAA,EAAe,QAAQ,aAAgB,GAAA,MAAA;AAAA,QACvC,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY;AAAA,OACtC;AAEA,MAAA,MAAM,OAAQ,CAAA,WAAA,CAAY,cAAgB,EAAA,MAAA,EAAQ,cAAc,CAAA;AAChE,MAAO,OAAA,cAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,4CAAA,EAA+C,MAAM,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAC7E,MAAM,MAAA,KAAA;AAAA;AACR,GACF;AAAA;AAAA,EAGA,MAAM,kCAAA,CACJ,MACA,EAAA,cAAA,EACA,WAAmB,CACnB,EAAA;AACA,IAAI,IAAA;AACF,MAAA,MAAM,OAAe,GAAA,MAAM,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA;AACrD,MAAI,IAAA,CAAC,SAAgB,OAAA,IAAA;AAErB,MAAA,MAAM,cAAiB,GAAA;AAAA,QACrB,GAAG,OAAA;AAAA,QACH,gBAAA,EAAkB,QAAQ,gBAAmB,GAAA,QAAA;AAAA,QAC7C,aAAA,EAAe,QAAQ,aAAgB,GAAA,cAAA;AAAA,QACvC,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY;AAAA,OACtC;AAEA,MAAA,MAAM,OAAQ,CAAA,WAAA,CAAY,cAAgB,EAAA,MAAA,EAAQ,cAAc,CAAA;AAChE,MAAO,OAAA,cAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,qDAAA,EAAwD,MAAM,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AACtF,MAAM,MAAA,KAAA;AAAA;AACR,GACF;AAAA;AAAA,EAGA,MAAM,QAAS,CAAA,MAAA,EAAgB,MAAgB,EAAA;AAC7C,IAAI,IAAA;AACF,MAAA,MAAM,OAAe,GAAA,MAAM,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA;AACrD,MAAI,IAAA,CAAC,SAAgB,OAAA,IAAA;AAErB,MAAA,MAAM,cAAiB,GAAA;AAAA,QACrB,GAAG,OAAA;AAAA,QACH,gBAAA,EAAkB,QAAQ,gBAAmB,GAAA,MAAA;AAAA,QAC7C,cAAA,EAAgB,QAAQ,cAAiB,GAAA,MAAA;AAAA,QACzC,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY;AAAA,OACtC;AAEA,MAAA,MAAM,OAAQ,CAAA,WAAA,CAAY,cAAgB,EAAA,MAAA,EAAQ,cAAc,CAAA;AAChE,MAAO,OAAA,cAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,4BAAA,EAA+B,MAAM,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAC7D,MAAM,MAAA,KAAA;AAAA;AACR,GACF;AAAA;AAAA,EAGA,MAAM,aAAc,CAAA,MAAA,EAAgB,MAAgB,EAAA;AAClD,IAAI,IAAA;AACF,MAAA,MAAM,OAAe,GAAA,MAAM,IAAK,CAAA,cAAA,CAAe,MAAM,CAAA;AACrD,MAAI,IAAA,CAAC,SAAgB,OAAA,IAAA;AAGrB,MAAI,IAAA,OAAA,CAAQ,mBAAmB,MAAQ,EAAA;AACrC,QAAM,MAAA,IAAI,MAAM,sBAAsB,CAAA;AAAA;AAGxC,MAAA,MAAM,cAAiB,GAAA;AAAA,QACrB,GAAG,OAAA;AAAA,QACH,gBAAA,EAAkB,QAAQ,gBAAmB,GAAA,MAAA;AAAA,QAC7C,cAAA,EAAgB,QAAQ,cAAiB,GAAA,MAAA;AAAA,QACzC,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY;AAAA,OACtC;AAEA,MAAA,MAAM,OAAQ,CAAA,WAAA,CAAY,cAAgB,EAAA,MAAA,EAAQ,cAAc,CAAA;AAChE,MAAO,OAAA,cAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,iCAAA,EAAoC,MAAM,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AAClE,MAAM,MAAA,KAAA;AAAA;AACR,GACF;AAAA;AAAA,EAGA,MAAM,eAAe,MAAgB,EAAA;AACnC,IAAI,IAAA;AACF,MAAA,MAAM,aAAgB,GAAA,MAAM,IAAK,CAAA,oBAAA,CAAqB,MAAM,CAAA;AAC5D,MAAA,IAAI,CAAC,aAAe,EAAA;AAClB,QAAA,MAAM,IAAI,KAAA,CAAM,CAAoC,iCAAA,EAAA,MAAM,CAAE,CAAA,CAAA;AAAA;AAG9D,MAAA,MAAM,eAAkB,GAAA,MAAM,IAAK,CAAA,oBAAA,CAAqB,aAAa,CAAA;AACrE,MAAA,MAAM,UAAU,MAAM,OAAA,CAAQ,SAAU,CAAA,cAAA,EAAgB,MAAM,CAAK,IAAA;AAAA,QACjE,MAAA;AAAA,QACA,gBAAkB,EAAA,CAAA;AAAA,QAClB,cAAgB,EAAA,CAAA;AAAA,QAChB,cAAgB,EAAA,CAAA;AAAA,QAChB,aAAe,EAAA,CAAA;AAAA,QACf,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY;AAAA,OACtC;AAEA,MAAA,MAAM,cAAiB,GAAA;AAAA,QACrB,GAAG,OAAA;AAAA,QACH,gBAAkB,EAAA,eAAA;AAAA,QAClB,aAAA;AAAA,QACA,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY;AAAA,OACtC;AAEA,MAAA,MAAM,OAAQ,CAAA,WAAA,CAAY,cAAgB,EAAA,MAAA,EAAQ,cAAc,CAAA;AAChE,MAAO,OAAA,cAAA;AAAA,aACA,KAAO,EAAA;AACd,MAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,kCAAA,EAAqC,MAAM,CAAA,CAAA,CAAA,EAAK,KAAK,CAAA;AACnE,MAAM,MAAA,KAAA;AAAA;AACR;AAEJ;AAEA,IAAM,OAAU,GAAA;AAAA,EACd,MAAM,SAAU,CAAA,UAAA,EAAoB,EAAY,EAAA;AAC9C,IAAA,OAAA,CAAQ,GAAI,CAAA,EAAE,UAAY,EAAA,EAAA,EAAI,CAAA;AAE9B,IAAA,MAAM,aAAgB,GAAA,MAAM,gBAAiB,CAAA,oBAAA,CAAqB,EAAE,CAAA;AAEpE,IAAA,IAAI,gBAAmB,GAAA,CAAA;AACvB,IAAA,IAAI,aAAe,EAAA;AACjB,MAAmB,gBAAA,GAAA,MAAM,gBAAiB,CAAA,oBAAA,CAAqB,aAAa,CAAA;AAAA;AAG9E,IAAA,MAAM,OAAU,GAAA;AAAA,MACd,MAAQ,EAAA,EAAA;AAAA,MACR,gBAAA;AAAA,MACA,cAAgB,EAAA,CAAA;AAAA,MAChB,cAAgB,EAAA,CAAA;AAAA,MAChB,aAAe,EAAA,CAAA;AAAA,MACf,WAAa,EAAA,iBAAA,IAAI,IAAK,EAAA,EAAE,WAAY,EAAA;AAAA,MACpC;AAAA,KACF;AACA,IAAO,OAAA,OAAA;AAAA,GACT;AAAA,EAEA,MAAM,WAAA,CAAY,UAAoB,EAAA,EAAA,EAAY,MAAa,EAAA;AAC7D,IAAA,OAAA,CAAQ,GAAI,CAAA,EAAE,UAAY,EAAA,EAAA,EAAI,QAAQ,CAAA;AACtC,IAAO,OAAA,IAAA;AAAA;AAEX,CAAA","file":"user-balance-store.cjs","sourcesContent":["import { fetchCallReadOnlyFunction, Cl, ClarityType } from '@stacks/transactions';\nimport { STACKS_MAINNET } from '@stacks/network';\nimport { createClerkClient } from '@clerk/backend';\n\nconst CONTRACT_ADDRESS = 'SP2ZNGJ85ENDY6QRHQ5P2D4FXKGZWCKTB2T0Z55KS';\nconst CONTRACT_NAME = 'blaze-welsh-v1';\n\nconst clerkClient = createClerkClient({\n secretKey: process.env.CLERK_SECRET_KEY,\n publishableKey: process.env.CLERK_PUBLISHABLE_KEY\n});\n\n// User balance store with Clerk integration\nexport const userBalanceStore = {\n /**\n * Get the user's Stacks address from Clerk's publicMetadata\n */\n async getUserStacksAddress(userId: string): Promise<string | null> {\n try {\n // Get the user from Clerk\n const user = await clerkClient.users.getUser(userId);\n\n // Check for Stacks address in public metadata\n if (user.publicMetadata && typeof user.publicMetadata === 'object') {\n const metadata = user.publicMetadata as Record<string, any>;\n if (metadata.stacksAddress) {\n return metadata.stacksAddress as string;\n }\n }\n\n // No Stacks address found\n console.warn(`No Stacks address found for user ${userId}`);\n return null;\n } catch (error) {\n console.error(`Error getting Stacks address for user ${userId}:`, error);\n return null;\n }\n },\n\n /**\n * Fetch a user's on-chain balance from the contract\n */\n async fetchContractBalance(user: string): Promise<number> {\n try {\n const result = await fetchCallReadOnlyFunction({\n contractAddress: CONTRACT_ADDRESS,\n contractName: CONTRACT_NAME,\n functionName: 'get-balance',\n functionArgs: [Cl.principal(user)],\n network: STACKS_MAINNET,\n senderAddress: user\n });\n const balance = result.type === ClarityType.UInt ? Number(result.value) : 0;\n\n return balance;\n } catch (error: unknown) {\n console.error('Failed to fetch contract balance:', error);\n return 0;\n }\n },\n\n /**\n * Get user balance using their Clerk ID\n * Fetches directly from blockchain if Stacks address is available\n */\n async getUserBalance(userId: string) {\n try {\n if (!userId) return null;\n\n // Get stacks address from Clerk\n const stacksAddress = await this.getUserStacksAddress(userId);\n\n // Get stored balance data\n let balance = await kvStore.getEntity('USER_BALANCE', userId);\n\n // If no balance exists, initialize it\n if (!balance) {\n balance = {\n userId,\n availableBalance: 0,\n totalDeposited: 0,\n totalWithdrawn: 0,\n inPredictions: 0,\n lastUpdated: new Date().toISOString(),\n stacksAddress: null\n };\n }\n\n // If we have a Stacks address, update with real blockchain balance\n if (stacksAddress) {\n balance.stacksAddress = stacksAddress;\n const contractBalance = await this.fetchContractBalance(stacksAddress);\n balance.availableBalance = contractBalance;\n }\n\n return balance;\n } catch (error) {\n console.error(`Error getting user balance for ${userId}:`, error);\n return null;\n }\n },\n\n // Update user balance when making a prediction\n async updateBalanceForPrediction(userId: string, amount: number) {\n try {\n const balance: any = await this.getUserBalance(userId);\n if (!balance) return null;\n\n // Check if user has enough balance\n if (balance.availableBalance < amount) {\n throw new Error('Insufficient balance');\n }\n\n const updatedBalance = {\n ...balance,\n availableBalance: balance.availableBalance - amount,\n inPredictions: balance.inPredictions + amount,\n lastUpdated: new Date().toISOString()\n };\n\n await kvStore.storeEntity('USER_BALANCE', userId, updatedBalance);\n return updatedBalance;\n } catch (error) {\n console.error(`Error updating balance for prediction, user ${userId}:`, error);\n throw error;\n }\n },\n\n // Update user balance when a prediction is resolved\n async updateBalanceForResolvedPrediction(\n userId: string,\n originalAmount: number,\n winnings: number = 0\n ) {\n try {\n const balance: any = await this.getUserBalance(userId);\n if (!balance) return null;\n\n const updatedBalance = {\n ...balance,\n availableBalance: balance.availableBalance + winnings,\n inPredictions: balance.inPredictions - originalAmount,\n lastUpdated: new Date().toISOString()\n };\n\n await kvStore.storeEntity('USER_BALANCE', userId, updatedBalance);\n return updatedBalance;\n } catch (error) {\n console.error(`Error updating balance for resolved prediction, user ${userId}:`, error);\n throw error;\n }\n },\n\n // Add funds to user balance (for deposit functionality)\n async addFunds(userId: string, amount: number) {\n try {\n const balance: any = await this.getUserBalance(userId);\n if (!balance) return null;\n\n const updatedBalance = {\n ...balance,\n availableBalance: balance.availableBalance + amount,\n totalDeposited: balance.totalDeposited + amount,\n lastUpdated: new Date().toISOString()\n };\n\n await kvStore.storeEntity('USER_BALANCE', userId, updatedBalance);\n return updatedBalance;\n } catch (error) {\n console.error(`Error adding funds for user ${userId}:`, error);\n throw error;\n }\n },\n\n // Withdraw funds from user balance\n async withdrawFunds(userId: string, amount: number) {\n try {\n const balance: any = await this.getUserBalance(userId);\n if (!balance) return null;\n\n // Check if user has enough balance\n if (balance.availableBalance < amount) {\n throw new Error('Insufficient balance');\n }\n\n const updatedBalance = {\n ...balance,\n availableBalance: balance.availableBalance - amount,\n totalWithdrawn: balance.totalWithdrawn + amount,\n lastUpdated: new Date().toISOString()\n };\n\n await kvStore.storeEntity('USER_BALANCE', userId, updatedBalance);\n return updatedBalance;\n } catch (error) {\n console.error(`Error withdrawing funds for user ${userId}:`, error);\n throw error;\n }\n },\n\n // Force refresh a user's balance from the blockchain\n async refreshBalance(userId: string) {\n try {\n const stacksAddress = await this.getUserStacksAddress(userId);\n if (!stacksAddress) {\n throw new Error(`No Stacks address found for user ${userId}`);\n }\n\n const contractBalance = await this.fetchContractBalance(stacksAddress);\n const balance = await kvStore.getEntity('USER_BALANCE', userId) || {\n userId,\n availableBalance: 0,\n totalDeposited: 0,\n totalWithdrawn: 0,\n inPredictions: 0,\n lastUpdated: new Date().toISOString()\n };\n\n const updatedBalance = {\n ...balance,\n availableBalance: contractBalance,\n stacksAddress,\n lastUpdated: new Date().toISOString()\n };\n\n await kvStore.storeEntity('USER_BALANCE', userId, updatedBalance);\n return updatedBalance;\n } catch (error) {\n console.error(`Error refreshing balance for user ${userId}:`, error);\n throw error;\n }\n }\n};\n\nconst kvStore = {\n async getEntity(collection: string, id: string) {\n console.log({ collection, id });\n // Get the user's Stacks address\n const stacksAddress = await userBalanceStore.getUserStacksAddress(id);\n\n let availableBalance = 0;\n if (stacksAddress) {\n availableBalance = await userBalanceStore.fetchContractBalance(stacksAddress);\n }\n\n const balance = {\n userId: id,\n availableBalance,\n totalDeposited: 0,\n totalWithdrawn: 0,\n inPredictions: 0,\n lastUpdated: new Date().toISOString(),\n stacksAddress\n };\n return balance;\n },\n\n async storeEntity(collection: string, id: string, entity: any) {\n console.log({ collection, id, entity });\n return null;\n }\n};"]}