UNPKG

@faktoryfun/core-sdk

Version:

The official SDK for interacting with Faktory tokens and DEX contracts

835 lines (834 loc) 36.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FaktorySDK = void 0; const transactions_1 = require("@stacks/transactions"); const network_1 = require("@stacks/network"); // Helper function to get network object function getNetworkObject(network) { switch (network) { case "mainnet": return network_1.STACKS_MAINNET; case "testnet": return network_1.STACKS_TESTNET; case "devnet": case "mocknet": return network_1.STACKS_DEVNET; default: throw new Error(`Unsupported network: ${network}`); } } class FaktorySDK { constructor(config) { this.SBTC_CONTRACT = { mainnet: { address: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4", name: "sbtc-token", assetName: "sbtc-token", }, testnet: { address: "STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2", name: "sbtc-token", assetName: "sbtc-token", }, devnet: { address: "STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2", name: "sbtc-token", assetName: "sbtc-token", }, mocknet: { address: "STV9K21TBFAK4KNRJXF5DFP8N7W46G4V9RJ5XDY2", name: "sbtc-token", assetName: "sbtc-token", }, }; this.network = config.network; this.apiHost = config.apiHost || (this.network === "testnet" ? "https://faktory-testnet-be.vercel.app/api" : "https://faktory-be.vercel.app/api"); this.apiKey = config.apiKey || "blablahnotsharing"; this.hiroApiKey = config.hiroApiKey; } async fetch(endpoint, options = {}) { const url = `${this.apiHost}${endpoint}`; const response = await fetch(url, { ...options, headers: { ...options.headers, Authorization: `Bearer ${this.apiKey}`, }, }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); } // New method - user handles deployment async getTokenDeployParams(input) { // Validate required fields const requiredFields = [ "symbol", "name", "description", "supply", "targetStx", "creatorAddress", "initialBuyAmount", "targetAmm", ]; for (const field of requiredFields) { if (input[field] === undefined || input[field] === null) { throw new Error(`Missing required field: ${field}`); } } if (input.supply > 1000000000) { throw new Error("Token supply cannot exceed 1 billion tokens for better relatability"); } return this.fetch("/tokens/create", { method: "POST", body: JSON.stringify(input), headers: { "Content-Type": "application/json", }, }); } // Buy params builder async getBuyParams({ dexContract, inAmount, // amount is in STX or BTC units senderAddress, slippage = 15, }) { const networkObj = getNetworkObject(this.network); const tokenInfo = await this.getTokenInfo(dexContract); // Check if token is BTC denominated const isBtcDenominated = tokenInfo.denomination === "btc"; // Convert based on denomination let ustx = isBtcDenominated ? inAmount * 100000000 // Convert to satoshis (10^8) : inAmount * 1000000; // Convert to microSTX (10^6) const [contractAddress, contractName] = dexContract.split("."); const [tokenAddress, tokenName] = tokenInfo.tokenContract.split("."); const isExternal = this.isExternalDex(contractName); const sbtcContract = this.SBTC_CONTRACT[this.network]; if (isBtcDenominated) { // For BTC-denominated tokens, we handle differently // Get buy quote - using new v7 method name const buyQuoteCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-in", // Keep same function name functionArgs: [(0, transactions_1.uintCV)(ustx)], network: networkObj, senderAddress, }); const buyQuoteJSON = (0, transactions_1.cvToJSON)(buyQuoteCV); const stxToGrad = buyQuoteJSON.value.value["stx-to-grad"]?.value; if (stxToGrad) { const maxAllowed = Math.floor(Number(stxToGrad) * 1.15); // 15% leeway if (Number(ustx) > maxAllowed) { console.log(`Buy amount (${ustx}) exceeds the recommended amount needed to graduate plus 15% leeway. Adjusting to ${maxAllowed}.`); ustx = maxAllowed; } } // Internal DEX format const quoteAmount = buyQuoteJSON.value.value["tokens-out"].value; const newStx = Number(buyQuoteJSON.value.value["new-stx"].value); const tokenBalance = buyQuoteJSON.value.value["ft-balance"]?.value; if (!tokenBalance) { throw new Error("Missing token balance from quote response"); } const slippagePercent = BigInt(100 - slippage); const minTokensOut = (BigInt(quoteAmount) * slippagePercent) / BigInt(100); const currentStxBalance = Number(buyQuoteJSON.value.value["total-stx"].value); const isLastBuy = tokenInfo.targetStx && currentStxBalance + ustx >= tokenInfo.targetStx * Math.pow(10, tokenInfo.decimals); if (!tokenInfo.targetStx) { throw new Error("Missing target STX from quote response"); } try { // v7 Post-conditions - using new human-readable format const postConditions = isLastBuy ? [ { type: "ft-postcondition", address: senderAddress, condition: "lte", amount: ustx.toString(), asset: `${sbtcContract.address}.${sbtcContract.name}::${sbtcContract.assetName}`, }, { type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: tokenBalance.toString(), asset: `${tokenAddress}.${tokenName}::${tokenInfo.symbol}`, }, { type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: (tokenInfo.targetStx * Math.pow(10, tokenInfo.decimals)).toString(), asset: `${sbtcContract.address}.${sbtcContract.name}::${sbtcContract.assetName}`, }, ] : [ { type: "ft-postcondition", address: senderAddress, condition: "lte", amount: ustx.toString(), asset: `${sbtcContract.address}.${sbtcContract.name}::${sbtcContract.assetName}`, }, { type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: minTokensOut.toString(), asset: `${tokenAddress}.${tokenName}::${tokenInfo.symbol}`, }, ]; return { contractAddress, contractName, functionName: "buy", functionArgs: [ (0, transactions_1.contractPrincipalCV)(tokenAddress, tokenName), (0, transactions_1.uintCV)(ustx), ], network: networkObj, anchorMode: transactions_1.AnchorMode.Any, postConditionMode: transactions_1.PostConditionMode.Deny, postConditions, }; } catch (error) { console.error(`Error creating post conditions:`, error); throw error; } } else { // Original STX-denominated logic with v7 updates // Get buy quote - using new v7 method name const buyQuoteCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: isExternal ? "get-buyable-tokens" : "get-in", functionArgs: [(0, transactions_1.uintCV)(ustx)], network: networkObj, senderAddress, }); const buyQuoteJSON = (0, transactions_1.cvToJSON)(buyQuoteCV); let quoteAmount; let newStx; let tokenBalance; if (isExternal) { // External DEX format quoteAmount = buyQuoteJSON.value.value["buyable-token"].value; const stxBalance = buyQuoteJSON.value.value["stx-balance"].value; const stxBuy = buyQuoteJSON.value.value["stx-buy"].value; newStx = Number(stxBalance) - Number(stxBuy); tokenBalance = buyQuoteJSON.value.value["token-balance"]?.value; // Check recommend-stx-amount limit for external DEX with 15% leeway const recommendedStxAmount = buyQuoteJSON.value.value["recommend-stx-amount"]?.value; if (recommendedStxAmount) { const maxAllowed = Math.floor(Number(recommendedStxAmount) * 1.15); // 15% leeway if (Number(ustx) > maxAllowed) { console.log(`Buy amount (${ustx}) exceeds the recommended amount plus 15% leeway. Adjusting to ${maxAllowed}.`); ustx = maxAllowed; } } } else { // Internal DEX format quoteAmount = buyQuoteJSON.value.value["tokens-out"].value; newStx = Number(buyQuoteJSON.value.value["new-stx"].value); tokenBalance = buyQuoteJSON.value.value["ft-balance"]?.value; const stxToGrad = buyQuoteJSON.value.value["stx-to-grad"]?.value; if (stxToGrad) { const maxAllowed = Math.floor(Number(stxToGrad) * 1.15); // 15% leeway if (Number(ustx) > maxAllowed) { console.log(`Buy amount (${ustx}) exceeds the remaining amount needed to graduate plus 15% leeway. Adjusting to ${maxAllowed}.`); ustx = maxAllowed; } } } if (!tokenBalance) { throw new Error("Missing token balance from quote response"); } const slippagePercent = BigInt(100 - slippage); const minTokensOut = (BigInt(quoteAmount) * slippagePercent) / BigInt(100); let currentStxBalance; if (isExternal) { currentStxBalance = Number(buyQuoteJSON.value.value["stx-balance"].value); } else { currentStxBalance = Number(buyQuoteJSON.value.value["total-stx"].value); } const isLastBuy = tokenInfo.targetStx && currentStxBalance + ustx >= tokenInfo.targetStx * Math.pow(10, tokenInfo.decimals); if (!tokenInfo.targetStx) { throw new Error("Missing target STX from quote response"); } // v7 Post-conditions - using new human-readable format const postConditions = isLastBuy ? [ { type: "stx-postcondition", address: senderAddress, condition: "lte", amount: ustx.toString(), }, { type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: tokenBalance.toString(), asset: `${tokenAddress}.${tokenName}::${tokenInfo.symbol}`, }, { type: "stx-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: (tokenInfo.targetStx * Math.pow(10, tokenInfo.decimals)).toString(), }, ] : [ { type: "stx-postcondition", address: senderAddress, condition: "lte", amount: ustx.toString(), }, { type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: minTokensOut.toString(), asset: `${tokenAddress}.${tokenName}::${tokenInfo.symbol}`, }, ]; return { contractAddress, contractName, functionName: "buy", functionArgs: [ (0, transactions_1.contractPrincipalCV)(tokenAddress, tokenName), (0, transactions_1.uintCV)(ustx), ], network: networkObj, anchorMode: transactions_1.AnchorMode.Any, postConditionMode: transactions_1.PostConditionMode.Deny, postConditions, }; } } // Sell params builder async getSellParams({ dexContract, amount, // amount is in TOKEN units senderAddress, slippage = 15, }) { const networkObj = getNetworkObject(this.network); const tokenInfo = await this.getTokenInfo(dexContract); const amountWithDecimals = BigInt(amount) * BigInt(Math.pow(10, tokenInfo.decimals)); const isBtcDenominated = tokenInfo.denomination === "btc"; const sbtcContract = this.SBTC_CONTRACT[this.network]; const [contractAddress, contractName] = dexContract.split("."); const [tokenAddress, tokenName] = tokenInfo.tokenContract.split("."); const isExternal = this.isExternalDex(contractName); // Using v7 method name const sellQuoteCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: isExternal ? "get-sellable-stx" : "get-out", functionArgs: [(0, transactions_1.uintCV)(amountWithDecimals)], network: networkObj, senderAddress, }); const sellQuoteJSON = (0, transactions_1.cvToJSON)(sellQuoteCV); const quoteAmount = sellQuoteJSON.value.value["stx-out"].value; const slippagePercent = BigInt(100 - slippage); const minStxOut = (BigInt(quoteAmount) * slippagePercent) / BigInt(100); // v7 Post-conditions const postConditions = [ { type: "ft-postcondition", address: senderAddress, condition: "lte", amount: amountWithDecimals.toString(), asset: `${tokenAddress}.${tokenName}::${tokenInfo.symbol}`, }, isBtcDenominated ? { type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: minStxOut.toString(), asset: `${sbtcContract.address}.${sbtcContract.name}::${sbtcContract.assetName}`, } : { type: "stx-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: minStxOut.toString(), }, ]; return { contractAddress, contractName, functionName: "sell", functionArgs: [ (0, transactions_1.contractPrincipalCV)(tokenAddress, tokenName), (0, transactions_1.uintCV)(amountWithDecimals), ], network: networkObj, anchorMode: transactions_1.AnchorMode.Any, postConditionMode: transactions_1.PostConditionMode.Deny, postConditions, }; } isExternalDex(contractName) { return !contractName.endsWith("faktory-dex"); } // Read-only functions - updated to use v7 method names async getIn(dexContract, senderAddress, stx // amount in STX units ) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = dexContract.split("."); const isExternal = this.isExternalDex(contractName); const ustx = stx * 1000000; // Convert to microSTX const result = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: isExternal ? "get-buyable-tokens" : "get-in", functionArgs: [(0, transactions_1.uintCV)(ustx)], network: networkObj, senderAddress, }); return (0, transactions_1.cvToJSON)(result); } async getOut(dexContract, senderAddress, amount // amount in TOKEN units ) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = dexContract.split("."); const isExternal = this.isExternalDex(contractName); const tokenInfo = await this.getTokenInfo(dexContract); const amountWithDecimals = amount * Math.pow(10, tokenInfo.decimals); const result = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: isExternal ? "get-sellable-stx" : "get-out", functionArgs: [(0, transactions_1.uintCV)(amountWithDecimals)], network: networkObj, senderAddress, }); return (0, transactions_1.cvToJSON)(result); } async getOpen(dexContract, senderAddress) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = dexContract.split("."); const result = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-open", functionArgs: [], network: networkObj, senderAddress, }); return (0, transactions_1.cvToJSON)(result); } async getVerifiedTokens(options) { const url = new URL("/tokens", this.apiHost); const params = new URLSearchParams({ verified: "true" }); if (options?.search) params.append("search", options.search); if (options?.sortOrder) params.append("sortOrder", options.sortOrder); if (options?.page) params.append("page", options.page.toString()); if (options?.limit) params.append("limit", options.limit.toString()); if (options?.daoOnly) params.append("daoOnly", "true"); return this.fetch(url.pathname + "?" + params.toString(), { method: "GET" }); } async getDaoTokens(options) { return this.getVerifiedTokens({ ...options, daoOnly: true, }); } async getTokenInfo(dexContract) { const response = await this.fetch(`/tokens/${dexContract}`); return { symbol: response.data.symbol, decimals: response.data.decimals, targetStx: response.data.targetStx, tokenContract: response.data.tokenContract, denomination: response.data.denomination || "btc", }; } async verifyTransfer(tokenAddress) { return this.fetch(`/tokens/verify-transfer?token_address=${tokenAddress}`, { method: "GET" }); } async getToken(dexContract) { return this.fetch(`/tokens/${dexContract}`, { method: "GET", }); } async getTokenTrades(tokenContract) { if (!tokenContract) { throw new Error("Token contract is required"); } return this.fetch(`/tokens/trades/${tokenContract}`, { method: "GET", }); } // ===== PRE-LAUNCH METHODS ===== // Helper to get seat price based on contract type getSeatPrice(contractType) { // Helico: 6,900 sats per seat (200 total seats) // AI DAOs: 20,000 sats per seat (20 total seats) // Meme tokens: 69,000 sats per seat (20 total seats) switch (contractType) { case "helico": return 6900; case "dao": return 20000; case "meme": default: return 69000; } } // Get seat limits based on contract type getSeatLimits(contractType) { const limits = { helico: { TOTAL_SEATS: 200, MIN_USERS: 100, MAX_SEATS_PER_USER: 7 }, dao: { TOTAL_SEATS: 20, MIN_USERS: 10, MAX_SEATS_PER_USER: 7 }, meme: { TOTAL_SEATS: 20, MIN_USERS: 10, MAX_SEATS_PER_USER: 7 }, }; return limits[contractType]; } // Helper to detect contract type from total seats detectContractTypeFromSeats(totalSeats) { if (totalSeats === 200) return "helico"; if (totalSeats === 20) return "meme"; // Default to meme for 20 seats return "meme"; } // Enhanced contract type detection with helico support static detectContractType(prelaunchContract, tokenInfo) { const contractName = prelaunchContract.split(".")[1]; // Check for helico first (special case with 200 seats) if (tokenInfo?.preHash === "helico" || contractName.includes("helico")) { return "helico"; } // Check for DAO indicators if (contractName.includes("ai") || contractName.includes("dao") || tokenInfo?.daoToken) { return "dao"; } // Default to meme return "meme"; } // Enhanced pricing info static getSeatPricing(contractType = "meme") { const prices = { helico: { sats: 6900, btc: 0.000069, description: "0.00006900 BTC per seat (Helico - 200 seats total)", totalSeats: 200, minUsers: 100, }, dao: { sats: 20000, btc: 0.0002, description: "0.00020000 BTC per seat (AI DAO - 20 seats total)", totalSeats: 20, minUsers: 10, }, meme: { sats: 69000, btc: 0.00069, description: "0.00069000 BTC per seat (Meme Token - 20 seats total)", totalSeats: 20, minUsers: 10, }, }; return { contractType, ...prices[contractType], maxSeatsPerUser: 7, usd: null, }; } // Buy seats in pre-launch (buy-up-to function) - Enhanced with backend logic async getBuySeatsParams({ prelaunchContract, seatCount, senderAddress, contractType, tokenInfo, // Add optional token info for enhanced detection }) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = prelaunchContract.split("."); const sbtcContract = this.SBTC_CONTRACT[this.network]; // Enhanced contract type detection using token info const detectedType = contractType || FaktorySDK.detectContractType(prelaunchContract, tokenInfo); const seatLimits = this.getSeatLimits(detectedType); // Get contract status to understand current state const statusCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-contract-status", functionArgs: [], network: networkObj, senderAddress, }); const statusJSON = (0, transactions_1.cvToJSON)(statusCV); const isDistributionPeriod = statusJSON.value.value["is-distribution-period"].value; if (isDistributionPeriod) { throw new Error("Pre-launch period has ended, distribution has started"); } // Get user info to check current seats owned const userInfoCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-user-info", functionArgs: [(0, transactions_1.principalCV)(senderAddress)], network: networkObj, senderAddress, }); const userInfoJSON = (0, transactions_1.cvToJSON)(userInfoCV); const currentSeats = Number(userInfoJSON.value.value["seats-owned"].value); // Get remaining seats const remainingSeatsCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-remaining-seats", functionArgs: [], network: networkObj, senderAddress, }); const remainingSeats = Number((0, transactions_1.cvToJSON)(remainingSeatsCV).value.value["remainin-seats"].value); // Get total seats taken and users (mimicking backend logic) const contractStatusData = statusJSON.value.value; const totalSeatsTaken = Number(contractStatusData["total-seats-taken"].value); const totalUsers = Number(contractStatusData["total-users"].value); // Calculate max seats allowed using backend logic const seatsRemaining = seatLimits.TOTAL_SEATS - totalSeatsTaken; const usersRemaining = Math.max(0, seatLimits.MIN_USERS - totalUsers); const maxPossible = Math.max(0, seatsRemaining - usersRemaining + 1); const maxSeatsAllowed = Math.min(maxPossible, seatLimits.MAX_SEATS_PER_USER - currentSeats); if (seatCount > maxSeatsAllowed) { throw new Error(`Cannot buy ${seatCount} seats. Maximum additional seats allowed: ${maxSeatsAllowed}`); } if (seatCount > remainingSeats) { throw new Error(`Cannot buy ${seatCount} seats. Only ${remainingSeats} seats remaining.`); } // Calculate cost based on detected contract type const PRICE_PER_SEAT = this.getSeatPrice(detectedType); const totalCost = seatCount * PRICE_PER_SEAT; // Check if this purchase will complete the pre-launch const willCompleteLaunch = remainingSeats === seatCount; // Post-conditions for buy-up-to const postConditions = [ { type: "ft-postcondition", address: senderAddress, condition: "lte", amount: totalCost.toString(), asset: `${sbtcContract.address}.${sbtcContract.name}::${sbtcContract.assetName}`, }, ]; // Add special post condition for the last seat purchase if (willCompleteLaunch) { const totalAccumulatedBtc = seatLimits.TOTAL_SEATS * PRICE_PER_SEAT; postConditions.push({ type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "gte", amount: totalAccumulatedBtc.toString(), asset: `${sbtcContract.address}.${sbtcContract.name}::${sbtcContract.assetName}`, }); } return { contractAddress, contractName, functionName: "buy-up-to", functionArgs: [(0, transactions_1.uintCV)(seatCount)], network: networkObj, anchorMode: transactions_1.AnchorMode.Any, postConditionMode: transactions_1.PostConditionMode.Deny, postConditions, estimatedCost: totalCost, // Return for UI display currentSeats, maxAdditionalSeats: maxSeatsAllowed, detectedType, willCompleteLaunch, // New: indicates if this purchase completes the pre-launch remainingSeats, // New: for UI display }; } // Refund seats from pre-launch async getRefundParams({ prelaunchContract, senderAddress, contractType = "meme", }) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = prelaunchContract.split("."); const sbtcContract = this.SBTC_CONTRACT[this.network]; // Get contract status to ensure we're still in pre-launch const statusCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-contract-status", functionArgs: [], network: networkObj, senderAddress, }); const statusJSON = (0, transactions_1.cvToJSON)(statusCV); const isDistributionPeriod = statusJSON.value.value["is-distribution-period"].value; if (isDistributionPeriod) { throw new Error("Cannot refund after distribution has started"); } // Get user's current seats const userInfoCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-user-info", functionArgs: [(0, transactions_1.principalCV)(senderAddress)], network: networkObj, senderAddress, }); const userInfoJSON = (0, transactions_1.cvToJSON)(userInfoCV); const userSeats = Number(userInfoJSON.value.value["seats-owned"].value); if (userSeats === 0) { throw new Error("No seats owned to refund"); } // Calculate refund amount based on contract type const PRICE_PER_SEAT = this.getSeatPrice(contractType); const refundAmount = userSeats * PRICE_PER_SEAT; // Post-conditions for Pre-launch contract - user should receive sBTC back const postConditions = [ { type: "ft-postcondition", address: `${contractAddress}.${contractName}`, condition: "lte", amount: refundAmount.toString(), asset: `${sbtcContract.address}.${sbtcContract.name}::${sbtcContract.assetName}`, }, ]; return { contractAddress, contractName, functionName: "refund", functionArgs: [], network: networkObj, anchorMode: transactions_1.AnchorMode.Any, postConditionMode: transactions_1.PostConditionMode.Deny, postConditions, refundAmount, seatsToRefund: userSeats, }; } // Get pre-launch contract status and info async getPrelaunchStatus(prelaunchContract, senderAddress) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = prelaunchContract.split("."); // Get contract status const statusCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-contract-status", functionArgs: [], network: networkObj, senderAddress, }); // Get user info const userInfoCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-user-info", functionArgs: [(0, transactions_1.principalCV)(senderAddress)], network: networkObj, senderAddress, }); // Get remaining seats const remainingSeatsCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-remaining-seats", functionArgs: [], network: networkObj, senderAddress, }); // Get max seats allowed const maxSeatsCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-max-seats-allowed", functionArgs: [], network: networkObj, senderAddress, }); // Get seat holders const seatHoldersCV = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "get-seat-holders", functionArgs: [], network: networkObj, senderAddress, }); return { status: (0, transactions_1.cvToJSON)(statusCV), userInfo: (0, transactions_1.cvToJSON)(userInfoCV), remainingSeats: (0, transactions_1.cvToJSON)(remainingSeatsCV), maxSeatsAllowed: (0, transactions_1.cvToJSON)(maxSeatsCV), seatHolders: (0, transactions_1.cvToJSON)(seatHoldersCV), }; } // Claim vested tokens from pre-launch async getClaimParams({ prelaunchContract, tokenContract, senderAddress, }) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = prelaunchContract.split("."); const [tokenAddress, tokenName] = tokenContract.split("."); // ULTRA SIMPLE - No status checks, no post-conditions // Let the contract handle everything return { contractAddress, contractName, functionName: "claim", functionArgs: [(0, transactions_1.contractPrincipalCV)(tokenAddress, tokenName)], network: networkObj, anchorMode: transactions_1.AnchorMode.Any, postConditionMode: transactions_1.PostConditionMode.Allow, // Allow mode - no restrictions claimableAmount: 0, // Contract will determine seatsOwned: 0, // Contract will determine }; } // Additional methods to add to the FaktorySDK class // Trigger fee airdrop for pre-launch participants async getTriggerFeeAirdropParams({ prelaunchContract, senderAddress, }) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = prelaunchContract.split("."); // Simple - no status checks, let contract handle validation return { contractAddress, contractName, functionName: "trigger-fee-airdrop", functionArgs: [], network: networkObj, anchorMode: transactions_1.AnchorMode.Any, postConditionMode: transactions_1.PostConditionMode.Allow, // Allow mode - no restrictions }; } // Check if market is open (DEX is active, pre-launch complete) async isMarketOpen(prelaunchContract, senderAddress) { const networkObj = getNetworkObject(this.network); const [contractAddress, contractName] = prelaunchContract.split("."); const result = await (0, transactions_1.fetchCallReadOnlyFunction)({ contractAddress, contractName, functionName: "is-market-open", functionArgs: [], network: networkObj, senderAddress, }); return (0, transactions_1.cvToJSON)(result); } } exports.FaktorySDK = FaktorySDK;