@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 • 115 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("ethers"),require("axios"),require("@gala-chain/connect"),require("zod"),require("@gala-chain/api"),require("bignumber.js"),require("uuid"),require("socket.io-client")):"function"==typeof define&&define.amd?define(["exports","ethers","axios","@gala-chain/connect","zod","@gala-chain/api","bignumber.js","uuid","socket.io-client"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).GalaLaunchpadSDK={},e.ethers,e.axios,e.GalaChainConnect,e.z,e.GalaChainAPI,e.BigNumber,e.uuid,e.io)}(this,function(e,t,a,n,r,s,o,i,c){"use strict";var l,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"}(l||(l={}));class u extends Error{constructor(e,t,a){super(t),this.type=e,this.originalError=a,this.name="AuthError"}}class h{constructor(e){if(this.wallet=e.wallet,this.messagePrefix=e.messagePrefix||"Create a GalaChain Wallet",""===e.messagePrefix)throw new u(l.SIGNATURE_FAILED,"Message prefix cannot be empty");this.validateWallet()}async generateSignature(){try{const e=Date.now(),t=`${this.messagePrefix} ${e}`,a=await this.wallet.signMessage(t);return{message:t,signature:a,address:this.formatAddress(this.wallet.address),timestamp:e}}catch(e){throw new u(l.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}formatAddress(e){const t=e.replace(/^0x/i,"");if(!/^[a-fA-F0-9]{40}$/.test(t))throw new u(l.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 u(l.SIGNATURE_FAILED,t,e instanceof Error?e:new Error(String(e)))}}async generateAuthHeaders(e,t){try{const a=Date.now(),n=`${this.messagePrefix} ${t.toUpperCase()} ${e} ${a}`,r=await this.wallet.signMessage(n);return{"x-signature":r,"x-address":this.formatAddress(this.wallet.address),"x-message":n,"x-timestamp":a.toString()}}catch(e){throw new u(l.SIGNATURE_FAILED,"Failed to generate authentication headers",e instanceof Error?e:new Error(String(e)))}}async signTypedData(e,t,a){try{return await this.wallet.signTypedData(e,t,a)}catch(e){throw new u(l.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 u(l.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 u(l.SIGNATURE_FAILED,"Failed to generate custom message signature",e instanceof Error?e:new Error(String(e)))}}validateWallet(){if(!this.wallet)throw new u(l.WALLET_NOT_CONNECTED,"Wallet is required for authentication");if(!this.wallet.address)throw new u(l.WALLET_NOT_CONNECTED,"Wallet address is not available");if(!this.wallet.privateKey&&!this.wallet.signMessage)throw new u(l.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 g{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,a){if(this.levelPriority[e]<this.levelPriority[this.minLevel])return;if(e===d.DEBUG&&!this.debugEnabled)return;const n=`[${(new Date).toISOString()}] [${this.context}] [${e}]`,r=this.getConsoleMethod(e);void 0!==a?a instanceof Error?r(`${n} ${t}`,a.message,a.stack):r(`${n} ${t}`,a):r(`${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 g({debug:this.debugEnabled,context:`${this.context}:${e}`,minLevel:this.minLevel})}isDebugEnabled(){return this.debugEnabled&&this.levelPriority[d.DEBUG]>=this.levelPriority[this.minLevel]}}function m(e){const t={};for(const[a,n]of Object.entries(e))null!=n&&("string"==typeof n?t[a]=n:"number"==typeof n||"boolean"==typeof n?t[a]=n.toString():Array.isArray(n)?t[a]=n.join(","):t[a]="object"==typeof n?JSON.stringify(n):String(n));return t}class p{constructor(e,t={}){this.auth=e,this.debug=t.debug??!1,this.logger=new g({debug:this.debug,context:"HttpClient"}),this.axios=a.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:m(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 a=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:a,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,a){return this.request({method:"GET",url:e,...t&&{params:t},...a&&{headers:a}})}async post(e,t,a){return this.request({method:"POST",url:e,data:t,...a&&{headers:a}})}async put(e,t,a){return this.request({method:"PUT",url:e,data:t,...a&&{headers:a}})}async delete(e,t,a){return this.request({method:"DELETE",url:e,...t&&{params:t},...a&&{headers:a}})}async patch(e,t,a){return this.request({method:"PATCH",url:e,data:t,...a&&{headers:a}})}getAddress(){return this.auth.getAddress()}getEthereumAddress(){return this.auth.getEthereumAddress()}async signMessage(e){return(await this.auth.signMessage(e)).signature}async signTypedData(e,t,a){return await this.auth.signTypedData(e,t,a)}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,a=n.SigningType.SIGN_TYPED_DATA){const r=this.auth.wallet.privateKey;if(!r)throw new Error("Wallet private key not available for @gala-chain signing");const s=new n.SigningClient(r);return await s.sign(e,t,a)}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",y=e=>`Could not find vault address for token: ${e}`;class A extends Error{constructor(e,t,a){super(e),this.field=t,this.code=a,this.name="ValidationError"}}class w extends Error{constructor(e,t,a){super(e),this.statusCode=t,this.originalError=a,this.name="NetworkError"}}class v extends Error{constructor(e,t){super(e),this.field=t,this.name="ConfigurationError"}}class k extends Error{constructor(e,t,a){super(e),this.transactionId=t,this.code=a,this.name="TransactionError"}}function T(e,t,a){const{MIN_PAGE:n,MAX_PAGE:r,MIN_LIMIT:s,MAX_LIMIT:o}=a.PAGINATION;if("number"!=typeof e||e<n||e>r)throw new A(`Page must be a number between ${n} and ${r}`,"page","INVALID_PAGE");if("number"!=typeof t||t<s||t>o)throw new A(`Limit must be a number between ${s} and ${o}`,"limit","INVALID_LIMIT")}const b={ETH_ADDRESS:/^0x[0-9a-fA-F]{40}$/,BACKEND_ADDRESS:/^eth\|[0-9a-fA-F]{40}$/};function E(e){return"string"==typeof e&&e.trim().length>0}function N(e){return!(!e||"string"!=typeof e)&&(b.ETH_ADDRESS.test(e)||b.BACKEND_ADDRESS.test(e))}function S(e){return e.startsWith("0x")?`eth|${e.slice(2)}`:e}const I=r.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"),D=r.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"),F=r.z.string().min(1,"Token description is required").max(500,"Token description must be at most 500 characters"),C=r.z.string().min(1,"Token name must be at least 1 character").max(50,"Token name must be at most 50 characters"),$=r.z.string().min(1,"Search query must be at least 1 character").max(100,"Search query must be at most 100 characters"),_=r.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"),P=r.z.string().regex(b.BACKEND_ADDRESS,"Address must be in format: eth|[40-hex-chars]"),O=r.z.string().regex(b.ETH_ADDRESS,"Invalid Ethereum address format"),L=r.z.string().refine(e=>b.BACKEND_ADDRESS.test(e)||b.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),U=r.z.string().refine(e=>b.BACKEND_ADDRESS.test(e)||/^service\|Token\$Unit\$[A-Z0-9]+\$eth:[0-9a-fA-F]{40}\$launchpad$/.test(e),"Invalid vault address format"),x=r.z.string().regex(/^\d+(\.\d+)?$/,"Must be a valid decimal number").refine(e=>parseFloat(e)>0,"Amount must be greater than zero"),R=r.z.string().regex(/^\d+(\.\d+)?$/,"Must be a valid decimal number").refine(e=>parseFloat(e)>=0,"Amount must be zero or greater"),B=r.z.string().regex(/^(?!0+(\.0+)?$)\d+(\.\d+)?$/,"Amount must be a positive, non-zero number"),K=r.z.string().url("Must be a valid URL").regex(/^https?:\/\//,"URL must start with http:// or https://"),M=r.z.string().optional().refine(e=>!e||/^https?:\/\/.+\..+/.test(e),"Must be a valid URL if provided"),G=r.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 z(e=100){return r.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 V=z(100),q=z(20),j=z(20),W=r.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"),H=r.z.string().max(255,"Filename must be at most 255 characters"),Q=r.z.enum(["image/png","image/jpg","image/jpeg","image/gif","image/webp","image/svg+xml"]),X=r.z.string().min(1,"Comment message is required").max(500,"Comment must be at most 500 characters"),Y=r.z.string().datetime("Must be a valid ISO 8601 date string"),J=r.z.number().int("Timestamp must be an integer").min(0,"Timestamp must be non-negative"),Z=r.z.string().regex(/^0x[a-fA-F0-9]{64}$/,"Private key must be format: 0x + 64 hex characters"),ee=r.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"),te=r.z.string().regex(/^galaconnect-operation-[a-z0-9-]+$/,"Unique key must be format: galaconnect-operation-{unique-id}"),ae=r.z.object({websiteUrl:M,telegramUrl:M,twitterUrl:M}).refine(e=>e.websiteUrl||e.telegramUrl||e.twitterUrl,"At least one social URL (website, telegram, or twitter) is required"),ne=r.z.string().min(1,"Token category must not be empty").default("Unit"),re=r.z.string().min(1,"Token collection must not be empty").default("Token"),se=r.z.object({minFeePortion:x,maxFeePortion:x}),oe=r.z.object({tokenName:I,tokenSymbol:D,tokenDescription:F,tokenImage:r.z.union([r.z.instanceof(File),r.z.instanceof(Buffer),r.z.string().url("Token image must be a valid URL")]).optional(),preBuyQuantity:R.default("0"),websiteUrl:M,telegramUrl:M,twitterUrl:M,tokenCategory:ne,tokenCollection:re,reverseBondingCurveConfiguration:se.optional(),privateKey:Z.optional()}),ie=r.z.object({file:r.z.union([r.z.instanceof(File),r.z.instanceof(Buffer)]),tokenName:I}),ce=r.z.enum(["recent","popular"]),le=r.z.object({tokenName:I.optional(),symbol:D.optional()}).refine(e=>e.tokenName||e.symbol,"At least one of tokenName or symbol is required"),de=r.z.enum(["NATIVE","MEME"]),ue=r.z.enum(["IN","OUT"]),he=r.z.object({from:r.z.number().int("From timestamp must be an integer").min(173e6,"From timestamp must be at least 173000000"),to:r.z.number().int("To timestamp must be an integer").min(173e6,"To timestamp must be at least 173000000"),resolution:r.z.number().int("Resolution must be an integer").min(1,"Resolution must be at least 1"),tokenName:I}),ge=r.z.object({tokenName:I,slippageToleranceFactor:r.z.number().min(0).max(1).optional(),maxAcceptableReverseBondingCurveFeeSlippageFactor:r.z.number().min(0).max(1).optional(),privateKey:Z.optional()}),me=[".png",".jpg",".jpeg",".gif",".webp",".svg"],pe=r.z.object({file:r.z.union([r.z.instanceof(File),r.z.instanceof(Buffer)]),name:H,size:W,type:Q}),fe=r.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"),ye=r.z.instanceof(Buffer).refine(e=>e.length>=1&&e.length<=10485760,"Buffer size must be between 1 byte and 10MB"),Ae=r.z.union([fe,ye]),we=r.z.enum([".png",".jpg",".jpeg",".gif",".webp",".svg"]),ve=H.refine(e=>{const t=e.slice(e.lastIndexOf(".")).toLowerCase();return me.includes(t)},`Filename must end with one of: ${me.join(", ")}`),ke=r.z.object({page:G,limit:V}),Te=r.z.object({page:G,limit:q}),be=r.z.object({page:G,limit:j}),Ee=r.z.object({page:G,limit:z(50)}),Ne=ke.extend({type:r.z.enum(["recent","popular"]).optional(),tokenName:r.z.string().min(1).max(50).optional(),search:r.z.string().min(1).max(100).optional()}),Se=Te.extend({tokenName:r.z.string().min(1).max(50).optional(),search:r.z.string().min(1).max(100).optional()}),Ie=be.extend({tradeType:r.z.enum(["BUY","SELL"]).optional(),tokenName:r.z.string().min(1).max(50).optional(),userAddress:r.z.string().regex(/^(0x[a-fA-F0-9]{40}|eth\|[a-fA-F0-9]{40})$/).optional(),startDate:r.z.string().datetime().optional(),endDate:r.z.string().datetime().optional(),sortOrder:r.z.enum(["ASC","DESC"]).default("DESC")}),De=r.z.object({page:r.z.number().int().min(1),limit:r.z.number().int().min(1),total:r.z.number().int().min(0),totalPages:r.z.number().int().min(0),hasNext:r.z.boolean(),hasPrevious:r.z.boolean()});const Fe=r.z.enum(["all","DEFI","ASSET"]),Ce=Te.extend({type:Fe.optional(),address:L.optional(),search:$.optional(),tokenName:C.optional()}),$e=r.z.object({walletAddress:L,amount:B}),_e=r.z.object({address:L.optional(),refresh:r.z.boolean().optional()}),Pe=r.z.object({profileImage:r.z.string(),fullName:_,address:L,privateKey:Z.optional()}),Oe=r.z.object({file:r.z.union([r.z.instanceof(File),r.z.instanceof(Buffer)]),address:L.optional(),privateKey:Z.optional()}),Le=r.z.object({address:L,tokenId:r.z.union([r.z.string(),r.z.object({collection:r.z.string(),category:r.z.string(),type:r.z.string(),additionalKey:r.z.string()}),r.z.object({collection:r.z.string(),category:r.z.string(),type:r.z.string(),additionalKey:r.z.string(),instance:r.z.string()})]).optional(),tokenClassKey:r.z.object({collection:r.z.string(),category:r.z.string(),type:r.z.string(),additionalKey:r.z.string()}).optional(),tokenName:C.optional()}).refine(e=>void 0!==e.tokenId||void 0!==e.tokenName,"At least one token identifier (tokenId or tokenName) is required"),Ue=r.z.enum(["buy","sell"]),xe=r.z.enum(["BUY","SELL"]),Re=r.z.object({tradeType:Ue,tokenAmount:x,vaultAddress:U,userAddress:L,slippageTolerance:x.optional(),deadline:r.z.number().int().positive().optional()}),Be=r.z.object({tokenSymbol:D,nativeTokenQuantity:x,expectedToken:x,maxAcceptableReverseBondingCurveFee:R.default("0").optional()}),Ke=r.z.object({tokenSymbol:D,tokenQuantity:x,expectedNativeToken:x,maxAcceptableReverseBondingCurveFee:R.default("0").optional()}),Me=be.extend({tokenName:C.optional()}),Ge=r.z.object({page:r.z.number().int().min(1).max(1e3).default(1).optional(),limit:r.z.number().int().min(1).max(20).default(10).optional()}),ze=r.z.enum(["NATIVE","MEME"]),Ve=r.z.enum(["IN","OUT"]),qe=r.z.object({type:ze,method:Ve,vaultAddress:U,amount:x}),je=r.z.object({nativeTokenQuantity:x}),We=r.z.object({vaultAddress:U}),He=r.z.object({minFeePortion:x,maxFeePortion:x});function Qe(e){return t=>{const a=e.safeParse(t);return{success:a.success,data:a.success?a.data:void 0,errors:a.success?void 0:a.error.errors.map(e=>e.message)}}}const Xe=Qe(I),Ye=Qe(D),Je=Qe(F),Ze=Qe(L),et=Qe(U),tt=Qe(x),at=Qe(B),nt=Qe(_),rt=Qe($),st=Qe(C),ot=Qe(oe),it=Qe(ae),ct=Qe(ie),lt=Qe(le),dt=Qe(Ce),ut=Qe($e),ht=Qe(_e),gt=Qe(Pe),mt=Qe(Oe),pt=Qe(Le),ft=Qe(Re),yt=Qe(Be),At=Qe(Ke),wt=Qe(Me),vt=Qe(Ge),kt=Qe(qe),Tt=Qe(je),bt=Qe(We);function Et(e,t){throw new A(e.join("; "),t,"VALIDATION_ERROR")}function Nt(e){const t=Xe(e);!t.success&&t.errors&&Et(t.errors,"tokenName")}function St(e){const t=Ne.safeParse(e);t.success||Et(t.error.errors.map(e=>e.message),"pagination")}function It(e){const t=lt(e);!t.success&&t.errors&&Et(t.errors,"options")}function Dt(e){const t=kt(e);!t.success&&t.errors&&Et(t.errors,"options")}function Ft(e){const t=he.safeParse(e);t.success||Et(t.error.errors.map(e=>e.message),"options")}function Ct(e){const t=L.safeParse(e);if(!t.success)throw new A("Ethereum address must be 40 hex characters (with or without 0x prefix)","ethereumAddress","INVALID_FORMAT");return t.data}var $t=Object.freeze({__proto__:null,normalizeAddressInput:function(e){if(!e)return;const t=L.safeParse(e);if(!t.success)throw new A(`Invalid address format: ${e}. Must be either "0x..." (Ethereum) or "eth|..." (GalaChain) format`,"address","INVALID_FORMAT");return t.data},toBackendAddressFormat:Ct,validateCheckPoolOptions:It,validateGetAmountOptions:Dt,validateGetGraphOptions:Ft,validatePagination:St,validateTokenName:Nt});function _t(e){if(!e)return[];return(Array.isArray(e)?e:e.token??[]).map(e=>({...e,createdAt:new Date(e.createdAt),updatedAt:new Date(e.updatedAt)}))}function Pt(e,t){const a=Number(e.page)||t.page,n=Number(e.limit)||t.limit,r=Number(e.total)||Number(e.data?.count)||0;return{page:a,limit:n,total:r,totalPages:Math.ceil(r/n)}}function Ot(e,t){return{hasNext:e<t,hasPrevious:e>1}}function Lt(e,t,a=!1){const n=!0===e.error||200!==e.status,r=a&&!e.data;if(n||r)throw new Error(e.message||t)}const Ut="/launchpad/upload-image",xt="/launchpad/fetch-pool",Rt="/launchpad/check-pool",Bt="/launchpad/get-graph-data",Kt="/holders",Mt="/launchpad/get-badge/",Gt="/trade/",zt="/token/commment",Vt="/token/commment",qt="/user/profile",jt="/user/profile",Wt="/user/token-list",Ht="/user/token-hold",Qt="/user/transfer-faucets";function Xt(e,t){return new A(`Token "${e}" not found. Please verify the token name is correct.`,"tokenName","TOKEN_NOT_FOUND")}function Yt(e,t){const a=t||e.charAt(0).toUpperCase()+e.slice(1);return new A(`${a} is required`,e,"REQUIRED_FIELD")}function Jt(e,t,a){const n=a||e.charAt(0).toUpperCase()+e.slice(1);return new A(`${n} must be ${t}`,e,"INVALID_FORMAT")}function Zt(e,t,a){return new w(e,t,a)}function ea(e,t){return new v(e,t)}function ta(e,t,a){return new k(e,t,a)}function aa(e){return e&&"object"==typeof e&&"string"==typeof e.tokenName&&(void 0===e.from||"number"==typeof e.from)&&(void 0===e.to||"number"==typeof e.to)&&(void 0===e.resolution||"number"==typeof e.resolution)}class na{constructor(e){this.http=e}async fetchPools(e={}){let t;St({page:e.page??1,limit:e.limit??10}),e.tokenName&&Nt(e.tokenName),"recent"===e.type?t="RECENT":"popular"===e.type&&(t="POPULAR");const a={page:e.page||1,limit:e.limit||10};e.search&&(a.search=e.search),e.tokenName&&(a.tokenName=e.tokenName),t&&(a.type=t);const n={page:a.page.toString(),limit:a.limit.toString()};void 0!==a.type&&(n.type=a.type),void 0!==a.tokenName&&(n.tokenName=a.tokenName),void 0!==a.search&&(n.search=a.search);const r=m(n),s=await this.http.get(xt,r);Lt(s,"Failed to fetch pools",!0);return{pools:function(e){if(!e)return[];let t=[];return e.tokens?t=Array.isArray(e.tokens)?e.tokens.map(e=>({...e,createdAt:new Date(e.created_at??e.createdAt)})):[{...e.tokens,createdAt:new Date(e.tokens.created_at??e.tokens.createdAt)}]:e.pools&&Array.isArray(e.pools)&&(t=e.pools.map(e=>({...e,createdAt:new Date(e.created_at??e.createdAt)}))),t}(s.data),page:s.data.page,limit:s.data.limit,total:s.data.total,totalPages:s.data.totalPages,hasNext:s.data.page<s.data.totalPages,hasPrevious:s.data.page>1}}async checkPool(e){It(e),e.tokenName&&Nt(e.tokenName);const t=m(e),a=await this.http.get(Rt,t);Lt(a,"Failed to check pool");const n=a.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(!aa(e))throw new A("Invalid options provided. Expected { tokenName: string, from?: number, to?: number, resolution?: number }","options","INVALID_OPTIONS");const{tokenName:t,from:a,to:n,resolution:r}=e;if(Nt(t),!a||!n||!r)throw new A("Graph options (from, to, resolution) are required","options","MISSING_GRAPH_OPTIONS");const s={tokenName:t,from:a,to:n,resolution:r};Ft(s);const o=m(s),i=await this.http.get(Bt,o);return Lt(i,"Failed to fetch graph data",!0),{dataPoints:i.data}}async fetchTokenDistribution(e){if(!e)throw Yt("tokenName","Token name");Nt(e);const t=await this.resolveTokenNameToVault(e);if(!t)throw new A(y(e),"tokenName","VAULT_NOT_FOUND");const a=encodeURIComponent(t),n=await this.http.get(`${Kt}/${a}`);return Lt(n,"Failed to fetch token distribution",!0),{holders:n.data.holders||[],totalSupply:n.data.totalSupply||"0",totalHolders:n.data.totalHolders||0,lastUpdated:new Date}}async fetchTokenBadges(e){if(!e)throw Yt("tokenName","Token name");Nt(e);const t=await this.http.get(Mt,{tokenName:e});return Lt(t,"Failed to fetch token badges",!0),{volumeBadges:t.data.volumeBadge||[],engagementBadges:t.data.engagementBadge||[]}}async hasTokenBadge(e){const{tokenName:t,badgeType:a,badgeName:n}=e;try{const e=await this.fetchTokenBadges(t);if(!e)return!1;const r=("volume"===a?e.volumeBadges:e.engagementBadges).find(e=>e.badgeName===n);return r?.isActive||!1}catch{return!1}}async resolveTokenNameToVault(e){try{const t=await this.fetchPools({tokenName:e});return t.pools&&Array.isArray(t.pools)&&t.pools.length>0?t.pools[0].vaultAddress||null:t.pools&&t.pools.tokens&&t.pools.tokens.vaultAddress||null}catch{return null}}}function ra(e,t={}){const{stringifyFields:a=[],optionalFields:n=[],fieldMappings:r={}}=t,s={};for(const[t,o]of Object.entries(e)){const e=t;if(n.includes(e)&&void 0===o)continue;if(n.includes(e)&&"string"==typeof o&&0===o.trim().length)continue;const i=r[e],c=i?String(i):t;a.includes(e)?s[c]=String(o):s[c]=o}return m(s)}const sa={PAGINATION:{MIN_PAGE:1,MAX_PAGE:1e3,MIN_LIMIT:1,MAX_LIMIT:20}};class oa{constructor(e){this.http=e}async fetchTrades(e){if(!(t=e)||"object"!=typeof t||"string"!=typeof t.tokenName||void 0!==t.tradeType&&"buy"!==t.tradeType&&"sell"!==t.tradeType||void 0!==t.userAddress&&"string"!=typeof t.userAddress||void 0!==t.page&&"number"!=typeof t.page||void 0!==t.limit&&"number"!=typeof t.limit)throw new A("Invalid options provided. Expected { tokenName: string, tradeType?: string, userAddress?: string, page?: number, limit?: number, startDate?: Date, endDate?: Date, sortOrder?: string }","options","INVALID_OPTIONS");var t;const{tokenName:a,tradeType:n,userAddress:r,page:s=1,limit:o=10,startDate:i,endDate:c,sortOrder:l}=e;if(!E(a))throw new A("Token name is required and must be a non-empty string","tokenName","INVALID_TOKEN_NAME");T(s,o,sa);const d=function(e,t,a){return ra({tokenName:e,page:t,limit:a},{stringifyFields:["page","limit"]})}(a,s,o),u=await this.http.get(Gt,d),h=(g=u.data)?(Array.isArray(g)?g:g.trades?g.trades:[]).map(e=>({...e,createdAt:new Date(e.createdAt),updatedAt:new Date(e.updatedAt)})):[];var g;const m=Pt(u,{page:s,limit:o}),p=Ot(m.page,m.totalPages);return{trades:h,...m,...p}}}const ia=new g({debug:!1,context:"DateUtils"});function ca(e,t){if(!e)return t||new Date;if(e instanceof Date)return isNaN(e.getTime())?t||new Date:e;try{const a=new Date(e);return isNaN(a.getTime())?(ia.warn(`Invalid date string received: "${e}". Using fallback.`),t||new Date):a}catch(a){return ia.warn(`Date parsing error for "${e}":`,a),t||new Date}}const la={PAGINATION:{MIN_PAGE:1,MAX_PAGE:1e3,MIN_LIMIT:1,MAX_LIMIT:50},CONTENT:{MIN_LENGTH:1,MAX_LENGTH:500}};class da{constructor(e,t){this.http=e,this.poolService=t}async fetchComments(e){if(!(t=e)||"object"!=typeof t||"string"!=typeof t.tokenName||void 0!==t.page&&"number"!=typeof t.page||void 0!==t.limit&&"number"!=typeof t.limit)throw new A("Invalid options provided. Expected { tokenName: string, page?: number, limit?: number }","options","INVALID_OPTIONS");var t;const{tokenName:a,page:n=1,limit:r=10}=e;if(!E(a))throw new A("Token name is required and must be a non-empty string","tokenName","INVALID_TOKEN_NAME");T(n,r,la);const s=await this.poolService.resolveTokenNameToVault(a);if(!s)throw Xt(a);const o=ra({vaultAddress:s,page:n,limit:r},{stringifyFields:["page","limit"]}),i=await this.http.get(zt,o);Lt(i,"Failed to fetch comments");return{comments:i.data.comments.map(e=>({...e,createdAt:ca(e.createdAt)})),total:i.data.count}}async postComment(e){if(!(t=e)||"object"!=typeof t||"string"!=typeof t.tokenName||"string"!=typeof t.content)throw new A("Invalid options provided. Expected { tokenName: string, content: string }","options","INVALID_OPTIONS");var t;const{tokenName:a,content:n}=e;if(!E(a))throw new A("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>=la.CONTENT.MIN_LENGTH&&t.length<=la.CONTENT.MAX_LENGTH}(n))throw new A(`Comment content must be between ${la.CONTENT.MIN_LENGTH} and ${la.CONTENT.MAX_LENGTH} characters`,"content","INVALID_CONTENT");const r=await this.poolService.resolveTokenNameToVault(a);if(!r)throw Xt(a);const s={userAddress:this.http.getAddress(),vaultAddress:r,content:n};Lt(await this.http.post(Vt,s),"Failed to create comment")}}const ua={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 ha(e){return!(!e||"string"!=typeof e)&&ua.USER_ADDRESS.PATTERN.test(e)}const ga="Update profile";class ma{constructor(e){this.http=e}async fetchProfile(e){const t=e??this.http.getAddress();if(!ha(t))throw new A("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");const a={userAddress:t};return await this.http.get(qt,a)}async updateProfile(e){this.validateUpdateProfileData(e);let t=e.profileImage;if(!t||""===t.trim())try{const a=await this.fetchProfile(e.address);t=a.data?.profileImage||""}catch{t=""}const a={profileImage:t,fullName:e.fullName,userAddress:e.address},n=await this.http.signCustomMessage(ga),r={address:n.address,message:ga,publickey:n.ethereumAddress,sign:n.signature};Lt(await this.http.put(jt,a,r),"Profile update failed")}async uploadProfileImage(e){this.validateUploadProfileImageOptions(e);const t=e.address??this.http.getAddress();try{const a=new FormData;if("undefined"!=typeof File&&e.file instanceof File)a.append("image",e.file);else{if(!Buffer.isBuffer(e.file))throw new A("Invalid file type","file","INVALID_FILE_TYPE");{const n=`profile-image-${t}.png`,r=new Blob([e.file],{type:"image/png"});a.append("image",r,n)}}const n=await this.http.request({method:"POST",url:`${Ut}?tokenName=${encodeURIComponent(t)}`,data:a,headers:{}});return Lt(n,"Image upload failed"),"string"==typeof n.data?n.data:""}catch(e){if(e instanceof A)throw e;throw new A(`Profile image upload failed: ${e instanceof Error?e.message:"Unknown error"}`,"file","UPLOAD_FAILED")}}async fetchTokenList(e){this.validateGetTokenListOptions(e);const t=ra({page:e.page,limit:e.limit,type:"all"!==e.type&&e.type?e.type:"DEFI",address:e.address,search:e.search,tokenName:e.tokenName},{stringifyFields:["page","limit"],optionalFields:["address","search","tokenName"]}),a=await this.http.get(Wt,t);Lt(a,"Failed to fetch token list",!0);const n=_t(a.data),r=Pt(a,{page:e.page||1,limit:e.limit||10}),s=Ot(r.page,r.totalPages);return{tokens:n,...r,...s}}async fetchTokensHeld(e){this.validateGetTokenListOptions(e);const t=ra({page:e.page,limit:e.limit,address:e.address,search:e.search,tokenName:e.tokenName},{stringifyFields:["page","limit"],optionalFields:["address","search","tokenName"]}),a=await this.http.get(Ht,t);Lt(a,"Failed to fetch tokens held",!0);const n=_t(a.data),r=Pt(a,{page:e.page||1,limit:e.limit||10}),s=Ot(r.page,r.totalPages);return{tokens:n,...r,...s}}async fetchTokensCreated(e={}){const{page:t=1,limit:a=10,search:n,tokenName:r}=e,s={type:"DEFI",address:this.http.getAddress(),page:t,limit:a};return void 0!==n&&(s.search=n),void 0!==r&&(s.tokenName=r),this.fetchTokenList(s)}validateGetTokenListOptions(e){if(T(e.page,e.limit,ua),void 0!==e.address&&!ha(e.address))throw new A("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>=ua.SEARCH.MIN_LENGTH&&t.length<=ua.SEARCH.MAX_LENGTH))throw new A(`Search query must be between ${ua.SEARCH.MIN_LENGTH} and ${ua.SEARCH.MAX_LENGTH} characters`,"search","INVALID_SEARCH");var t,a;if(void 0!==e.tokenName&&e.tokenName.trim().length>0&&!((a=e.tokenName)&&"string"==typeof a&&a.length>=ua.TOKEN_NAME.MIN_LENGTH&&a.length<=ua.TOKEN_NAME.MAX_LENGTH))throw new A(`Token name must be between ${ua.TOKEN_NAME.MIN_LENGTH} and ${ua.TOKEN_NAME.MAX_LENGTH} characters`,"tokenName","INVALID_TOKEN_NAME")}validateUpdateProfileData(e){if(!ha(e.address))throw new A("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");if(!((t=e.fullName)&&"string"==typeof t&&t.length>=ua.PROFILE.FULL_NAME.MIN_LENGTH&&t.length<=ua.PROFILE.FULL_NAME.MAX_LENGTH&&ua.PROFILE.FULL_NAME.ALPHABETS_ONLY_PATTERN.test(t)))throw new A(`Full name must be between ${ua.PROFILE.FULL_NAME.MIN_LENGTH} and ${ua.PROFILE.FULL_NAME.MAX_LENGTH} characters`,"fullName","INVALID_FULL_NAME");var t}validateUploadProfileImageOptions(e){if(e.address&&!ha(e.address))throw new A("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS")}}class pa extends Error{constructor(e,t,a){super(e),this.filename=t,this.mimeType=a,this.name="FileValidationError"}}function fa(e,t,a){if(!e)throw new pa("File is required",t,a);if("undefined"!=typeof File&&e instanceof File){const t=fe.safeParse(e);if(!t.success){const a=t.error.errors.map(e=>e.message).join("; ");throw new pa(a,e.name,e.type)}return}if(Buffer.isBuffer(e)){if(!t)throw new pa("Filename is required when uploading Buffer objects",t,a);const n=ye.safeParse(e);if(!n.success){const e=n.error.errors.map(e=>e.message).join("; ");throw new pa(e,t,a)}if(t.length>255)throw new pa(`Filename length ${t.length} exceeds maximum allowed length of 255 characters`,t,a);const r=["image/png","image/jpg","image/jpeg","image/gif","image/webp","image/svg+xml"];if(!r.includes(a))throw new pa(`Invalid file type "${a}" is not allowed. Allowed types: ${r.join(", ")}`,t,a);const s=function(e){if(!e)return"";const t=e.lastIndexOf(".");if(-1===t)return"";return e.substring(t).toLowerCase()}(t),o=[".png",".jpg",".jpeg",".gif",".webp",".svg"];if(!o.includes(s))throw new pa(`File extension "${s}" is not allowed. Allowed extensions: ${o.join(", ")}`,t,a);const i=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"}}(s);if(i!==a&&"application/octet-stream"!==i)throw new pa(`File extension "${s}" does not match MIME type "${a}"`,t,a);return}throw new pa("File must be a File object (browser) or Buffer (Node.js)",t,a)}class ya{constructor(e){this.http=e}async uploadImageByTokenName(e){const{tokenName:t,options:a}=e;Nt(t);const n=`${t}.png`;fa(a.file,n,"image/png");try{const e=new FormData;if("undefined"!=typeof File&&a.file instanceof File)e.append("image",a.file);else{if(!Buffer.isBuffer(a.file))throw Jt("file","a File object (browser) or Buffer (Node.js)");{const n=`${a.tokenName??t}.png`,r=new Blob([a.file],{type:"image/png"});e.append("image",r,n)}}const n=await this.http.request({method:"POST",url:`${Ut}?tokenName=${encodeURIComponent(a.tokenName??t)}`,data:e,headers:{}});return Lt(n,"Image upload failed"),"string"==typeof n.data?n.data:""}catch(e){if(e instanceof Error&&e.message.includes("FormData"))throw ea("File upload failed: FormData not supported in this environment. Ensure you have proper polyfills for Node.js environments.","FormData");throw e}}}class Aa{constructor(e){this.http=e}async transferFaucets(e){this.validateTransferFaucetsData(e);const t={userAddress:e.walletAddress,amount:e.amount};Lt(await this.http.post(Qt,t),"Faucet transfer failed")}validateTransferFaucetsData(e){if(!ha(e.walletAddress))throw new A("Address must be in format: eth|[40-hex-chars]","address","INVALID_ADDRESS");if(!(t=e.amount)||"string"!=typeof t||!ua.FAUCET_AMOUNT.POSITIVE_NON_ZERO_DECIMAL.test(t))throw new A("Amount must be a positive decimal string greater than zero","amount","INVALID_AMOUNT");var t}}class wa{constructor(e){this.http=e,this.poolService=new na(e),this.tradeService=new oa(e),this.commentService=new da(e,this.poolService),this.userService=new ma(e),this.imageService=new ya(e),this.faucetService=new Aa(e)}async uploadImageByTokenName(e){return this.imageService.uploadImageByTokenName(e)}async fetchPools(e={}){return this.poolService.fetchPools(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 Nt(e)}}class va 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,a,n,r){let s;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`);s={collection:e[0],category:e[1],type:e[2],additionalKey:e[3],instance:"0"}}else s={collection:n.collection,category:n.category,type:n.type,additionalKey:n.additionalKey,instance:"0"};return new va({from:e,to:t,quantity:a,tokenInstance:s,uniqueKey:r||`galaconnect-operation-${Date.now()}_${Math.random().toString(36).substring(2,8)}`})}static forGALA(e,t,a,n){return new va({from:e,to:t,quantity:a,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 ka{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},a={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,a,e),domain:t,types:a,signerPublicKey:this.wallet.signingKey.publicKey}}static toGalaChainAddress(e){const a=e.replace("0x","");return`eth|${t.ethers.getAddress(`0x${a}`).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 Ta(e){if("string"==typeof e){const t=e.split("|");if(t.length<4)throw new A(`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 A(`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 A("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 A(`Invalid tokenId type: ${typeof e}. Expected string, TokenClassKey, or TokenInstanceKey`,"tokenId","INVALID_TOKEN_ID_TYPE")}var ba=Object.freeze({__proto__:null,normalizeToTokenInstanceKey:Ta});const Ea={MAX_UNIQUE_KEY_LENGTH:64,UNIQUE_KEY_PATTERN:/^(galaswap-operation-|galaconnect-operation-)/,TOKEN_NAME_PATTERN:/^[a-zA-Z0-9]+$/};var Na;!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"}(Na||(Na={}));class Sa extends Error{constructor(e,t,a){super(e),this.type=t,this.details=a,this.name="TransferError"}}class Ia{constructor(e,t,a,n=!1){this.http=e,this.wallet=t,this.tokenResolver=a,this.signatureHelper=new ka(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 Zt(`Failed to fetch pool details: Status ${t.Status}`,t.Status);return t}async fetchLaunchTokenFee(){const e=await this.http.post("/api/asset/launchpad-contract/FetchLaunchpadFeeAmount",{});if(1!==e.Status)throw Zt(`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 A("Invalid fetch pool details data: missing required fields","data","INVALID_TYPE");var t;if(!e.vaultAddress||"string"!=typeof e.vaultAddress)throw new A("Vault address is required and must be a string","vaultAddress","INVALID_VAULT_ADDRESS");if(!e.vaultAddress.startsWith("service|Token$Unit$"))throw new A("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 a=t.Data.find(t=>t.collection===e.collection&&t.category===e.category&&t.additionalKey===e.additionalKey&&t.type===e.type);if(!a||"0"===a.quantity)return null;const n=`${a.collection}|${a.category}|${a.additionalKey}|${a.type}`;return{quantity:a.quantity,collection:a.collection,category:a.category,tokenId:n}}catch(e){throw Zt(`Failed to fetch token balance from GalaChain: ${e.message||"Unknown error"}`,void 0,e)}}async transferGala(e){this.validateTransferGalaData(e);try{const t=S(e.recipientAddress),a=S(this.wallet.address),n=va.forGALA(a,t,e.amount,e.uniqueKey),r=await this.signatureHelper.signTransferToken(n.toSigningPayload()),s=new va({...n.toSigningPayload(),signedPayload:r});this.logger.debug("[DEBUG] Full GALA Transfer Request Payload:",JSON.stringify(s,null,2));const o=await this.http.post("/api/asset/token-contract/TransferToken",s);if(this.logger.debug("[DEBUG] Transfer response:",JSON.stringify(o,null,2)),o&&"object"==typeof o){if("Status"in o&&1===o.Status&&"Data"in o){const e=o;return Array.isArray(e.Data)&&e.Data.length>0?"gala-transfer-successful":"transfer-successful-no-id"}if("transactionId"in o&&o.transactionId)return o.transactionId}throw new Sa("Transfer succeeded but transaction ID could not be extracted",Na.NETWORK_ERROR)}catch(t){throw this.handleTransferError(t,"GALA transfer failed",e)}}async transferToken(e){this.validateTransferTokenData(e);try{const t=S(e.to),a=S(this.wallet.address);let n;if(e.tokenId)n=Ta(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 Sa("Must provide either tokenId or tokenName for token identification",Na.TOKEN_NOT_FOUND);n=await this.resolveTokenInstance(e.tokenName)}const r=new va({from:a,to:t,quantity:e.amount,tokenInstance:n,uniqueKey:e.uniqueKey||`galaconnect-operation-${Date.now()}_${Math.random().toString(36).substring(2,8)}`}),s=await this.signatureHelper.signTransferToken(r.toSigningPayload()),o=new va({...r.toSigningPayload(),signedPayload:s});this.logger.debug("[DEBUG] Full Transfer Request Payload:",JSON.stringify(o,null,2));const i=await this.http.post("/api/asset/token-contract/TransferToken",o);if(this.logger.debug("[DEBUG] Token transfer response:",JSON.stringify(i,null,2)),i&&"object"==typeof i){if("Status"in i&&1===i.Status&&"Data"in i){const e=i;return Array.isArray(e.Data)&&e.Data.length>0?"token-transfer-successful":"transfer-successful-no-id"}if("transactionId"in i&&i.transactionId)return i.transactionId}throw new Sa("Transfer succeeded but transaction ID could not be extracted",Na.NETWORK_ERROR)}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.stringify(t,null,2)),t}catch(t){if(t instanceof Sa)throw t;throw new Sa(`Failed to resolve token class key for '${e}': ${t instanceof Error?t.message:String(t)}`,Na.TOKEN_NOT_FOUND,{tokenName:e})}}validateTransferGalaData(e){if(!((t=e)&&"object"==typeof t&&"string"==typeof t.recipientAddress&&t.recipientAddress.trim().length>0&&"string"==typeof t.amount&&t.amount.trim().length>0)||void 0!==t.uniqueKey&&"string"!=typeof t.uniqueKey)throw new A("Invalid GALA transfer data: missing required fields");var t;if(!N(e.recipientAddress))throw new Sa("Invalid recipient address format",Na.INVALID_RECIPIENT,{recipientAddress:e.recipientAddress});if(parseFloat(e.amount)<=0)throw new Sa("Transfer amount must be positive",Na.INVALID_AMOUNT,{amount:e.amount});if(e.uniqueKey){if(e.uniqueKey.length>Ea.MAX_UNIQUE_KEY_LENGTH)throw new A(`Unique key too long. Maximum length: ${Ea.MAX_UNIQUE_KEY_LENGTH}`);if(!Ea.UNIQUE_KEY_PATTERN.test(e.uniqueKey))throw new Sa('Invalid unique key format. Must start with "galaswap-operation-" or "galaconnect-operation-"',Na.INVALID_AMOUNT,{uniqueKey:e.uniqueKey})}}validateTransferTokenData(e){if(!((t=e)&&"object"==typeof t&&"string"==typeof t.to&&t.to.trim().length>0&&"string"==typeof t.amount&&t.amount.trim().length>0&&(void 0!==t.tokenId||"string"==typeof t.tokenName&&t.tokenName.trim().length>0))||void 0!==t.uniqueKey&&"string"!=typeof t.uniqueKey)throw new A("Invalid token transfer data: missing required fields");var t;if(!N(e.to))throw new Sa("Invalid recipient address format",Na.INVALID_RECIPIENT,{recipientAddress:e.to});if(!e.tokenId&&!e.tokenName)throw new Sa("Must provide either tokenId or tokenName for token identification",Na.TOKEN_NOT_FOUND);if(e.tokenName&&!Ea.TOKEN_NAME_PATTERN.test(e.tokenName))throw new Sa("Invalid token name format",Na.TOKEN_NOT_FOUND,{tokenName:e.tokenName});if(parseFloat(e.amount)<=0)throw new Sa("Transfer amount must be positive",Na.INVALID_AMOUNT,{amount:e.amount});if(e.uniqueKey){if(e.uniqueKey.length>Ea.MAX_UNIQUE_KEY_LENGTH)throw new A(`Unique key too long. Maximum length: ${Ea.MAX_UNIQUE_KEY_LENGTH}`);if(!Ea.UNIQUE_KEY_PATTERN.test(e.uniqueKey))throw new Sa('Invalid unique key format. Must start with "galaswap-operation-" or "galaconnect-operation-"',Na.INVALID_AMOUNT,{uniqueKey:e.uniqueKey})}}async resolveTokenInstance(e){try{const t=await this.tokenResolver.resolveTokenToVault(e);if(!t)throw new Sa(`Token '${e}' not found or not available for transfer`,Na.TOKEN_NOT_FOUND,{tokenName:e});const a=this.resolveTokenInstanceFromVaultAddress(t);return this.logger.debug(`[DEBUG] Token resolution for '${e}':\n Vault Address: ${t}\n Token Instance: ${JSON.stringify(a,null,2)}`),a}catch(t){if(t instanceof Sa)throw t;throw new Sa(`Failed to resolve token '${e}': ${t instanceof Error?t.message:String(t)}`,Na.TOKEN_NOT_FOUND,{tokenName:e})}}resolveTokenInstanceFromVaultAddress(e){const[t,a]=e.split("|");if(!a)throw new Sa(`Invalid vault address format: missing token components. Address: ${e}`,Na.TOKEN_NOT_FOUND);const n=a.split("$");if(n.length<4)throw new Sa(`Invalid vault address format: insufficient token components. Expected 4+, got ${n.length}. Address: ${e}`,Na.TOKEN_NOT_FOUND);return{collection:n[0],category:n[1],type:n[2],additionalKey:n[3],instance:"0"}}handleTransferError(e,t,a){if(e instanceof Sa)return e;if(e instanceof A)return new Sa(e.message,Na.INVALID_AMOUNT);if(400===e.response?.status)return new Sa(e.response.data?.message||"Invalid transfer request",Na.INVALID_AMOUNT);if(403===e.response?.status)return new Sa("Insufficient balance for transfer",Na.INSUFFICIENT_BALANCE);if(404===e.response?.status){const e={};return"tokenName"in a&&(e.tokenName=a.tokenName),new Sa("Token not found",Na.TOKEN_NOT_FOUND,e)}return"ECONNABORTED"===e.code||"ETIMEDOUT"===e.code?new Sa("Transfer request timed out",Na.NETWORK_ERROR):new Sa(e.message||t,Na.NETWORK_ERROR)}}class Da{constructor(e){this.http=e}async fetchTokenSpotPrice(e){if(!e||Array.isArray(e)&&0===e.length)throw Yt("symbols","At least one symbol");const t=Array.isArray