@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
"use strict";var e,t,E=require("ethers"),n=require("axios"),_=require("@gala-chain/connect"),i=require("zod"),r=require("bignumber.js"),s=require("@gala-chain/api"),A=require("uuid"),a=require("socket.io-client"),o=require("events"),R=require("process"),I=require("net"),N=require("tls"),T=require("timers"),c=require("stream"),u=require("crypto"),l=require("zlib"),h=require("util"),O=require("url");function C(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}!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"}(e||(e={}));class D extends Error{constructor(e,t,E){super(t),this.type=e,this.originalError=E,this.name="AuthError"}}class d{constructor(t){if(this.wallet=t.wallet,this.messagePrefix=t.messagePrefix||"Create a GalaChain Wallet",""===t.messagePrefix)throw new D(e.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(t){throw new D(e.SIGNATURE_FAILED,"Failed to generate signature for authentication",t instanceof Error?t:new Error(String(t)))}}getAddress(){return this.formatAddress(this.wallet.address)}getEthereumAddress(){return this.wallet.address}getPrivateKey(){if(!this.wallet.privateKey)throw new D(e.WALLET_NOT_CONNECTED,"Wallet private key not available for @gala-chain signing");return this.wallet.privateKey}formatAddress(t){const E=t.replace(/^0x/i,"");if(!/^[a-fA-F0-9]{40}$/.test(E))throw new D(e.INVALID_ADDRESS,`Invalid Ethereum address format: ${t}`);return`eth|${E}`}async signMessage(t){try{return{message:t,signature:await this.wallet.signMessage(t),address:this.wallet.address,timestamp:Date.now()}}catch(t){const E=t instanceof Error?t.message:String(t);throw new D(e.SIGNATURE_FAILED,E,t instanceof Error?t:new Error(String(t)))}}async generateAuthHeaders(t,E){try{const e=Date.now(),n=`${this.messagePrefix} ${E.toUpperCase()} ${t} ${e}`,_=await this.wallet.signMessage(n);return{"x-signature":_,"x-address":this.formatAddress(this.wallet.address),"x-message":n,"x-timestamp":e.toString()}}catch(t){throw new D(e.SIGNATURE_FAILED,"Failed to generate authentication headers",t instanceof Error?t:new Error(String(t)))}}async signTypedData(t,E,n){try{return await this.wallet.signTypedData(t,E,n)}catch(t){throw new D(e.SIGNATURE_FAILED,"Failed to sign typed data",t instanceof Error?t:new Error(String(t)))}}async generateCustomSignature(t){if(!t||"string"!=typeof t||0===t.trim().length)throw new D(e.SIGNATURE_FAILED,"Custom message must be a non-empty string");try{const e=await this.wallet.signMessage(t);return{message:t,signature:e,address:this.formatAddress(this.wallet.address),timestamp:Date.now()}}catch(t){throw new D(e.SIGNATURE_FAILED,"Failed to generate custom message signature",t instanceof Error?t:new Error(String(t)))}}validateWallet(){if(!this.wallet)throw new D(e.WALLET_NOT_CONNECTED,"Wallet is required for authentication");if(!this.wallet.address)throw new D(e.WALLET_NOT_CONNECTED,"Wallet address is not available");if(!this.wallet.privateKey&&!this.wallet.signMessage)throw new D(e.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"}(t||(t={}));class g{constructor(e){this.levelPriority={[t.DEBUG]:0,[t.INFO]:1,[t.WARN]:2,[t.ERROR]:3},this.debugEnabled=e.debug,this.context=e.context||"SDK",this.minLevel=e.minLevel||(e.debug?t.DEBUG:t.INFO)}debug(e,E){this.log(t.DEBUG,e,E)}info(e,E){this.log(t.INFO,e,E)}warn(e,E){this.log(t.WARN,e,E)}error(e,E){this.log(t.ERROR,e,E)}log(e,E,n){if(this.levelPriority[e]<this.levelPriority[this.minLevel])return;if(e===t.DEBUG&&!this.debugEnabled)return;const _=`[${(new Date).toISOString()}] [${this.context}] [${e}]`,i=this.getConsoleMethod(e);void 0!==n?n instanceof Error?i(`${_} ${E}`,n.message,n.stack):i(`${_} ${E}`,n):i(`${_} ${E}`)}getConsoleMethod(e){switch(e){case t.DEBUG:return console.debug;case t.INFO:return console.info;case t.WARN:return console.warn;case t.ERROR:return console.error;default:return console.log}}child(e){return new g({debug:this.debugEnabled,context:`${this.context}:${e}`,minLevel:this.minLevel})}isDebugEnabled(){return this.debugEnabled&&this.levelPriority[t.DEBUG]>=this.levelPriority[this.minLevel]}}function S(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 B{constructor(e,t={}){this.auth=e,this.debug=t.debug??!1,this.logger=new g({debug:this.debug,context:"HttpClient"}),this.axios=n.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:S(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=_.SigningType.SIGN_TYPED_DATA){const n=this.auth.getPrivateKey(),i=new _.SigningClient(n);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 M="Token name is required and must be a string",f=e=>`Could not find vault address for token: ${e}`;class L extends Error{constructor(e,t,E){super(e),this.field=t,this.code=E,this.name="ValidationError"}}class U extends Error{constructor(e,t,E){super(e),this.statusCode=t,this.originalError=E,this.name="NetworkError"}}class w extends Error{constructor(e,t){super(e),this.field=t,this.name="ConfigurationError"}}class p extends Error{constructor(e,t,E){super(e),this.transactionId=t,this.code=E,this.name="TransactionError"}}function F(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 L(`Page must be a number between ${n} and ${_}`,"page","INVALID_PAGE");if("number"!=typeof t||t<i||t>r)throw new L(`Limit must be a number between ${i} and ${r}`,"limit","INVALID_LIMIT")}const G={ETH_ADDRESS:/^0x[0-9a-fA-F]{40}$/,BACKEND_ADDRESS:/^eth\|[0-9a-fA-F]{40}$/};function m(e){return"string"==typeof e&&e.trim().length>0}function P(e){return!(!e||"string"!=typeof e)&&(G.ETH_ADDRESS.test(e)||G.BACKEND_ADDRESS.test(e))}function b(e){return e.startsWith("0x")?`eth|${e.slice(2)}`:e}const Q=i.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"),V=i.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=i.z.string().min(1,"Token description is required").max(500,"Token description must be at most 500 characters"),Y=i.z.string().min(1,"Token name must be at least 1 character").max(50,"Token name must be at most 50 characters"),v=i.z.string().min(1,"Search query must be at least 1 character").max(100,"Search query must be at most 100 characters"),W=i.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"),H=i.z.string().regex(G.BACKEND_ADDRESS,"Address must be in format: eth|[40-hex-chars]"),k=i.z.string().regex(G.ETH_ADDRESS,"Invalid Ethereum address format"),x=i.z.string().refine(e=>G.BACKEND_ADDRESS.test(e)||G.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),K=i.z.string().refine(e=>G.BACKEND_ADDRESS.test(e)||/^service\|Token\$Unit\$[A-Z0-9]+\$eth:[0-9a-fA-F]{40}\$launchpad$/.test(e),"Invalid vault address format"),X=i.z.string().regex(/^\d+(\.\d+)?$/,"Must be a valid decimal number").refine(e=>parseFloat(e)>0,"Amount must be greater than zero"),z=i.z.string().regex(/^\d+(\.\d+)?$/,"Must be a valid decimal number").refine(e=>parseFloat(e)>=0,"Amount must be zero or greater"),j=i.z.string().regex(/^(?!0+(\.0+)?$)\d+(\.\d+)?$/,"Amount must be a positive, non-zero number"),J=i.z.string().url("Must be a valid URL").regex(/^https?:\/\//,"URL must start with http:// or https://"),Z=i.z.string().optional().refine(e=>!e||/^https?:\/\/.+\..+/.test(e),"Must be a valid URL if provided"),q=i.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 $(e=100){return i.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 ee=$(100),te=$(20),Ee=$(20),ne=i.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"),_e=i.z.string().max(255,"Filename must be at most 255 characters"),ie=i.z.enum(["image/png","image/jpg","image/jpeg","image/gif","image/webp","image/svg+xml"]),re=i.z.string().min(1,"Comment message is required").max(500,"Comment must be at most 500 characters"),se=i.z.string().datetime("Must be a valid ISO 8601 date string"),Ae=i.z.number().int("Timestamp must be an integer").min(0,"Timestamp must be non-negative"),ae=i.z.string().regex(/^0x[a-fA-F0-9]{64}$/,"Private key must be format: 0x + 64 hex characters"),oe=i.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"),Re=i.z.string().regex(/^galaconnect-operation-[a-z0-9-]+$/,"Unique key must be format: galaconnect-operation-{unique-id}"),Ie=i.z.object({websiteUrl:Z,telegramUrl:Z,twitterUrl:Z}).refine(e=>e.websiteUrl||e.telegramUrl||e.twitterUrl,"At least one social URL (website, telegram, or twitter) is required"),Ne=i.z.string().min(1,"Token category must not be empty").default("Unit"),Te=i.z.string().min(1,"Token collection must not be empty").default("Token"),ce=i.z.object({minFeePortion:X,maxFeePortion:X}),ue=i.z.object({tokenName:Q,tokenSymbol:V,tokenDescription:y,tokenImage:i.z.union([i.z.instanceof(File),i.z.instanceof(Buffer),i.z.string().url("Token image must be a valid URL")]).optional(),preBuyQuantity:z.default("0"),websiteUrl:Z,telegramUrl:Z,twitterUrl:Z,tokenCategory:Ne,tokenCollection:Te,reverseBondingCurveConfiguration:ce.optional(),privateKey:ae.optional()}),le=i.z.object({file:i.z.union([i.z.instanceof(File),i.z.instanceof(Buffer)]),tokenName:Q}),he=i.z.enum(["recent","popular"]),Oe=i.z.object({tokenName:Q.optional(),symbol:V.optional()}).refine(e=>e.tokenName||e.symbol,"At least one of tokenName or symbol is required"),Ce=i.z.enum(["NATIVE","MEME"]),De=i.z.enum(["IN","OUT"]),de=i.z.object({from:i.z.number().int("From timestamp must be an integer").min(173e6,"From timestamp must be at least 173000000"),to:i.z.number().int("To timestamp must be an integer").min(173e6,"To timestamp must be at least 173000000"),resolution:i.z.number().int("Resolution must be an integer").min(1,"Resolution must be at least 1"),tokenName:Q}),ge=i.z.object({tokenName:Q,slippageToleranceFactor:i.z.number().min(0).max(1).optional(),maxAcceptableReverseBondingCurveFeeSlippageFactor:i.z.number().min(0).max(1).optional(),privateKey:ae.optional()}),Se=[".png",".jpg",".jpeg",".gif",".webp",".svg"],Be=i.z.object({file:i.z.union([i.z.instanceof(File),i.z.instanceof(Buffer)]),name:_e,size:ne,type:ie}),Me=i.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"),fe=i.z.instanceof(Buffer).refine(e=>e.length>=1&&e.length<=10485760,"Buffer size must be between 1 byte and 10MB"),Le=i.z.union([Me,fe]),Ue=i.z.enum([".png",".jpg",".jpeg",".gif",".webp",".svg"]),we=_e.refine(e=>{const t=e.slice(e.lastIndexOf(".")).toLowerCase();return Se.includes(t)},`Filename must end with one of: ${Se.join(", ")}`),pe=i.z.object({page:q,limit:ee}),Fe=i.z.object({page:q,limit:te}),Ge=i.z.object({page:q,limit:Ee}),me=i.z.object({page:q,limit:$(50)}),Pe=pe.extend({type:i.z.enum(["recent","popular"]).optional(),tokenName:i.z.string().min(1).max(50).optional(),search:i.z.string().min(1).max(100).optional()}),be=Fe.extend({tokenName:i.z.string().min(1).max(50).optional(),search:i.z.string().min(1).max(100).optional()}),Qe=Ge.extend({tradeType:i.z.enum(["BUY","SELL"]).optional(),tokenName:i.z.string().min(1).max(50).optional(),userAddress:i.z.string().regex(/^(0x[a-fA-F0-9]{40}|eth\|[a-fA-F0-9]{40})$/).optional(),startDate:i.z.string().datetime().optional(),endDate:i.z.string().datetime().optional(),sortOrder:i.z.enum(["ASC","DESC"]).default("DESC")}),Ve=i.z.object({page:i.z.number().int().min(1),limit:i.z.number().int().min(1),total:i.z.number().int().min(0),totalPages:i.z.number().int().min(0),hasNext:i.z.boolean(),hasPrevious:i.z.boolean()});const ye=i.z.enum(["all","DEFI","ASSET"]),Ye=Fe.extend({type:ye.optional(),address:x.optional(),search:v.optional(),tokenName:Y.optional()}),ve=i.z.object({walletAddress:x,amount:j}),We=i.z.object({address:x.optional(),refresh:i.z.boolean().optional()}),He=i.z.object({profileImage:i.z.string(),fullName:W,address:x,privateKey:ae.optional()}),ke=i.z.object({file:i.z.union([i.z.instanceof(File),i.z.instanceof(Buffer)]),address:x.optional(),privateKey:ae.optional()}),xe=i.z.object({address:x,tokenId:i.z.union([i.z.string(),i.z.object({collection:i.z.string(),category:i.z.string(),type:i.z.string(),additionalKey:i.z.string()}),i.z.object({collection:i.z.string(),category:i.z.string(),type:i.z.string(),additionalKey:i.z.string(),instance:i.z.string()})]).optional(),tokenName:Y.optional()}).refine(e=>void 0!==e.tokenId||void 0!==e.tokenName,"At least one token identifier (tokenId or tokenName) is required"),Ke=i.z.enum(["buy","sell"]),Xe=i.z.enum(["BUY","SELL"]),ze=i.z.object({tradeType:Ke,tokenAmount:X,vaultAddress:K,userAddress:x,slippageTolerance:X.optional(),deadline:i.z.number().int().positive().optional()}),je=i.z.object({tokenSymbol:V,nativeTokenQuantity:X,expectedToken:X,maxAcceptableReverseBondingCurveFee:z.default("0").optional()}),Je=i.z.object({tokenSymbol:V,tokenQuantity:X,expectedNativeToken:X,maxAcceptableReverseBondingCurveFee:z.default("0").optional()}),Ze=Ge.extend({tokenName:Y.optional()}),qe=i.z.object({page:i.z.number().int().min(1).max(1e3).default(1).optional(),limit:i.z.number().int().min(1).max(20).default(10).optional()}),$e=i.z.enum(["NATIVE","MEME"]),et=i.z.enum(["IN","OUT"]),tt=i.z.object({type:$e,method:et,vaultAddress:K,amount:X}),Et=i.z.object({nativeTokenQuantity:X}),nt=i.z.object({vaultAddress:K}),_t=i.z.object({minFeePortion:X,maxFeePortion:X});function it(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 rt=it(Q),st=it(V),At=it(y),at=it(x),ot=it(K),Rt=it(X),It=it(j),Nt=it(W),Tt=it(v),ct=it(Y),ut=it(ue),lt=it(Ie),ht=it(le),Ot=it(Oe),Ct=it(Ye),Dt=it(ve),dt=it(We),gt=it(He),St=it(ke),Bt=it(xe),Mt=it(ze),ft=it(je),Lt=it(Je),Ut=it(Ze),wt=it(qe),pt=it(tt),Ft=it(Et),Gt=it(nt);function mt(e,t){throw new L(e.join("; "),t,"VALIDATION_ERROR")}function Pt(e){const t=rt(e);!t.success&&t.errors&&mt(t.errors,"tokenName")}function bt(e){const t=Pe.safeParse(e);t.success||mt(t.error.errors.map(e=>e.message),"pagination")}function Qt(e){const t=Ot(e);!t.success&&t.errors&&mt(t.errors,"options")}function Vt(e){const t=pt(e);!t.success&&t.errors&&mt(t.errors,"options")}function yt(e){const t=de.safeParse(e);t.success||mt(t.error.errors.map(e=>e.message),"options")}function Yt(e){const t=x.safeParse(e);if(!t.success)throw new L("Ethereum address must be 40 hex characters (with or without 0x prefix)","ethereumAddress","INVALID_FORMAT");return t.data}function vt(e,t,E=!0){if(!e||""===e.trim())throw new L(`${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 L(`${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 L(`${t} must be a valid numeric string. Received: "${e}"`,t,"INVALID_NUMERIC_STRING");if(!isFinite(n))throw new L(`${t} must be a finite number. Cannot be Infinity or -Infinity.`,t,"INVALID_NUMERIC_STRING");if(n<0)throw new L(`${t} must be non-negative. Received: "${e}"`,t,"INVALID_NUMERIC_STRING");if(!E&&0===n)throw new L(`${t} must be greater than zero. Received: "${e}"`,t,"INVALID_NUMERIC_STRING")}var Wt=Object.freeze({__proto__:null,normalizeAddressInput:function(e){if(!e)return;const t=x.safeParse(e);if(!t.success)throw new L(`Invalid address format: ${e}. Must be either "0x..." (Ethereum) or "eth|..." (GalaChain) format`,"address","INVALID_FORMAT");return t.data},toBackendAddressFormat:Yt,validateCheckPoolOptions:Qt,validateGetAmountOptions:Vt,validateGetGraphOptions:yt,validateNumericString:vt,validatePagination:bt,validateTokenName:Pt});function Ht(e,t){return new L(`Token "${e}" not found. Please verify the token name is correct.`,"tokenName","TOKEN_NOT_FOUND")}function kt(e,t){const E=t||e.charAt(0).toUpperCase()+e.slice(1);return new L(`${E} is required`,e,"REQUIRED_FIELD")}function xt(e,t,E){const n=E||e.charAt(0).toUpperCase()+e.slice(1);return new L(`${n} must be ${t}`,e,"INVALID_FORMAT")}function Kt(e,t,E){return new U(e,t,E)}function Xt(e,t){return new w(e,t)}function zt(e,t,E){return new p(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 Jt(e,t){return{hasNext:e<t,hasPrevious:e>1}}function Zt(e,t,E=!1){const n=!0===e.error||200!==e.status,_=E&&!e.data;if(n||_)throw new Error(e.message||t)}const qt="/launchpad/upload-image",$t="/launchpad/fetch-pool",eE="/launchpad/check-pool",tE="/launchpad/get-graph-data",EE="/holders",nE="/launchpad/get-badge/",_E="/trade/",iE="/token/commment",rE="/token/commment",sE="/user/profile",AE="/user/profile",aE="/user/token-list",oE="/user/token-hold",RE="/user/transfer-faucets";function IE(e,t){return"string"==typeof e[t]}function NE(e,t){return void 0===e[t]||"string"==typeof e[t]}function TE(e,t){return void 0===e[t]||"number"==typeof e[t]}function cE(e){return void 0===e.calculateAmountMode||"local"===e.calculateAmountMode||"external"===e.calculateAmountMode}function uE(e){if(!e||"object"!=typeof e)return!1;const t=e;return IE(t,"tokenName")&&TE(t,"from")&&TE(t,"to")&&TE(t,"resolution")}class lE{constructor(e,t=!1){this.http=e,this.logger=new g({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=S(t),n=await this.http.get($t,E);Zt(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&&bt({page:t,limit:E}),e.tokenName&&Pt(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){Qt(e),e.tokenName&&Pt(e.tokenName);const t=S(e),E=await this.http.get(eE,t);Zt(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(!uE(e))throw new L("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(Pt(t),!E||!n||!_)throw new L("Graph options (from, to, resolution) are required","options","MISSING_GRAPH_OPTIONS");const i={tokenName:t,from:E,to:n,resolution:_};yt(i);const r=S(i),s=await this.http.get(tE,r);return Zt(s,"Failed to fetch graph data",!0),{dataPoints:s.data}}async fetchTokenDistribution(e){if(!e)throw kt("tokenName","Token name");Pt(e);const t=await this.resolveTokenNameToVault(e);if(!t)throw new L(f(e),"tokenName","VAULT_NOT_FOUND");const E=encodeURIComponent(t),n=await this.http.get(`${EE}/${E}`);Zt(n,"Failed to fetch token distribution",!0);const _=n.data;if(!Array.isArray(_))throw Kt("Invalid API response: expected array of holders",n.status);for(const e of _){if(!e.owner||"string"!=typeof e.owner)throw Kt("Invalid holder data: missing or invalid owner field",n.status);if(!e.quantity||"string"!=typeof e.quantity)throw Kt("Invalid holder data: missing or invalid quantity field",n.status);const t=parseFloat(e.quantity);if(isNaN(t)||!isFinite(t))throw Kt(`Invalid holder quantity: "${e.quantity}"`,n.status)}const i=_.reduce((e,t)=>e.plus(t.quantity),new r(0));return{holders:_.map(e=>{const t=new r(e.quantity),E=i.isZero()?0:t.dividedBy(i).multipliedBy(100).toNumber();return{address:e.owner,balance:e.quantity,percentage:E}}),totalSupply:i.toFixed(),totalHolders:_.length,lastUpdated:new Date}}async fetchTokenBadges(e){if(!e)throw kt("tokenName","Token name");Pt(e);const t=await this.http.get(nE,{tokenName:e});return Zt(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 hE(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 S(i)}const OE={PAGINATION:{MIN_PAGE:1,MAX_PAGE:1e3,MIN_LIMIT:1,MAX_LIMIT:20}};class CE{constructor(e,t=!1){this.http=e,this.logger=new g({debug:t,context:"TradeService"})}async fetchTrades(e){if(!function(e){if(!e||"object"!=typeof e)return!1;const t=e;return IE(t,"tokenName")&&(void 0===t.tradeType||"buy"===t.tradeType||"sell"===t.tradeType)&&NE(t,"userAddress")&&TE(t,"page")&&TE(t,"limit")}(e))throw new L("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(!m(t))throw new L("Token name is required and must be a non-empty string","tokenName","INVALID_TOKEN_NAME");F(_,i,OE);const a=function(e,t,E){return hE({tokenName:e,page:t,limit:E},{stringifyFields:["page","limit"]})}(t,_,i),o=await this.http.get(_E,a),R=(I=o.data)?Array.isArray(I)?I:I.trades:[];var I;const N=jt(o,{page:_,limit:i}),T=Jt(N.page,N.totalPages);return{trades:R,...N,...T}}}const DE=new g({debug:!1,context:"DateUtils"});function dE(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 gE={PAGINATION:{MIN_PAGE:1,MAX_PAGE:1e3,MIN_LIMIT:1,MAX_LIMIT:50},CONTENT:{MIN_LENGTH:1,MAX_LENGTH:500}};class SE{constructor(e,t,E=!1){this.http=e,this.poolService=t,this.logger=new g({debug:E,context:"CommentService"})}async fetchComments(e){if(!function(e){if(!e||"object"!=typeof e)return!1;const t=e;return IE(t,"tokenName")&&TE(t,"page")&&TE(t,"limit")}(e))throw new L("Invalid options provided. Expected { tokenName: string, page?: number, limit?: number }","options","INVALID_OPTIONS");const{tokenName:t,page:E=1,limit:n=10}=e;if(!m(t))throw new L("Token name is required and must be a non-empty string","tokenName","INVALID_TOKEN_NAME");F(E,n,gE);const _=await this.poolService.resolveTokenNameToVault(t);if(!_)throw Ht(t);const i=hE({vaultAddress:_,page:E,limit:n},{stringifyFields:["page","limit"]}),r=await this.http.get(iE,i);Zt(r,"Failed to fetch comments");return{comments:r.data.comments.map(e=>({...e,createdAt:dE(e.createdAt)})),total:r.data.count}}async postComment(e){if(!function(e){if(!e||"object"!=typeof e)return!1;const t=e;return IE(t,"tokenName")&&IE(t,"content")}(e))throw new L("Invalid options provided. Expected { tokenName: string, content: string }","options","INVALID_OPTIONS");const{tokenName:t,content:E}=e;if(!m(t))throw new L("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>=gE.CONTENT.MIN_LENGTH&&t.length<=gE.CONTENT.MAX_LENGTH}(E))throw new L(`Comment content must be between ${gE.CONTENT.MIN_LENGTH} and ${gE.CONTENT.MAX_LENGTH} characters`,"content","INVALID_CONTENT");const n=await this.poolService.resolveTokenNameToVault(t);if(!n)throw Ht(t);const _={userAddress:this.http.getAddress(),vaultAddress:n,content:E};Zt(await this.http.post(rE,_),"Failed to create comment")}}function BE(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 xt("file","a File object (browser) or Buffer (Node.js)");{const _=new Blob([e],{type:"image/png"});n.append(t,_,E)}}return n}const ME={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 fE(e){return!(!e||"string"!=typeof e)&&ME.USER_ADDRESS.PATTERN.test(e)}const LE="Update profile";class UE{constructor(e){this.http=e}async fetchProfile(e){const t=e??this.http.getAddress();if(!fE(t))throw new L("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");const E={userAddress:t};return await this.http.get(sE,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(LE),_={address:n.address,message:LE,publickey:n.ethereumAddress,sign:n.signature};Zt(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=BE(e.file,"image",E),_=await this.http.request({method:"POST",url:`${qt}?tokenName=${encodeURIComponent(t)}`,data:n,headers:{}});return Zt(_,"Image upload failed"),"string"==typeof _.data?_.data:""}catch(e){if(e instanceof L)throw e;throw new L(`Profile image upload failed: ${e instanceof Error?e.message:"Unknown error"}`,"file","UPLOAD_FAILED")}}async fetchTokenList(e){return this.buildFetchRequest(aE,e,{includeType:!0,errorMessage:"Failed to fetch token list"})}async fetchTokensHeld(e){return this.buildFetchRequest(oE,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},_=hE(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,_);Zt(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=Jt(A.page,A.totalPages);return{tokens:r,...A,...a}}validateGetTokenListOptions(e){if(F(e.page,e.limit,ME),void 0!==e.address&&!fE(e.address))throw new L("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>=ME.SEARCH.MIN_LENGTH&&t.length<=ME.SEARCH.MAX_LENGTH))throw new L(`Search query must be between ${ME.SEARCH.MIN_LENGTH} and ${ME.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>=ME.TOKEN_NAME.MIN_LENGTH&&E.length<=ME.TOKEN_NAME.MAX_LENGTH))throw new L(`Token name must be between ${ME.TOKEN_NAME.MIN_LENGTH} and ${ME.TOKEN_NAME.MAX_LENGTH} characters`,"tokenName","INVALID_TOKEN_NAME")}validateUpdateProfileData(e){if(!fE(e.address))throw new L("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");if(!((t=e.fullName)&&"string"==typeof t&&t.length>=ME.PROFILE.FULL_NAME.MIN_LENGTH&&t.length<=ME.PROFILE.FULL_NAME.MAX_LENGTH&&ME.PROFILE.FULL_NAME.ALPHABETS_ONLY_PATTERN.test(t)))throw new L(`Full name must be between ${ME.PROFILE.FULL_NAME.MIN_LENGTH} and ${ME.PROFILE.FULL_NAME.MAX_LENGTH} characters`,"fullName","INVALID_FULL_NAME");var t}validateUploadProfileImageOptions(e){if(e.address&&!fE(e.address))throw new L("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS")}}class wE extends Error{constructor(e,t,E){super(e),this.filename=t,this.mimeType=E,this.name="FileValidationError"}}function pE(e,t,E){if(!e)throw new wE("File is required",t,E);if("undefined"!=typeof File&&e instanceof File){const t=Me.safeParse(e);if(!t.success){const E=t.error.errors.map(e=>e.message).join("; ");throw new wE(E,e.name,e.type)}return}if(Buffer.isBuffer(e)){if(!t)throw new wE("Filename is required when uploading Buffer objects",t,E);const n=fe.safeParse(e);if(!n.success){const e=n.error.errors.map(e=>e.message).join("; ");throw new wE(e,t,E)}if(t.length>255)throw new wE(`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 wE(`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 wE(`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 wE(`File extension "${i}" does not match MIME type "${E}"`,t,E);return}throw new wE("File must be a File object (browser) or Buffer (Node.js)",t,E)}class FE{constructor(e,t=!1){this.http=e,this.logger=new g({debug:t,context:"ImageService"})}async uploadImageByTokenName(e){const{tokenName:t,options:E}=e;Pt(t);const n=`${t}.png`;pE(E.file,n,"image/png");try{const e=`${E.tokenName??t}.png`,n=BE(E.file,"image",e),_=await this.http.request({method:"POST",url:`${qt}?tokenName=${encodeURIComponent(E.tokenName??t)}`,data:n,headers:{}});return Zt(_,"Image upload failed"),"string"==typeof _.data?_.data:""}catch(e){if(e instanceof Error&&e.message.includes("FormData"))throw Xt("File upload failed: FormData not supported in this environment. Ensure you have proper polyfills for Node.js environments.","FormData");throw e}}}class GE{constructor(e,t=!1){this.http=e,this.logger=new g({debug:t,context:"FaucetService"})}async transferFaucets(e){this.validateTransferFaucetsData(e);const t={userAddress:e.walletAddress,amount:e.amount};Zt(await this.http.post(RE,t),"Faucet transfer failed")}validateTransferFaucetsData(e){if(!fE(e.walletAddress))throw new L("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");if(!(t=e.amount)||"string"!=typeof t||!ME.FAUCET_AMOUNT.POSITIVE_NON_ZERO_DECIMAL.test(t))throw new L("Amount must be a positive decimal string greater than zero","amount","INVALID_AMOUNT");var t}}class mE{constructor(e,t=!1){this.http=e,this.poolService=new lE(e,t),this.tradeService=new CE(e,t),this.commentService=new SE(e,this.poolService,t),this.userService=new UE(e),this.imageService=new FE(e,t),this.faucetService=new GE(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 Pt(e)}}const PE={MAX_UNIQUE_KEY_LENGTH:64,UNIQUE_KEY_PATTERN:/^(galaswap-operation-|galaconnect-operation-)/,TOKEN_NAME_PATTERN:/^[a-zA-Z0-9]+$/};var bE;!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"}(bE||(bE={}));class QE extends Error{constructor(e,t,E){super(e),this.type=t,this.details=E,this.name="TransferError"}}class VE{static validateAmount(e){if(parseFloat(e)<=0)throw new QE("Transfer amount must be positive",bE.INVALID_AMOUNT,{amount:e})}static validateUniqueKey(e){if(e){if(e.length>PE.MAX_UNIQUE_KEY_LENGTH)throw new L(`Unique key too long. Maximum length: ${PE.MAX_UNIQUE_KEY_LENGTH}`);if(!PE.UNIQUE_KEY_PATTERN.test(e))throw new QE('Invalid unique key format. Must start with "galaswap-operation-" or "galaconnect-operation-"',bE.INVALID_AMOUNT,{uniqueKey:e})}}}class yE extends _.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 YE{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 t=e.replace("0x","");return`eth|${E.ethers.getAddress(`0x${t}`).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 vE(e){if("string"==typeof e){const t=e.split("|");if(t.length<4)throw new L(`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 L(`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 L("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 L(`Invalid tokenId type: ${typeof e}. Expected string, TokenClassKey, or TokenInstanceKey`,"tokenId","INVALID_TOKEN_ID_TYPE")}var WE=Object.freeze({__proto__:null,normalizeToTokenInstanceKey:vE});function HE(e){return e instanceof Error}function kE(e){return HE(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 xE(e){return"object"==typeof e&&null!==e&&"message"in e&&("response"in e||"request"in e||"config"in e)}const KE="gala-transfer-successful",XE="token-transfer-successful",zE="transfer-successful-no-id";class jE{constructor(e,t,E,n=!1){this.http=e,this.wallet=t,this.tokenResolver=E,this.signatureHelper=new YE(t),this.logger=new g({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 Kt(`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 Kt(`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 L("Invalid fetch pool details data: missing required fields","data","INVALID_TYPE");var t;if(!e.vaultAddress||"string"!=typeof e.vaultAddress)throw new L("Vault address is required and must be a string","vaultAddress","INVALID_VAULT_ADDRESS");if(!e.vaultAddress.startsWith("service|Token$Unit$"))throw new L("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 Kt(`Failed to fetch token balance from GalaChain: ${kE(e)}`,void 0,HE(e)?e:void 0)}}async transferGala(e){this.validateTransferGalaData(e);try{const t=b(e.recipientAddress),E=b(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=b(e.to),E=b(this.wallet.address);let n;if(e.tokenId)n=vE(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 QE("Must provide either tokenId or tokenName for token identification",bE.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=await this.signatureHelper.signTransferToken(_.toSigningPayload()),r=new yE({..._.toSigningPayload(),signedPayload:i});this.logger.debug("[DEBUG] Full Transfer Request Payload:",JSON.stringify(r,null,2));const s=await this.http.post("/api/asset/token-contract/TransferToken",r);return this.logger.debug("[DEBUG] Token transfer response:",JSON.stringify(s,null,2)),this.extractTransactionIdFromResponse(s,"token")}catch(t){throw this.handleTransferError(t,"Token transfer failed",e)}}async resolveTokenClassKey(e){try{const t=await this.tokenResolver.resolveTokenClassKey(e);return this.logger.debug(`[DEBUG] Token class key resolution for '${e}':`,JSON