@gala-chain/launchpad-sdk
Version:
TypeScript SDK for Gala Launchpad Backend API - Production-ready DeFi token launchpad integration with wallet-based authentication, GalaChain trading, and comprehensive user operations. 100% tested (22/22 endpoints working).
1 lines • 956 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("ethers"),require("axios"),require("@gala-chain/connect"),require("zod"),require("bignumber.js"),require("@gala-chain/api"),require("uuid"),require("socket.io-client"),require("events"),require("process"),require("net"),require("tls"),require("timers"),require("stream"),require("crypto"),require("zlib"),require("util"),require("url")):"function"==typeof define&&define.amd?define(["exports","ethers","axios","@gala-chain/connect","zod","bignumber.js","@gala-chain/api","uuid","socket.io-client","events","process","net","tls","timers","stream","crypto","zlib","util","url"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).GalaLaunchpadSDK={},e.ethers,e.axios,e.GalaChainConnect,e.z,e.BigNumber,e.GalaChainAPI,e.uuid,e.io,e.require$$0$3,e.require$$0$2,e.require$$0$6,e.require$$2$1,e.require$$1$1,e.require$$2$2,e.require$$0$1,e.require$$0$4,e.require$$1$2,e.require$$0$5)}(this,function(e,t,E,n,_,i,r,s,A,a,o,R,I,N,T,c,u,l,h){"use strict";function O(e,t){return t.forEach(function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach(function(E){if("default"!==E&&!(E in e)){var n=Object.getOwnPropertyDescriptor(t,E);Object.defineProperty(e,E,n.get?n:{enumerable:!0,get:function(){return t[E]}})}})}),Object.freeze(e)}if("undefined"==typeof File){const{File:e}=require("web-file-polyfill");global.File=e}var C,D;!function(e){e.WALLET_NOT_CONNECTED="WALLET_NOT_CONNECTED",e.SIGNATURE_FAILED="SIGNATURE_FAILED",e.INVALID_ADDRESS="INVALID_ADDRESS",e.MESSAGE_GENERATION_FAILED="MESSAGE_GENERATION_FAILED"}(C||(C={}));class d extends Error{constructor(e,t,E){super(t),this.type=e,this.originalError=E,this.name="AuthError"}}class g{constructor(e){if(this.wallet=e.wallet,this.messagePrefix=e.messagePrefix||"Create a GalaChain Wallet",""===e.messagePrefix)throw new d(C.SIGNATURE_FAILED,"Message prefix cannot be empty");this.validateWallet()}async generateSignature(){try{const e=Date.now(),t=`${this.messagePrefix} ${e}`,E=await this.wallet.signMessage(t);return{message:t,signature:E,address:this.formatAddress(this.wallet.address),timestamp:e}}catch(e){throw new d(C.SIGNATURE_FAILED,"Failed to generate signature for authentication",e instanceof Error?e:new Error(String(e)))}}getAddress(){return this.formatAddress(this.wallet.address)}getEthereumAddress(){return this.wallet.address}getPrivateKey(){if(!this.wallet.privateKey)throw new d(C.WALLET_NOT_CONNECTED,"Wallet private key not available for @gala-chain signing");return this.wallet.privateKey}formatAddress(e){const t=e.replace(/^0x/i,"");if(!/^[a-fA-F0-9]{40}$/.test(t))throw new d(C.INVALID_ADDRESS,`Invalid Ethereum address format: ${e}`);return`eth|${t}`}async signMessage(e){try{return{message:e,signature:await this.wallet.signMessage(e),address:this.wallet.address,timestamp:Date.now()}}catch(e){const t=e instanceof Error?e.message:String(e);throw new d(C.SIGNATURE_FAILED,t,e instanceof Error?e:new Error(String(e)))}}async generateAuthHeaders(e,t){try{const E=Date.now(),n=`${this.messagePrefix} ${t.toUpperCase()} ${e} ${E}`,_=await this.wallet.signMessage(n);return{"x-signature":_,"x-address":this.formatAddress(this.wallet.address),"x-message":n,"x-timestamp":E.toString()}}catch(e){throw new d(C.SIGNATURE_FAILED,"Failed to generate authentication headers",e instanceof Error?e:new Error(String(e)))}}async signTypedData(e,t,E){try{return await this.wallet.signTypedData(e,t,E)}catch(e){throw new d(C.SIGNATURE_FAILED,"Failed to sign typed data",e instanceof Error?e:new Error(String(e)))}}async generateCustomSignature(e){if(!e||"string"!=typeof e||0===e.trim().length)throw new d(C.SIGNATURE_FAILED,"Custom message must be a non-empty string");try{const t=await this.wallet.signMessage(e);return{message:e,signature:t,address:this.formatAddress(this.wallet.address),timestamp:Date.now()}}catch(e){throw new d(C.SIGNATURE_FAILED,"Failed to generate custom message signature",e instanceof Error?e:new Error(String(e)))}}validateWallet(){if(!this.wallet)throw new d(C.WALLET_NOT_CONNECTED,"Wallet is required for authentication");if(!this.wallet.address)throw new d(C.WALLET_NOT_CONNECTED,"Wallet address is not available");if(!this.wallet.privateKey&&!this.wallet.signMessage)throw new d(C.WALLET_NOT_CONNECTED,"Wallet must have a private key for signing messages")}}!function(e){e.DEBUG="DEBUG",e.INFO="INFO",e.WARN="WARN",e.ERROR="ERROR"}(D||(D={}));class S{constructor(e){this.levelPriority={[D.DEBUG]:0,[D.INFO]:1,[D.WARN]:2,[D.ERROR]:3},this.debugEnabled=e.debug,this.context=e.context||"SDK",this.minLevel=e.minLevel||(e.debug?D.DEBUG:D.INFO)}debug(e,t){this.log(D.DEBUG,e,t)}info(e,t){this.log(D.INFO,e,t)}warn(e,t){this.log(D.WARN,e,t)}error(e,t){this.log(D.ERROR,e,t)}log(e,t,E){if(this.levelPriority[e]<this.levelPriority[this.minLevel])return;if(e===D.DEBUG&&!this.debugEnabled)return;const n=`[${(new Date).toISOString()}] [${this.context}] [${e}]`,_=this.getConsoleMethod(e);void 0!==E?E instanceof Error?_(`${n} ${t}`,E.message,E.stack):_(`${n} ${t}`,E):_(`${n} ${t}`)}getConsoleMethod(e){switch(e){case D.DEBUG:return console.debug;case D.INFO:return console.info;case D.WARN:return console.warn;case D.ERROR:return console.error;default:return console.log}}child(e){return new S({debug:this.debugEnabled,context:`${this.context}:${e}`,minLevel:this.minLevel})}isDebugEnabled(){return this.debugEnabled&&this.levelPriority[D.DEBUG]>=this.levelPriority[this.minLevel]}}function B(e){if(!e||"object"!=typeof e)return{};const t={};for(const[E,n]of Object.entries(e))null!=n&&("string"==typeof n?t[E]=n:"number"==typeof n||"boolean"==typeof n?t[E]=n.toString():Array.isArray(n)?t[E]=n.join(","):t[E]="object"==typeof n?JSON.stringify(n):String(n));return t}class M{constructor(e,t={}){this.auth=e,this.debug=t.debug??!1,this.logger=new S({debug:this.debug,context:"HttpClient"}),this.axios=E.create({baseURL:t.baseUrl||"https://lpad-backend-dev1.defi.gala.com",timeout:t.timeout||3e4,headers:{Accept:"application/json",...t.headers}}),this.setupInterceptors()}async request(e){try{const t={method:e.method,url:e.url,data:e.data,...e.params&&{params:B(e.params)},...e.headers&&{headers:e.headers},...e.timeout&&{timeout:e.timeout}};e.data instanceof FormData&&(t.headers&&t.headers["Content-Type"]&&delete t.headers["Content-Type"],this.logger.debug("FormData detected - removing Content-Type header for multipart upload"));const E=e.data instanceof FormData?"[FormData object - multipart/form-data]":e.data;this.logger.debug("Request:",{method:e.method,url:e.url,fullUrl:`${this.axios.defaults.baseURL}${e.url}`,baseURL:this.axios.defaults.baseURL,params:t.params,data:E,isFormData:e.data instanceof FormData,contentType:t.headers?.["Content-Type"]||"not set"});const n=await this.axios.request(t);return this.logger.debug("Response:",{status:n.status,data:n.data}),n.data}catch(e){throw this.logger.error("Error:",e),e}}async get(e,t,E){return this.request({method:"GET",url:e,...t&&{params:t},...E&&{headers:E}})}async post(e,t,E){return this.request({method:"POST",url:e,data:t,...E&&{headers:E}})}async put(e,t,E){return this.request({method:"PUT",url:e,data:t,...E&&{headers:E}})}async delete(e,t,E){return this.request({method:"DELETE",url:e,...t&&{params:t},...E&&{headers:E}})}async patch(e,t,E){return this.request({method:"PATCH",url:e,data:t,...E&&{headers:E}})}getAddress(){return this.auth.getAddress()}getEthereumAddress(){return this.auth.getEthereumAddress()}async signMessage(e){return(await this.auth.signMessage(e)).signature}async signTypedData(e,t,E){return await this.auth.signTypedData(e,t,E)}async signCustomMessage(e){try{const t=await this.auth.generateCustomSignature(e);return this.logger.debug("Generated custom signature:",{message:e,address:t.address,ethereumAddress:this.auth.getEthereumAddress()}),{signature:t.signature,address:t.address,ethereumAddress:this.auth.getEthereumAddress()}}catch(e){throw this.logger.error("Custom signature generation failed:",e),new Error(`Failed to generate custom signature for message: ${e instanceof Error?e.message:"Unknown error"}`)}}async signWithGalaChain(e,t,E=n.SigningType.SIGN_TYPED_DATA){const _=this.auth.getPrivateKey(),i=new n.SigningClient(_);return await i.sign(e,t,E)}setupInterceptors(){this.requestInterceptorId=this.axios.interceptors.request.use(async e=>{try{const t=await this.auth.generateSignature();return e.headers||(e.headers={}),e.headers.Sign=t.signature,e.data instanceof FormData||(e.headers["Content-Type"]="application/json"),this.logger.debug("Added signature header:",{address:t.address,message:t.message,timestamp:t.timestamp}),e}catch(e){throw this.logger.error("Failed to add signature:",e),e}},e=>Promise.reject(e)),this.responseInterceptorId=this.axios.interceptors.response.use(e=>e,e=>{if(e.response){const t={message:e.response.data?.message||e.message,error:e.response.data?.error,statusCode:e.response.status,details:e.response.data?.details,timestamp:e.response.data?.timestamp,path:e.response.data?.path};e.launchpadError=t,this.logger.error("Backend error:",t)}else e.request?this.logger.error("Network error:",e.message):this.logger.error("Request setup error:",e.message);return Promise.reject(e)})}cleanup(){void 0!==this.requestInterceptorId&&(this.axios.interceptors.request.eject(this.requestInterceptorId),this.requestInterceptorId=void 0),void 0!==this.responseInterceptorId&&(this.axios.interceptors.response.eject(this.responseInterceptorId),this.responseInterceptorId=void 0),this.logger.debug("Interceptors cleaned up")}}const f="Token name is required and must be a string",L=e=>`Could not find vault address for token: ${e}`;class U extends Error{constructor(e,t,E){super(e),this.field=t,this.code=E,this.name="ValidationError"}}class w extends Error{constructor(e,t,E){super(e),this.statusCode=t,this.originalError=E,this.name="NetworkError"}}class p extends Error{constructor(e,t){super(e),this.field=t,this.name="ConfigurationError"}}class F extends Error{constructor(e,t,E){super(e),this.transactionId=t,this.code=E,this.name="TransactionError"}}function G(e,t,E){const{MIN_PAGE:n,MAX_PAGE:_,MIN_LIMIT:i,MAX_LIMIT:r}=E.PAGINATION;if("number"!=typeof e||e<n||e>_)throw new U(`Page must be a number between ${n} and ${_}`,"page","INVALID_PAGE");if("number"!=typeof t||t<i||t>r)throw new U(`Limit must be a number between ${i} and ${r}`,"limit","INVALID_LIMIT")}const m={ETH_ADDRESS:/^0x[0-9a-fA-F]{40}$/,BACKEND_ADDRESS:/^eth\|[0-9a-fA-F]{40}$/};function P(e){return"string"==typeof e&&e.trim().length>0}function b(e){return!(!e||"string"!=typeof e)&&(m.ETH_ADDRESS.test(e)||m.BACKEND_ADDRESS.test(e))}function Q(e){return e.startsWith("0x")?`eth|${e.slice(2)}`:e}const V=_.z.string().min(3,"Token name must be at least 3 characters").max(20,"Token name must be at most 20 characters").regex(/^[a-zA-Z0-9]{3,20}$/,"Token name can only contain letters and numbers"),y=_.z.string().min(1,"Token symbol must be at least 1 character").max(8,"Token symbol must be at most 8 characters").regex(/^[A-Z]{1,8}$/,"Token symbol must be uppercase letters only"),Y=_.z.string().min(1,"Token description is required").max(500,"Token description must be at most 500 characters"),v=_.z.string().min(1,"Token name must be at least 1 character").max(50,"Token name must be at most 50 characters"),W=_.z.string().min(1,"Search query must be at least 1 character").max(100,"Search query must be at most 100 characters"),H=_.z.string().min(1,"Full name is required").max(100,"Full name must be at most 100 characters").regex(/^[a-zA-Z\s]+$/,"Full name can only contain letters and spaces"),k=_.z.string().regex(m.BACKEND_ADDRESS,"Address must be in format: eth|[40-hex-chars]"),x=_.z.string().regex(m.ETH_ADDRESS,"Invalid Ethereum address format"),K=_.z.string().refine(e=>m.BACKEND_ADDRESS.test(e)||m.ETH_ADDRESS.test(e),"Address must be either eth|[40-hex-chars] or 0x[40-hex-chars] format").transform(e=>e.startsWith("0x")?`eth|${e.slice(2)}`:e),X=_.z.string().refine(e=>m.BACKEND_ADDRESS.test(e)||/^service\|Token\$Unit\$[A-Z0-9]+\$eth:[0-9a-fA-F]{40}\$launchpad$/.test(e),"Invalid vault address format"),z=_.z.string().regex(/^\d+(\.\d+)?$/,"Must be a valid decimal number").refine(e=>parseFloat(e)>0,"Amount must be greater than zero"),j=_.z.string().regex(/^\d+(\.\d+)?$/,"Must be a valid decimal number").refine(e=>parseFloat(e)>=0,"Amount must be zero or greater"),J=_.z.string().regex(/^(?!0+(\.0+)?$)\d+(\.\d+)?$/,"Amount must be a positive, non-zero number"),Z=_.z.string().url("Must be a valid URL").regex(/^https?:\/\//,"URL must start with http:// or https://"),q=_.z.string().optional().refine(e=>!e||/^https?:\/\/.+\..+/.test(e),"Must be a valid URL if provided"),$=_.z.number().int("Page must be an integer").min(1,"Page must be at least 1").max(1e3,"Page must be at most 1000").default(1);function ee(e=100){return _.z.number().int("Limit must be an integer").min(1,"Limit must be at least 1").max(e,`Limit must be at most ${e}`).default(10)}const te=ee(100),Ee=ee(20),ne=ee(20),_e=_.z.number().int("File size must be an integer").min(1,"File must be at least 1 byte").max(10485760,"File must be at most 10MB"),ie=_.z.string().max(255,"Filename must be at most 255 characters"),re=_.z.enum(["image/png","image/jpg","image/jpeg","image/gif","image/webp","image/svg+xml"]),se=_.z.string().min(1,"Comment message is required").max(500,"Comment must be at most 500 characters"),Ae=_.z.string().datetime("Must be a valid ISO 8601 date string"),ae=_.z.number().int("Timestamp must be an integer").min(0,"Timestamp must be non-negative"),oe=_.z.string().regex(/^0x[a-fA-F0-9]{64}$/,"Private key must be format: 0x + 64 hex characters"),Re=_.z.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/,"Transaction ID must be in UUID format"),Ie=_.z.string().regex(/^galaconnect-operation-[a-z0-9-]+$/,"Unique key must be format: galaconnect-operation-{unique-id}"),Ne=_.z.object({websiteUrl:q,telegramUrl:q,twitterUrl:q}).refine(e=>e.websiteUrl||e.telegramUrl||e.twitterUrl,"At least one social URL (website, telegram, or twitter) is required"),Te=_.z.string().min(1,"Token category must not be empty").default("Unit"),ce=_.z.string().min(1,"Token collection must not be empty").default("Token"),ue=_.z.object({minFeePortion:z,maxFeePortion:z}),le=_.z.object({tokenName:V,tokenSymbol:y,tokenDescription:Y,tokenImage:_.z.union([_.z.instanceof(File),_.z.instanceof(Buffer),_.z.string().url("Token image must be a valid URL")]).optional(),preBuyQuantity:j.default("0"),websiteUrl:q,telegramUrl:q,twitterUrl:q,tokenCategory:Te,tokenCollection:ce,reverseBondingCurveConfiguration:ue.optional(),privateKey:oe.optional()}),he=_.z.object({file:_.z.union([_.z.instanceof(File),_.z.instanceof(Buffer)]),tokenName:V}),Oe=_.z.enum(["recent","popular"]),Ce=_.z.object({tokenName:V.optional(),symbol:y.optional()}).refine(e=>e.tokenName||e.symbol,"At least one of tokenName or symbol is required"),De=_.z.enum(["NATIVE","MEME"]),de=_.z.enum(["IN","OUT"]),ge=_.z.object({from:_.z.number().int("From timestamp must be an integer").min(173e6,"From timestamp must be at least 173000000"),to:_.z.number().int("To timestamp must be an integer").min(173e6,"To timestamp must be at least 173000000"),resolution:_.z.number().int("Resolution must be an integer").min(1,"Resolution must be at least 1"),tokenName:V}),Se=_.z.object({tokenName:V,slippageToleranceFactor:_.z.number().min(0).max(1).optional(),maxAcceptableReverseBondingCurveFeeSlippageFactor:_.z.number().min(0).max(1).optional(),privateKey:oe.optional()}),Be=[".png",".jpg",".jpeg",".gif",".webp",".svg"],Me=_.z.object({file:_.z.union([_.z.instanceof(File),_.z.instanceof(Buffer)]),name:ie,size:_e,type:re}),fe=_.z.instanceof(File).refine(e=>e.size>=1&&e.size<=10485760,"File size must be between 1 byte and 10MB").refine(e=>["image/png","image/jpg","image/jpeg","image/gif","image/webp","image/svg+xml"].includes(e.type),"File must be a valid image type (PNG, JPG, JPEG, GIF, WebP, or SVG)").refine(e=>e.name.length<=255,"Filename must be at most 255 characters"),Le=_.z.instanceof(Buffer).refine(e=>e.length>=1&&e.length<=10485760,"Buffer size must be between 1 byte and 10MB"),Ue=_.z.union([fe,Le]),we=_.z.enum([".png",".jpg",".jpeg",".gif",".webp",".svg"]),pe=ie.refine(e=>{const t=e.slice(e.lastIndexOf(".")).toLowerCase();return Be.includes(t)},`Filename must end with one of: ${Be.join(", ")}`),Fe=_.z.object({page:$,limit:te}),Ge=_.z.object({page:$,limit:Ee}),me=_.z.object({page:$,limit:ne}),Pe=_.z.object({page:$,limit:ee(50)}),be=Fe.extend({type:_.z.enum(["recent","popular"]).optional(),tokenName:_.z.string().min(1).max(50).optional(),search:_.z.string().min(1).max(100).optional()}),Qe=Ge.extend({tokenName:_.z.string().min(1).max(50).optional(),search:_.z.string().min(1).max(100).optional()}),Ve=me.extend({tradeType:_.z.enum(["BUY","SELL"]).optional(),tokenName:_.z.string().min(1).max(50).optional(),userAddress:_.z.string().regex(/^(0x[a-fA-F0-9]{40}|eth\|[a-fA-F0-9]{40})$/).optional(),startDate:_.z.string().datetime().optional(),endDate:_.z.string().datetime().optional(),sortOrder:_.z.enum(["ASC","DESC"]).default("DESC")}),ye=_.z.object({page:_.z.number().int().min(1),limit:_.z.number().int().min(1),total:_.z.number().int().min(0),totalPages:_.z.number().int().min(0),hasNext:_.z.boolean(),hasPrevious:_.z.boolean()});const Ye=_.z.enum(["all","DEFI","ASSET"]),ve=Ge.extend({type:Ye.optional(),address:K.optional(),search:W.optional(),tokenName:v.optional()}),We=_.z.object({walletAddress:K,amount:J}),He=_.z.object({address:K.optional(),refresh:_.z.boolean().optional()}),ke=_.z.object({profileImage:_.z.string(),fullName:H,address:K,privateKey:oe.optional()}),xe=_.z.object({file:_.z.union([_.z.instanceof(File),_.z.instanceof(Buffer)]),address:K.optional(),privateKey:oe.optional()}),Ke=_.z.object({address:K,tokenId:_.z.union([_.z.string(),_.z.object({collection:_.z.string(),category:_.z.string(),type:_.z.string(),additionalKey:_.z.string()}),_.z.object({collection:_.z.string(),category:_.z.string(),type:_.z.string(),additionalKey:_.z.string(),instance:_.z.string()})]).optional(),tokenName:v.optional()}).refine(e=>void 0!==e.tokenId||void 0!==e.tokenName,"At least one token identifier (tokenId or tokenName) is required"),Xe=_.z.enum(["buy","sell"]),ze=_.z.enum(["BUY","SELL"]),je=_.z.object({tradeType:Xe,tokenAmount:z,vaultAddress:X,userAddress:K,slippageTolerance:z.optional(),deadline:_.z.number().int().positive().optional()}),Je=_.z.object({tokenSymbol:y,nativeTokenQuantity:z,expectedToken:z,maxAcceptableReverseBondingCurveFee:j.default("0").optional()}),Ze=_.z.object({tokenSymbol:y,tokenQuantity:z,expectedNativeToken:z,maxAcceptableReverseBondingCurveFee:j.default("0").optional()}),qe=me.extend({tokenName:v.optional()}),$e=_.z.object({page:_.z.number().int().min(1).max(1e3).default(1).optional(),limit:_.z.number().int().min(1).max(20).default(10).optional()}),et=_.z.enum(["NATIVE","MEME"]),tt=_.z.enum(["IN","OUT"]),Et=_.z.object({type:et,method:tt,vaultAddress:X,amount:z}),nt=_.z.object({nativeTokenQuantity:z}),_t=_.z.object({vaultAddress:X}),it=_.z.object({minFeePortion:z,maxFeePortion:z});function rt(e){return t=>{const E=e.safeParse(t);return{success:E.success,data:E.success?E.data:void 0,errors:E.success?void 0:E.error.errors.map(e=>e.message)}}}const st=rt(V),At=rt(y),at=rt(Y),ot=rt(K),Rt=rt(X),It=rt(z),Nt=rt(J),Tt=rt(H),ct=rt(W),ut=rt(v),lt=rt(le),ht=rt(Ne),Ot=rt(he),Ct=rt(Ce),Dt=rt(ve),dt=rt(We),gt=rt(He),St=rt(ke),Bt=rt(xe),Mt=rt(Ke),ft=rt(je),Lt=rt(Je),Ut=rt(Ze),wt=rt(qe),pt=rt($e),Ft=rt(Et),Gt=rt(nt),mt=rt(_t);function Pt(e,t){throw new U(e.join("; "),t,"VALIDATION_ERROR")}function bt(e){const t=st(e);!t.success&&t.errors&&Pt(t.errors,"tokenName")}function Qt(e){const t=be.safeParse(e);t.success||Pt(t.error.errors.map(e=>e.message),"pagination")}function Vt(e){const t=Ct(e);!t.success&&t.errors&&Pt(t.errors,"options")}function yt(e){const t=Ft(e);!t.success&&t.errors&&Pt(t.errors,"options")}function Yt(e){const t=ge.safeParse(e);t.success||Pt(t.error.errors.map(e=>e.message),"options")}function vt(e){const t=K.safeParse(e);if(!t.success)throw new U("Ethereum address must be 40 hex characters (with or without 0x prefix)","ethereumAddress","INVALID_FORMAT");return t.data}function Wt(e,t,E=!0){if(!e||""===e.trim())throw new U(`${t} cannot be empty or whitespace-only. Provide a valid numeric string or omit the parameter to auto-fetch.`,t,"INVALID_NUMERIC_STRING");if(/[eE]/.test(e))throw new U(`${t} cannot use scientific notation. Use standard decimal format (e.g., "1000" instead of "1e3").`,t,"INVALID_NUMERIC_STRING");const n=parseFloat(e);if(isNaN(n))throw new U(`${t} must be a valid numeric string. Received: "${e}"`,t,"INVALID_NUMERIC_STRING");if(!isFinite(n))throw new U(`${t} must be a finite number. Cannot be Infinity or -Infinity.`,t,"INVALID_NUMERIC_STRING");if(n<0)throw new U(`${t} must be non-negative. Received: "${e}"`,t,"INVALID_NUMERIC_STRING");if(!E&&0===n)throw new U(`${t} must be greater than zero. Received: "${e}"`,t,"INVALID_NUMERIC_STRING")}var Ht=Object.freeze({__proto__:null,normalizeAddressInput:function(e){if(!e)return;const t=K.safeParse(e);if(!t.success)throw new U(`Invalid address format: ${e}. Must be either "0x..." (Ethereum) or "eth|..." (GalaChain) format`,"address","INVALID_FORMAT");return t.data},toBackendAddressFormat:vt,validateCheckPoolOptions:Vt,validateGetAmountOptions:yt,validateGetGraphOptions:Yt,validateNumericString:Wt,validatePagination:Qt,validateTokenName:bt});function kt(e,t){return new U(`Token "${e}" not found. Please verify the token name is correct.`,"tokenName","TOKEN_NOT_FOUND")}function xt(e,t){const E=t||e.charAt(0).toUpperCase()+e.slice(1);return new U(`${E} is required`,e,"REQUIRED_FIELD")}function Kt(e,t,E){const n=E||e.charAt(0).toUpperCase()+e.slice(1);return new U(`${n} must be ${t}`,e,"INVALID_FORMAT")}function Xt(e,t,E){return new w(e,t,E)}function zt(e,t){return new p(e,t)}function jt(e,t,E){return new F(e,t,E)}function Jt(e,t){const E=e,n=Number(E.page)||t.page,_=Number(E.limit)||t.limit,i=E.data,r=Number(E.total)||Number(i?.count)||0;return{page:n,limit:_,total:r,totalPages:Math.ceil(r/_)}}function Zt(e,t){return{hasNext:e<t,hasPrevious:e>1}}function qt(e,t,E=!1){const n=!0===e.error||200!==e.status,_=E&&!e.data;if(n||_)throw new Error(e.message||t)}const $t="/launchpad/upload-image",eE="/launchpad/fetch-pool",tE="/launchpad/check-pool",EE="/launchpad/get-graph-data",nE="/holders",_E="/launchpad/get-badge/",iE="/trade/",rE="/token/commment",sE="/token/commment",AE="/user/profile",aE="/user/profile",oE="/user/token-list",RE="/user/token-hold",IE="/user/transfer-faucets";function NE(e,t){return"string"==typeof e[t]}function TE(e,t){return void 0===e[t]||"string"==typeof e[t]}function cE(e,t){return void 0===e[t]||"number"==typeof e[t]}function uE(e){return void 0===e.calculateAmountMode||"local"===e.calculateAmountMode||"external"===e.calculateAmountMode}function lE(e){if(!e||"object"!=typeof e)return!1;const t=e;return NE(t,"tokenName")&&cE(t,"from")&&cE(t,"to")&&cE(t,"resolution")}class hE{constructor(e,t=!1){this.http=e,this.logger=new S({debug:t,context:"PoolService"})}async fetchSinglePage(e){const t={page:e.page.toString(),limit:e.limit.toString()};void 0!==e.type&&(t.type=e.type),void 0!==e.tokenName&&(t.tokenName=e.tokenName),void 0!==e.search&&(t.search=e.search);const E=B(t),n=await this.http.get(eE,E);qt(n,"Failed to fetch pools",!0);const _=function(e){if(!e)return[];let t=[];if(e.tokens)if(Array.isArray(e.tokens))t=e.tokens.map(e=>({...e,createdAt:e.created_at||e.createdAt||""}));else{const E=e.tokens;t=[{...E,createdAt:E.created_at||E.createdAt||""}]}else e.pools&&Array.isArray(e.pools)&&(t=e.pools.map(e=>({...e,createdAt:e.created_at||e.createdAt||""})));return t}(n.data),i=n.data.count??n.data.total??0;return{pools:_,total:i,totalPages:e.limit>0?Math.ceil(i/e.limit):1}}async fetchMultiplePages(e){const{startPage:t,totalPages:E,pageSize:n,..._}=e,i=[];if(E&&E>=t){const e=[];for(let n=t;n<=E;n++)e.push(n);for(let t=0;t<e.length;t+=5){const E=e.slice(t,t+5).map(e=>this.fetchSinglePage({..._,page:e,limit:n}));(await Promise.all(E)).forEach(e=>{i.push(...e.pools)})}return i}let r=t,s=!0;for(;s;){const e=[];for(let t=0;t<5&&s;t++)e.push(r+t);const t=e.map(e=>this.fetchSinglePage({..._,page:e,limit:n})),E=await Promise.all(t);for(const e of E){if(0===e.pools.length){s=!1;break}i.push(...e.pools)}r+=e.length,r>100&&(s=!1)}return i}async fetchPools(e={}){const t=e.page||1,E=e.limit??10;let n;if(0!==E&&Qt({page:t,limit:E}),e.tokenName&&bt(e.tokenName),"recent"===e.type?n="RECENT":"popular"===e.type&&(n="POPULAR"),E>0&&E<=20){const _=await this.fetchSinglePage({...e.search&&{search:e.search},...e.tokenName&&{tokenName:e.tokenName},...n&&{type:n},page:t,limit:E});return{pools:_.pools,page:t,limit:E,total:_.total,totalPages:_.totalPages,hasNext:t<_.totalPages,hasPrevious:t>1}}if(0===E){const t=20,E=await this.fetchSinglePage({...e.search&&{search:e.search},...e.tokenName&&{tokenName:e.tokenName},...n&&{type:n},page:1,limit:t}),_=[...E.pools];if(E.pools.length>0){const i=await this.fetchMultiplePages({...e.search&&{search:e.search},...e.tokenName&&{tokenName:e.tokenName},...n&&{type:n},startPage:2,totalPages:E.totalPages>1?E.totalPages:null,pageSize:t});_.push(...i)}return{pools:_,page:1,limit:_.length,total:E.total||_.length,totalPages:1,hasNext:!1,hasPrevious:!1}}const _=Math.ceil(E/20),i=await this.fetchSinglePage({...e.search&&{search:e.search},...e.tokenName&&{tokenName:e.tokenName},...n&&{type:n},page:t,limit:20}),r=[...i.pools],s=Math.min(_,i.totalPages-t+1);if(s>1){const E=t+s-1,_=await this.fetchMultiplePages({...e.search&&{search:e.search},...e.tokenName&&{tokenName:e.tokenName},...n&&{type:n},startPage:t+1,totalPages:E,pageSize:20});r.push(..._)}const A=r.slice(0,E);return{pools:A,page:t,limit:E,total:i.total,totalPages:i.totalPages,hasNext:t<i.totalPages&&A.length<i.total,hasPrevious:t>1}}async fetchAllPools(e){return this.fetchPools({...e,limit:0})}async checkPool(e){Vt(e),e.tokenName&&bt(e.tokenName);const t=B(e),E=await this.http.get(tE,t);qt(E,"Failed to check pool");const n=E.data;return e.symbol?n?.isSymbolExist??!1:e.tokenName?n?.isNameExist??!1:n?.exists??!1}async isTokenNameAvailable(e){try{return!await this.checkPool({tokenName:e})}catch{return!1}}async isTokenSymbolAvailable(e){try{return!await this.checkPool({symbol:e})}catch{return!1}}async fetchVolumeData(e){if(!lE(e))throw new U("Invalid options provided. Expected { tokenName: string, from?: number, to?: number, resolution?: number }","options","INVALID_OPTIONS");const{tokenName:t,from:E,to:n,resolution:_}=e;if(bt(t),!E||!n||!_)throw new U("Graph options (from, to, resolution) are required","options","MISSING_GRAPH_OPTIONS");const i={tokenName:t,from:E,to:n,resolution:_};Yt(i);const r=B(i),s=await this.http.get(EE,r);return qt(s,"Failed to fetch graph data",!0),{dataPoints:s.data}}async fetchTokenDistribution(e){if(!e)throw xt("tokenName","Token name");bt(e);const t=await this.resolveTokenNameToVault(e);if(!t)throw new U(L(e),"tokenName","VAULT_NOT_FOUND");const E=encodeURIComponent(t),n=await this.http.get(`${nE}/${E}`);qt(n,"Failed to fetch token distribution",!0);const _=n.data;if(!Array.isArray(_))throw Xt("Invalid API response: expected array of holders",n.status);for(const e of _){if(!e.owner||"string"!=typeof e.owner)throw Xt("Invalid holder data: missing or invalid owner field",n.status);if(!e.quantity||"string"!=typeof e.quantity)throw Xt("Invalid holder data: missing or invalid quantity field",n.status);const t=parseFloat(e.quantity);if(isNaN(t)||!isFinite(t))throw Xt(`Invalid holder quantity: "${e.quantity}"`,n.status)}const r=_.reduce((e,t)=>e.plus(t.quantity),new i(0));return{holders:_.map(e=>{const t=new i(e.quantity),E=r.isZero()?0:t.dividedBy(r).multipliedBy(100).toNumber();return{address:e.owner,balance:e.quantity,percentage:E}}),totalSupply:r.toFixed(),totalHolders:_.length,lastUpdated:new Date}}async fetchTokenBadges(e){if(!e)throw xt("tokenName","Token name");bt(e);const t=await this.http.get(_E,{tokenName:e});return qt(t,"Failed to fetch token badges",!0),{volumeBadges:t.data.volumeBadge||[],engagementBadges:t.data.engagementBadge||[]}}async hasTokenBadge(e){const{tokenName:t,badgeType:E,badgeName:n}=e;try{const e=await this.fetchTokenBadges(t);if(!e)return!1;const _=("volume"===E?e.volumeBadges:e.engagementBadges).find(e=>e.badgeName===n);return _?.isActive||!1}catch{return!1}}async resolveTokenNameToVault(e){try{const t=await this.fetchPools({tokenName:e});if(t.pools&&Array.isArray(t.pools)&&t.pools.length>0)return t.pools[0].vaultAddress||null;if(t.pools&&"object"==typeof t.pools){const e=t.pools.tokens;return e?.vaultAddress||null}return null}catch{return null}}}function OE(e,t={}){const{stringifyFields:E=[],optionalFields:n=[],fieldMappings:_={}}=t,i={};for(const[t,r]of Object.entries(e)){const e=t;if(n.includes(e)&&void 0===r)continue;if(n.includes(e)&&"string"==typeof r&&0===r.trim().length)continue;const s=_[e],A=s?String(s):t;E.includes(e)?i[A]=String(r):i[A]=r}return B(i)}const CE={PAGINATION:{MIN_PAGE:1,MAX_PAGE:1e3,MIN_LIMIT:1,MAX_LIMIT:20}};class DE{constructor(e,t=!1){this.http=e,this.logger=new S({debug:t,context:"TradeService"})}async fetchTrades(e){if(!function(e){if(!e||"object"!=typeof e)return!1;const t=e;return NE(t,"tokenName")&&(void 0===t.tradeType||"buy"===t.tradeType||"sell"===t.tradeType)&&TE(t,"userAddress")&&cE(t,"page")&&cE(t,"limit")}(e))throw new U("Invalid options provided. Expected { tokenName: string, tradeType?: string, userAddress?: string, page?: number, limit?: number, startDate?: Date, endDate?: Date, sortOrder?: string }","options","INVALID_OPTIONS");const{tokenName:t,tradeType:E,userAddress:n,page:_=1,limit:i=10,startDate:r,endDate:s,sortOrder:A}=e;if(!P(t))throw new U("Token name is required and must be a non-empty string","tokenName","INVALID_TOKEN_NAME");G(_,i,CE);const a=function(e,t,E){return OE({tokenName:e,page:t,limit:E},{stringifyFields:["page","limit"]})}(t,_,i),o=await this.http.get(iE,a),R=(I=o.data)?Array.isArray(I)?I:I.trades:[];var I;const N=Jt(o,{page:_,limit:i}),T=Zt(N.page,N.totalPages);return{trades:R,...N,...T}}}const dE=new S({debug:!1,context:"DateUtils"});function gE(e,t){if(!e)return t||new Date;if(e instanceof Date)return isNaN(e.getTime())?t||new Date:e;try{const E=new Date(e);return isNaN(E.getTime())?(dE.warn(`Invalid date string received: "${e}". Using fallback.`),t||new Date):E}catch(E){return dE.warn(`Date parsing error for "${e}":`,E),t||new Date}}const SE={PAGINATION:{MIN_PAGE:1,MAX_PAGE:1e3,MIN_LIMIT:1,MAX_LIMIT:50},CONTENT:{MIN_LENGTH:1,MAX_LENGTH:500}};class BE{constructor(e,t,E=!1){this.http=e,this.poolService=t,this.logger=new S({debug:E,context:"CommentService"})}async fetchComments(e){if(!function(e){if(!e||"object"!=typeof e)return!1;const t=e;return NE(t,"tokenName")&&cE(t,"page")&&cE(t,"limit")}(e))throw new U("Invalid options provided. Expected { tokenName: string, page?: number, limit?: number }","options","INVALID_OPTIONS");const{tokenName:t,page:E=1,limit:n=10}=e;if(!P(t))throw new U("Token name is required and must be a non-empty string","tokenName","INVALID_TOKEN_NAME");G(E,n,SE);const _=await this.poolService.resolveTokenNameToVault(t);if(!_)throw kt(t);const i=OE({vaultAddress:_,page:E,limit:n},{stringifyFields:["page","limit"]}),r=await this.http.get(rE,i);qt(r,"Failed to fetch comments");return{comments:r.data.comments.map(e=>({...e,createdAt:gE(e.createdAt)})),total:r.data.count}}async postComment(e){if(!function(e){if(!e||"object"!=typeof e)return!1;const t=e;return NE(t,"tokenName")&&NE(t,"content")}(e))throw new U("Invalid options provided. Expected { tokenName: string, content: string }","options","INVALID_OPTIONS");const{tokenName:t,content:E}=e;if(!P(t))throw new U("Token name is required and must be a non-empty string","tokenName","INVALID_TOKEN_NAME");if(!function(e){if(!e||"string"!=typeof e)return!1;const t=e.trim();return t.length>=SE.CONTENT.MIN_LENGTH&&t.length<=SE.CONTENT.MAX_LENGTH}(E))throw new U(`Comment content must be between ${SE.CONTENT.MIN_LENGTH} and ${SE.CONTENT.MAX_LENGTH} characters`,"content","INVALID_CONTENT");const n=await this.poolService.resolveTokenNameToVault(t);if(!n)throw kt(t);const _={userAddress:this.http.getAddress(),vaultAddress:n,content:E};qt(await this.http.post(sE,_),"Failed to create comment")}}function ME(e,t="image",E){const n=new FormData;if("undefined"!=typeof File&&e instanceof File)n.append(t,e);else{if(!Buffer.isBuffer(e))throw Kt("file","a File object (browser) or Buffer (Node.js)");{const _=new Blob([e],{type:"image/png"});n.append(t,_,E)}}return n}const fE={PAGINATION:{MIN_PAGE:1,MAX_PAGE:1e3,MIN_LIMIT:1,MAX_LIMIT:20},USER_ADDRESS:{PATTERN:/^eth\|[0-9a-fA-F]{40}$/},TOKEN_NAME:{MIN_LENGTH:1,MAX_LENGTH:50},SEARCH:{MIN_LENGTH:1,MAX_LENGTH:100},FAUCET_AMOUNT:{POSITIVE_NON_ZERO_DECIMAL:/^(?!0+(\.0+)?$)\d+(\.\d+)?$/},PROFILE:{FULL_NAME:{MIN_LENGTH:1,MAX_LENGTH:100,ALPHABETS_ONLY_PATTERN:/^[a-zA-Z]+(?:\s[a-zA-Z]+)?$/}}};function LE(e){return!(!e||"string"!=typeof e)&&fE.USER_ADDRESS.PATTERN.test(e)}const UE="Update profile";class wE{constructor(e){this.http=e}async fetchProfile(e){const t=e??this.http.getAddress();if(!LE(t))throw new U("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");const E={userAddress:t};return await this.http.get(AE,E)}async updateProfile(e){this.validateUpdateProfileData(e);let t=e.profileImage;if(!t||""===t.trim())try{const E=await this.fetchProfile(e.address);t=E.data?.profileImage||""}catch{t=""}const E={profileImage:t,fullName:e.fullName,userAddress:e.address},n=await this.http.signCustomMessage(UE),_={address:n.address,message:UE,publickey:n.ethereumAddress,sign:n.signature};qt(await this.http.put(aE,E,_),"Profile update failed")}async uploadProfileImage(e){this.validateUploadProfileImageOptions(e);const t=e.address??this.http.getAddress();try{const E=`profile-image-${t}.png`,n=ME(e.file,"image",E),_=await this.http.request({method:"POST",url:`${$t}?tokenName=${encodeURIComponent(t)}`,data:n,headers:{}});return qt(_,"Image upload failed"),"string"==typeof _.data?_.data:""}catch(e){if(e instanceof U)throw e;throw new U(`Profile image upload failed: ${e instanceof Error?e.message:"Unknown error"}`,"file","UPLOAD_FAILED")}}async fetchTokenList(e){return this.buildFetchRequest(oE,e,{includeType:!0,errorMessage:"Failed to fetch token list"})}async fetchTokensHeld(e){return this.buildFetchRequest(RE,e,{includeType:!1,errorMessage:"Failed to fetch tokens held"})}async fetchTokensCreated(e={}){const{page:t=1,limit:E=10,search:n,tokenName:_}=e,i={type:"DEFI",address:this.http.getAddress(),page:t,limit:E};return void 0!==n&&(i.search=n),void 0!==_&&(i.tokenName=_),this.fetchTokenList(i)}async buildFetchRequest(e,t,E){this.validateGetTokenListOptions(t);const n={page:t.page,limit:t.limit,address:t.address,search:t.search,tokenName:t.tokenName},_=OE(E.includeType?{...n,type:"all"!==t.type&&t.type?t.type:"DEFI"}:n,{stringifyFields:["page","limit"],optionalFields:["address","search","tokenName"]}),i=await this.http.get(e,_);qt(i,E.errorMessage,!0);const r=(s=i.data)?Array.isArray(s)?s:s.token:[];var s;const A=Jt(i,{page:t.page||1,limit:t.limit||10}),a=Zt(A.page,A.totalPages);return{tokens:r,...A,...a}}validateGetTokenListOptions(e){if(G(e.page,e.limit,fE),void 0!==e.address&&!LE(e.address))throw new U("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");if(void 0!==e.search&&e.search.trim().length>0&&!((t=e.search)&&"string"==typeof t&&t.length>=fE.SEARCH.MIN_LENGTH&&t.length<=fE.SEARCH.MAX_LENGTH))throw new U(`Search query must be between ${fE.SEARCH.MIN_LENGTH} and ${fE.SEARCH.MAX_LENGTH} characters`,"search","INVALID_SEARCH");var t,E;if(void 0!==e.tokenName&&e.tokenName.trim().length>0&&!((E=e.tokenName)&&"string"==typeof E&&E.length>=fE.TOKEN_NAME.MIN_LENGTH&&E.length<=fE.TOKEN_NAME.MAX_LENGTH))throw new U(`Token name must be between ${fE.TOKEN_NAME.MIN_LENGTH} and ${fE.TOKEN_NAME.MAX_LENGTH} characters`,"tokenName","INVALID_TOKEN_NAME")}validateUpdateProfileData(e){if(!LE(e.address))throw new U("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");if(!((t=e.fullName)&&"string"==typeof t&&t.length>=fE.PROFILE.FULL_NAME.MIN_LENGTH&&t.length<=fE.PROFILE.FULL_NAME.MAX_LENGTH&&fE.PROFILE.FULL_NAME.ALPHABETS_ONLY_PATTERN.test(t)))throw new U(`Full name must be between ${fE.PROFILE.FULL_NAME.MIN_LENGTH} and ${fE.PROFILE.FULL_NAME.MAX_LENGTH} characters`,"fullName","INVALID_FULL_NAME");var t}validateUploadProfileImageOptions(e){if(e.address&&!LE(e.address))throw new U("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS")}}class pE extends Error{constructor(e,t,E){super(e),this.filename=t,this.mimeType=E,this.name="FileValidationError"}}function FE(e,t,E){if(!e)throw new pE("File is required",t,E);if("undefined"!=typeof File&&e instanceof File){const t=fe.safeParse(e);if(!t.success){const E=t.error.errors.map(e=>e.message).join("; ");throw new pE(E,e.name,e.type)}return}if(Buffer.isBuffer(e)){if(!t)throw new pE("Filename is required when uploading Buffer objects",t,E);const n=Le.safeParse(e);if(!n.success){const e=n.error.errors.map(e=>e.message).join("; ");throw new pE(e,t,E)}if(t.length>255)throw new pE(`Filename length ${t.length} exceeds maximum allowed length of 255 characters`,t,E);const _=["image/png","image/jpg","image/jpeg","image/gif","image/webp","image/svg+xml"];if(!_.includes(E))throw new pE(`Invalid file type "${E}" is not allowed. Allowed types: ${_.join(", ")}`,t,E);const i=function(e){if(!e)return"";const t=e.lastIndexOf(".");if(-1===t)return"";return e.substring(t).toLowerCase()}(t),r=[".png",".jpg",".jpeg",".gif",".webp",".svg"];if(!r.includes(i))throw new pE(`File extension "${i}" is not allowed. Allowed extensions: ${r.join(", ")}`,t,E);const s=function(e){switch(e.toLowerCase()){case".png":return"image/png";case".jpg":case".jpeg":return"image/jpeg";case".gif":return"image/gif";case".webp":return"image/webp";case".svg":return"image/svg+xml";default:return"application/octet-stream"}}(i);if(s!==E&&"application/octet-stream"!==s)throw new pE(`File extension "${i}" does not match MIME type "${E}"`,t,E);return}throw new pE("File must be a File object (browser) or Buffer (Node.js)",t,E)}class GE{constructor(e,t=!1){this.http=e,this.logger=new S({debug:t,context:"ImageService"})}async uploadImageByTokenName(e){const{tokenName:t,options:E}=e;bt(t);const n=`${t}.png`;FE(E.file,n,"image/png");try{const e=`${E.tokenName??t}.png`,n=ME(E.file,"image",e),_=await this.http.request({method:"POST",url:`${$t}?tokenName=${encodeURIComponent(E.tokenName??t)}`,data:n,headers:{}});return qt(_,"Image upload failed"),"string"==typeof _.data?_.data:""}catch(e){if(e instanceof Error&&e.message.includes("FormData"))throw zt("File upload failed: FormData not supported in this environment. Ensure you have proper polyfills for Node.js environments.","FormData");throw e}}}class mE{constructor(e,t=!1){this.http=e,this.logger=new S({debug:t,context:"FaucetService"})}async transferFaucets(e){this.validateTransferFaucetsData(e);const t={userAddress:e.walletAddress,amount:e.amount};qt(await this.http.post(IE,t),"Faucet transfer failed")}validateTransferFaucetsData(e){if(!LE(e.walletAddress))throw new U("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");if(!(t=e.amount)||"string"!=typeof t||!fE.FAUCET_AMOUNT.POSITIVE_NON_ZERO_DECIMAL.test(t))throw new U("Amount must be a positive decimal string greater than zero","amount","INVALID_AMOUNT");var t}}class PE{constructor(e,t=!1){this.http=e,this.poolService=new hE(e,t),this.tradeService=new DE(e,t),this.commentService=new BE(e,this.poolService,t),this.userService=new wE(e),this.imageService=new GE(e,t),this.faucetService=new mE(e,t)}async uploadImageByTokenName(e){return this.imageService.uploadImageByTokenName(e)}async fetchPools(e={}){return this.poolService.fetchPools(e)}async fetchAllPools(e){return this.poolService.fetchAllPools(e)}async checkPool(e){return this.poolService.checkPool(e)}async isTokenNameAvailable(e){return this.poolService.isTokenNameAvailable(e)}async isTokenSymbolAvailable(e){return this.poolService.isTokenSymbolAvailable(e)}async fetchVolumeData(e){return this.poolService.fetchVolumeData(e)}async fetchTokenDistribution(e){return this.poolService.fetchTokenDistribution(e)}async fetchTokenBadges(e){return this.poolService.fetchTokenBadges(e)}async hasTokenBadge(e){return this.poolService.hasTokenBadge(e)}async fetchTrades(e){return this.tradeService.fetchTrades(e)}async fetchComments(e){return this.commentService.fetchComments(e)}async postComment(e){return this.commentService.postComment(e)}async fetchProfile(e){return this.userService.fetchProfile(e)}async updateProfile(e){return this.userService.updateProfile(e)}async uploadProfileImage(e){return this.userService.uploadProfileImage(e)}async fetchTokenList(e){return this.userService.fetchTokenList(e)}async fetchTokensHeld(e){return this.userService.fetchTokensHeld(e)}async fetchTokensCreated(e={}){return this.userService.fetchTokensCreated(e)}async transferFaucets(e){return this.faucetService.transferFaucets(e)}getAddress(){return this.http.getAddress()}validateTokenName(e){return bt(e)}}const bE={MAX_UNIQUE_KEY_LENGTH:64,UNIQUE_KEY_PATTERN:/^(galaswap-operation-|galaconnect-operation-)/,TOKEN_NAME_PATTERN:/^[a-zA-Z0-9]+$/};var QE;!function(e){e.INVALID_RECIPIENT="INVALID_RECIPIENT",e.INVALID_AMOUNT="INVALID_AMOUNT",e.INSUFFICIENT_BALANCE="INSUFFICIENT_BALANCE",e.TOKEN_NOT_FOUND="TOKEN_NOT_FOUND",e.SIGNATURE_FAILED="SIGNATURE_FAILED",e.NETWORK_ERROR="NETWORK_ERROR",e.DUPLICATE_TRANSFER="DUPLICATE_TRANSFER",e.TRANSFER_LIMIT_EXCEEDED="TRANSFER_LIMIT_EXCEEDED"}(QE||(QE={}));class VE extends Error{constructor(e,t,E){super(e),this.type=t,this.details=E,this.name="TransferError"}}class yE{static validateAmount(e){if(parseFloat(e)<=0)throw new VE("Transfer amount must be positive",QE.INVALID_AMOUNT,{amount:e})}static validateUniqueKey(e){if(e){if(e.length>bE.MAX_UNIQUE_KEY_LENGTH)throw new U(`Unique key too long. Maximum length: ${bE.MAX_UNIQUE_KEY_LENGTH}`);if(!bE.UNIQUE_KEY_PATTERN.test(e))throw new VE('Invalid unique key format. Must start with "galaswap-operation-" or "galaconnect-operation-"',QE.INVALID_AMOUNT,{uniqueKey:e})}}}class YE extends n.ChainCallDTO{constructor(e){super(),this.from=e.from,this.to=e.to,this.quantity=e.quantity,this.tokenInstance=e.tokenInstance,this.uniqueKey=e.uniqueKey,e.signedPayload&&(this.signature=e.signedPayload.signature,this.domain=e.signedPayload.domain,this.types=e.signedPayload.types,e.signedPayload.prefix&&(this.prefix=e.signedPayload.prefix))}static fromTokenClassKey(e,t,E,n,_){let i;if("string"==typeof n){const e=n.split("$");if(4!==e.length)throw new Error(`Invalid token class key format: ${n}. Expected format: collection$category$type$additionalKey`);i={collection:e[0],category:e[1],type:e[2],additionalKey:e[3],instance:"0"}}else i={collection:n.collection,category:n.category,type:n.type,additionalKey:n.additionalKey,instance:"0"};return new YE({from:e,to:t,quantity:E,tokenInstance:i,uniqueKey:_||`galaconnect-operation-${Date.now()}_${Math.random().toString(36).substring(2,8)}`})}static forGALA(e,t,E,n){return new YE({from:e,to:t,quantity:E,tokenInstance:{collection:"GALA",category:"Unit",type:"none",additionalKey:"none",instance:"0"},uniqueKey:n||`galaconnect-operation-${Date.now()}_${Math.random().toString(36).substring(2,8)}`})}getTokenClassKey(){return`${this.tokenInstance.collection}$${this.tokenInstance.category}$${this.tokenInstance.type}$${this.tokenInstance.additionalKey}`}toSigningPayload(){return{from:this.from,to:this.to,quantity:this.quantity,tokenInstance:this.tokenInstance,uniqueKey:this.uniqueKey}}}class vE{constructor(e){this.wallet=e}static generateUniqueKey(){return`${Date.now()}_${Math.random().toString(36).substring(2,8)}`}async signTransferToken(e){const t={name:"GalaChain",chainId:1},E={TransferToken:[{name:"from",type:"string"},{name:"to",type:"string"},{name:"quantity",type:"string"},{name:"tokenInstance",type:"TokenInstance"},{name:"uniqueKey",type:"string"}],TokenInstance:[{name:"collection",type:"string"},{name:"category",type:"string"},{name:"type",type:"string"},{name:"additionalKey",type:"string"},{name:"instance",type:"string"}]};return{signature:await this.wallet.signTypedData(t,E,e),domain:t,types:E,signerPublicKey:this.wallet.signingKey.publicKey}}static toGalaChainAddress(e){const E=e.replace("0x","");return`eth|${t.ethers.getAddress(`0x${E}`).replace("0x","")}`}static fromGalaChainAddress(e){return e.startsWith("eth|")?e.substring(4):e}static createGALATokenInstance(){return{collection:"GALA",category:"Unit",type:"none",additionalKey:"none",instance:"0"}}static createTokenInstanceFromClassKey(e){const t=e.split("$");if(4!==t.length)throw new Error(`Invalid token class key format: ${e}. Expected format: collection$category$type$additionalKey`);return{collection:t[0],category:t[1],type:t[2],additionalKey:t[3],instance:"0"}}}function WE(e){if("string"==typeof e){const t=e.split("|");if(t.length<4)throw new U(`Invalid tokenId string format: "${e}". Expected format: "collection|category|type|additionalKey" or "collection|category|type|additionalKey|instance"`,"tokenId","INVALID_TOKEN_ID_FORMAT");if(!(t[0]&&t[1]&&t[2]&&t[3]))throw new U(`Invalid tokenId string format: "${e}". All components (collection, category, type, additionalKey) must be non-empty`,"tokenId","INVALID_TOKEN_ID_FORMAT");return{collection:t[0],category:t[1],type:t[2],additionalKey:t[3],instance:t[4]||"0"}}if("object"==typeof e&&null!==e){if(!(e.collection&&e.category&&e.type&&e.additionalKey))throw new U("Invalid tokenId object format. All fields (collection, category, type, additionalKey) are required","tokenId","INVALID_TOKEN_ID_FORMAT");return"instance"in e&&void 0!==e.instance?e:{...e,instance:"0"}}throw new U(`Invalid tokenId type: ${typeof e}. Expected string, TokenClassKey, or TokenInstanceKey`,"tokenId","INVALID_TOKEN_ID_TYPE")}var HE=Object.freeze({__proto__:null,normalizeToTokenInstanceKey:WE});function kE(e){return e instanceof Error}function xE(e){return kE(e)||function(e){return"object"==typeof e&&null!==e&&"message"in e&&"string"==typeof e.message}(e)?e.message:"string"==typeof e?e:String(e)}function KE(e){return"object"==typeof e&&null!==e&&"message"in e&&("response"in e||"request"in e||"config"in e)}const XE="gala-transfer-successful",zE="token-transfer-successful",jE="transfer-successful-no-id";class JE{constructor(e,t,E,n=!1){this.http=e,this.wallet=t,this.tokenResolver=E,this.signatureHelper=new vE(t),this.logger=new S({debug:n,context:"GalaChainService"})}async fetchPoolDetails(e){this.validateFetchPoolDetailsData(e);const t=await this.http.post("/api/asset/launchpad-contract/FetchSaleDetails",e);if(1!==t.Status)throw Xt(`Failed to fetch pool details: Status ${t.Status}`,t.Status);const E=t.Data.reverseBondingCurveConfiguration,n=E?.minFeePortion??"0",_=E?.maxFeePortion??"0",i=(await import("bignumber.js")).default,r=!new i(n).isZero()||!new i(_).isZero(),s=t.Data;return s.reverseBondingCurveMinFeePortion=n,s.reverseBondingCurveMaxFeePortion=_,s.hasReverseBondingCurveFee=r,s.isGraduated="Completed"===t.Data.saleStatus,delete s.reverseBondingCurveConfiguration,t}async fetchLaunchTokenFee(){const e=await this.http.post("/api/asset/launchpad-contract/FetchLaunchpadFeeAmount",{});if(1!==e.Status)throw Xt(`Failed to fetch launch token fee: Status ${e.Status}`,e.Status);return e.Data.feeAmount}validateFetchPoolDetailsData(e){if(!(t=e)||"object"!=typeof t||"string"!=typeof t.vaultAddress)throw new U("Invalid fetch pool details data: missing required fields","data","INVALID_TYPE");var t;if(!e.vaultAddress||"string"!=typeof e.vaultAddress)throw new U("Vault address is required and must be a string","vaultAddress","INVALID_VAULT_ADDRESS");if(!e.vaultAddress.startsWith("service|Token$Unit$"))throw new U("Vault address must be in service format: service|Token$Unit$...","vaultAddress","INVALID_VAULT_ADDRESS")}async fetchGalaBalance(e){return this.fetchTokenBalance(e)}async fetchTokenBalance(e){try{const t=await this.http.post("/api/asset/token-contract/FetchBalances",e);if(1!==t.Status||!t.Data||0===t.Data.length)return null;const E=t.Data.find(t=>t.collection===e.collection&&t.category===e.category&&t.additionalKey===e.additionalKey&&t.type===e.type);if(!E||"0"===E.quantity)return null;const n=`${E.collection}|${E.category}|${E.additionalKey}|${E.type}`;return{quantity:E.quantity,collection:E.collection,category:E.category,tokenId:n}}catch(e){throw Xt(`Failed to fetch token balance from GalaChain: ${xE(e)}`,void 0,kE(e)?e:void 0)}}async transferGala(e){this.validateTransferGalaData(e);try{const t=Q(e.recipientAddress),E=Q(this.wallet.address),n=YE.forGALA(E,t,e.amount,e.uniqueKey),_=await this.signatureHelper.signTransferToken(n.toSigningPayload()),i=new YE({...n.toSigningPayload(),signedPayload:_});this.logger.debug("[DEBUG] Full GALA Transfer Request Payload:",JSON.stringify(i,null,2));const r=await this.http.post("/api/asset/token-contract/TransferToken",i);return this.logger.debug("[DEBUG] Transfer response:",JSON.stringify(r,null,2)),this.extractTransactionIdFromResponse(r,"gala")}catch(t){throw this.handleTransferError(t,"GALA transfer failed",e)}}async transferToken(e){this.validateTransferTokenData(e);try{const t=Q(e.to),E=Q(this.wallet.address);let n;if(e.tokenId)n=WE(e.tokenId),this.logger.debug("[DEBUG] Using provided tokenId:",e.tokenId),this.logger.debug("[DEBUG] Normalized Token Instance:",JSON.stringify(n,null,2));else{if(!e.tokenName)throw new VE("Must provide either tokenId or tokenName for token identification",QE.TOKEN_NOT_FOUND);n=await this.resolveTokenInstance(e.tokenName)}const _=new YE({from:E,to:t,quantity:e.amount,tokenInstance:n,uniqueKey:e.uniqueKey||`galaconnect-operation-${Date.now()}_${Math.random().toString(36).substring(2,8)}`}),i=aw