@naculus/connector-walletconnect 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Naculus
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var T=Object.create;var f=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var W=Object.getOwnPropertyNames;var U=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var E=(i,e)=>{for(var t in e)f(i,t,{get:e[t],enumerable:!0})},S=(i,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of W(e))!k.call(i,a)&&a!==t&&f(i,a,{get:()=>e[a],enumerable:!(n=x(e,a))||n.enumerable});return i};var b=(i,e,t)=>(t=i!=null?T(U(i)):{},S(e||!i||!i.__esModule?f(t,"default",{value:i,enumerable:!0}):t,i)),j=i=>S(f({},"__esModule",{value:!0}),i);var B={};E(B,{WalletConnectConnector:()=>y,buildRequiredNamespaces:()=>w,createWalletConnectConnector:()=>$,extractAddress:()=>P,isValidCAIP10:()=>v,mapNamespaces:()=>m,parseCAIP10:()=>_,toHexValue:()=>C});module.exports=j(B);var s=require("@naculus/connect-core"),R=require("@scure/base"),A=b(require("@walletconnect/sign-client"),1);var q=/^[-a-z0-9]{1,32}:[-a-zA-Z0-9]{1,64}$/;function D(i){return q.test(i)}function I(i,e,t){let n=[];if(t&&(!e.chains||e.chains.length===0)&&n.push(`Namespace "${i}": chains are required`),e.chains)for(let a of e.chains)D(a)||n.push(`Namespace "${i}": invalid CAIP-2 chain "${a}"`);return t&&(!e.methods||e.methods.length===0)&&n.push(`Namespace "${i}": methods are required`),e.events||n.push(`Namespace "${i}": events array is required`),n}function N(i){let e=[],t=[];if(!i.requiredNamespaces||Object.keys(i.requiredNamespaces).length===0)e.push("requiredNamespaces is required and cannot be empty");else for(let[n,a]of Object.entries(i.requiredNamespaces)){let o=I(n,a,!0);e.push(...o)}if(i.optionalNamespaces){for(let[n,a]of Object.entries(i.optionalNamespaces))if(!i.requiredNamespaces[n]){let o=I(n,a,!1);t.push(...o.map(c=>`optional: ${c}`))}}return{valid:e.length===0,errors:e,warnings:t}}var O=["eth_accounts","eth_requestAccounts","personal_sign","eth_sign","eth_signTransaction","eth_sendTransaction","eth_sendRawTransaction","eth_signTypedData_v4","wallet_switchEthereumChain"],M=["accountsChanged","chainChanged","disconnect","connect","message"],L=["solana_signMessage","solana_signTransaction","solana_sendTransaction"],V=["accountChanged","disconnect"];function C(i){return i.startsWith("0x")?i:`0x${BigInt(i).toString(16)}`}function _(i){let e=i.split(":");if(e.length===3)return{namespace:e[0],chainId:e[1],address:e[2]}}function P(i){let e=_(i);return e?e.address:i}function v(i){return i.includes(":")&&i.split(":").length===3}function m(i){return Object.entries(i).reduce((e,[t,n])=>(e[t]={chains:n.chains??[],accounts:n.accounts,methods:n.methods,events:n.events,capabilities:n.capabilities??{}},e),{})}function w(){return{eip155:{chains:["eip155:1","eip155:11155111","eip155:137","eip155:42161","eip155:10","eip155:8453"],methods:[...O],events:[...M]},solana:{chains:["solana:0","solana:1","solana:2"],methods:[...L],events:[...V]}}}var y=class{id="walletconnect";name="WalletConnect";kind="walletconnect";namespaces=["eip155","solana"];supports={desktop:!0,mobile:!0,deepLink:!0,qr:!0,trustedReconnect:!0};config;client;lastSession;lastUri;pendingApproval;sessionExpiryHandler;constructor(e){this.config=e,this.client=e.client}async getClient(){return this.client?this.client:(this.client=await A.default.init({projectId:this.config.projectId,relayUrl:this.config.relayUrl,metadata:this.config.metadata}),this.client.on("session_delete",e=>{e.topic===this.lastSession?.topic&&this.sessionExpiryHandler?.()}),this.client.on("session_expire",e=>{e.topic===this.lastSession?.topic&&this.sessionExpiryHandler?.()}),this.client)}async connect(e){let t=await this.getClient(),n=e&&typeof e=="object"?e:void 0,a=n?.requiredNamespaces,o=n?.optionalNamespaces,c=a??w(),l=N({requiredNamespaces:c,optionalNamespaces:o});if(!l.valid)throw new s.WalletError("invalid_proposal",`CAIP-25 validation failed: ${l.errors.join(", ")}`);try{let r={requiredNamespaces:c};o&&(r.optionalNamespaces=o);let{uri:d,approval:g}=await t.connect(r);d&&(this.lastUri=d);let p=await g(),u=m(p.namespaces),h=(0,s.createEmptySession)({id:crypto.randomUUID(),topic:p.topic,walletId:p.peer.metadata?.name??"walletconnect",walletType:"walletconnect",namespaces:u,platform:(0,s.detectPlatform)(),createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});return this.lastSession=h,h}catch(r){let d=r instanceof Error?r.message:"WalletConnect connect failed.";throw d.toLowerCase().includes("rejected")?new s.WalletError("user_rejected",d,r):new s.WalletError("wallet_unavailable",d,r)}}async reconnect(e){let t=await this.getClient();try{let n=t.session.get(e.topic??"");if(!n)throw new s.WalletError("session_expired","WalletConnect session not found.");let a=m(n.namespaces),o=(0,s.createEmptySession)({id:e.id,topic:n.topic,walletId:n.peer.metadata?.name??"walletconnect",walletType:"walletconnect",namespaces:a,platform:(0,s.detectPlatform)(),createdAt:e.createdAt,updatedAt:new Date().toISOString()});return this.lastSession=o,o}catch(n){throw n instanceof s.WalletError?n:new s.WalletError("session_expired","WalletConnect session not found.",n)}}async disconnect(e){if(!e.topic)return;await(await this.getClient()).disconnect({topic:e.topic,reason:{code:s.WC_DISCONNECT_USER,message:"User disconnected"}})}async getAccounts(e){if(!e.topic)return(0,s.extractAccounts)(e.namespaces);let n=(await this.getClient()).session.get(e.topic);if(!n)throw new s.WalletError("session_expired","WalletConnect session expired.");return(0,s.extractAccounts)(m(n.namespaces))}async signMessage(e,t){if(!t||typeof t!="object")throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.INVALID_INPUT);let n=t,a=typeof n.message=="string"?n.message:void 0,o=typeof n.address=="string"?n.address:void 0,c=typeof n.chainId=="string"?n.chainId:void 0;if(!a||!o)throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.MISSING_MESSAGE);let l=o.includes(":")?o.split(":").pop():o;if(this.isSolanaChain(c)){let g=new TextEncoder().encode(a),p=R.base58.encode(g);return this.makeRequest(e,"solana_signMessage",[{message:p,pubkey:l}],c)}let r=a.startsWith("{")?["eth_signTypedData_v4"]:["personal_sign","eth_sign"],d;for(let g of r){let p;g==="personal_sign"?p=[l,this.hexEncode(a)]:g==="eth_sign"?p=[l,this.hexEncode(a)]:p=[a,l];try{return await this.makeRequest(e,g,p,c)}catch(u){d=u;let h=u instanceof Error?u.message.toLowerCase():"";if(!(h.includes("not been authorized")||h.includes("not authorized")||h.includes("not approved")||h.includes("method not found")||h.includes("method_not_allowed"))||r.length===1)throw u instanceof s.WalletError?u:new s.WalletError("signature_rejected","WalletConnect signature rejected.",u)}}throw d instanceof s.WalletError?d:new s.WalletError("signature_rejected","WalletConnect signature rejected.",d)}async signTransaction(e,t){if(!t||typeof t!="object")throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.INVALID_INPUT);let n=t,a=n.transaction,o=typeof n.chainId=="string"?n.chainId:void 0;if(!a)throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.MISSING_TX);let l=this.isSolanaChain(o)?"solana_signTransaction":"eth_signTransaction";try{return await this.makeRequest(e,l,[a],o)}catch(r){throw r instanceof s.WalletError?r:new s.WalletError("signature_rejected","WalletConnect sign transaction rejected.",r)}}async sendRawTransaction(e,t){if(!t||typeof t!="object")throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.INVALID_INPUT);let n=t,a=typeof n.signedTransaction=="string"?n.signedTransaction:void 0,o=typeof n.chainId=="string"?n.chainId:void 0;if(!a)throw new s.WalletError("method_not_allowed","Missing signedTransaction parameter.");if(this.isSolanaChain(o))throw new s.WalletError("method_not_allowed","sendRawTransaction not supported for Solana via WalletConnect.");try{return await this.makeRequest(e,"eth_sendRawTransaction",[a],o)}catch(c){throw c instanceof s.WalletError?c:new s.WalletError("tx_failed","WalletConnect sendRawTransaction failed.",c)}}async sendTransaction(e,t){if(!t||typeof t!="object")throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.INVALID_INPUT);let n=t,a=n.transaction,o=typeof n.chainId=="string"?n.chainId:void 0;if(!a)throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.MISSING_TX);let c=this.isSolanaChain(o),l=c?"solana_sendTransaction":"eth_sendTransaction",r=c?a:{...a,value:typeof a.value=="string"?C(a.value):a.value};try{return await this.makeRequest(e,l,[r],o)}catch(d){throw d instanceof s.WalletError?d:new s.WalletError("tx_failed","WalletConnect transaction failed.",d)}}async switchChain(e,t){if(!t.startsWith("eip155:"))throw new s.WalletError("chain_unsupported","WalletConnect switchChain only supports EVM chains.");try{await this.makeRequest(e,"wallet_switchEthereumChain",[{chainId:`0x${Number(t.split(":")[1]).toString(16)}`}],t)}catch(n){throw n instanceof s.WalletError?n:new s.WalletError("chain_unsupported","WalletConnect switch chain failed.",n)}}async sendCalls(e,t,n){let a=n??this.getDefaultChainId(e);try{return await this.makeRequest(e,"wallet_sendCalls",[{calls:t,chainId:a}],a)}catch{let c=(e.namespaces.eip155?.accounts??[])[0]?.split(":").pop();if(!c)throw new s.WalletError("session_expired",s.CONNECTOR_ERROR_MESSAGES.NO_ACCOUNT_TX);let l=[];for(let r of t){let d=await this.makeRequest(e,"eth_sendTransaction",[{from:c,to:r.to,value:r.value,data:r.data}],a);l.push(d)}return l.length===1?l[0]:l.join(",")}}async getCapabilities(e){let t={};for(let n of Object.values(e.namespaces)){let a=n.capabilities??{},o=!!a.atomicBatch;for(let c of n.chains)t[c]={atomicBatch:o?{supported:!0,maxBatchSize:5}:{supported:!1},paymasterService:a.paymasterService?{supported:!0}:void 0}}return t}async getCallsStatus(e,t){try{return await this.makeRequest(e,"wallet_getCallsStatus",[t])}catch{return{status:"PENDING"}}}async request(e){let t=this.lastSession;if(!t)throw new s.WalletError("session_expired",s.CONNECTOR_ERROR_MESSAGES.SESSION_EXPIRED);return this.makeRequest(t,e.method,e.params,this.getDefaultChainId(t))}async getBalance(e){let t=this.lastSession;if(!t)throw new s.WalletError("session_expired",s.CONNECTOR_ERROR_MESSAGES.SESSION_EXPIRED);let n=e??this.getDefaultChainId(t),a=s.DEFAULT_RPC_URLS[n];if(!a)throw new s.WalletError("chain_unsupported","No RPC URL for chain "+n);let c=(0,s.extractAccounts)(t.namespaces)[0]?.split(":").pop();if(!c)throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.NO_ACCOUNTS);return(await(await fetch(a,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_getBalance",params:[c,"latest"]})})).json()).result}async deepLink(e){if(typeof window>"u")return;let t=this.lastUri;if(!t)throw new s.WalletError("deeplink_timeout","WalletConnect URI unavailable.");let n=`${e}${e.includes("?")?"&":"?"}uri=${encodeURIComponent(t)}`;window.location.assign(n)}getDefaultChainId(e){let t=e.namespaces.eip155;if(t&&t.chains.length>0)return t.chains[0];let n=e.namespaces.solana;return n&&n.chains.length>0?n.chains[0]:s.EIP155_MAINNET}requireSessionTopic(e){if(!e.topic)throw new s.WalletError("session_expired","WalletConnect session missing topic.");return e.topic}isSolanaChain(e){return e?.startsWith("solana:")??!1}hexEncode(e){if(/^0x[0-9a-fA-F]*$/.test(e))return e;let t=new TextEncoder().encode(e),n="0x";for(let a=0;a<t.length;a++)n+=t[a].toString(16).padStart(2,"0");return n}async signTypedData(e,t){if(!t||typeof t!="object")throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.INVALID_INPUT);let n=t,a=typeof n.typedData=="string"?n.typedData:void 0,o=typeof n.address=="string"?n.address:void 0,c=typeof n.chainId=="string"?n.chainId:void 0;if(!a||!o)throw new s.WalletError("method_not_allowed",s.CONNECTOR_ERROR_MESSAGES.INVALID_INPUT);let l=o.includes(":")?o.split(":").pop():o;if(this.isSolanaChain(c))throw new s.WalletError("method_not_allowed","signTypedData not supported for Solana.");try{return await this.makeRequest(e,"eth_signTypedData_v4",[l,a],c)}catch(r){throw r instanceof s.WalletError?r:new s.WalletError("signature_rejected","WalletConnect signTypedData_v4 rejected.",r)}}async makeRequest(e,t,n,a){let o=await this.getClient(),c=this.requireSessionTopic(e),l=a??this.getDefaultChainId(e);try{return await o.request({topic:c,chainId:l,request:{method:t,params:n}})}catch(r){let d=r instanceof Error?r.message:String(r);throw new s.WalletError("signature_rejected",d,{method:t,originalError:r})}}onSessionExpiry(e){this.sessionExpiryHandler=e}get uri(){return this.lastUri}async startPairing(){let e=await this.getClient(),t=w(),n=await e.connect({requiredNamespaces:t});if(!n.uri)throw new s.WalletError("wallet_unavailable","No URI");return this.lastUri=n.uri,this.pendingApproval=n.approval,n.uri}async completePairing(){if(!this.pendingApproval)throw new s.WalletError("wallet_unavailable","No pending approval");let t=await this.pendingApproval(),n=t.namespaces,a=t.topic,o=t.peer?.metadata,c=typeof o?.name=="string"?o.name:"walletconnect";this.pendingApproval=void 0;let l=m(n),r=(0,s.createEmptySession)({id:crypto.randomUUID(),topic:a,walletId:c,walletType:"walletconnect",namespaces:l,platform:(0,s.detectPlatform)(),createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});return this.lastSession=r,r}};function $(i){return new y(i)}0&&(module.exports={WalletConnectConnector,buildRequiredNamespaces,createWalletConnectConnector,extractAddress,isValidCAIP10,mapNamespaces,parseCAIP10,toHexValue});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/caip25.ts","../src/namespaces.ts"],"sourcesContent":["import type {\n BatchCall,\n Namespace,\n SessionNamespace,\n UniversalConnector,\n UniversalWalletSession,\n WalletCapabilities,\n} from \"@naculus/connect-core\";\nimport {\n CONNECTOR_ERROR_MESSAGES,\n createEmptySession,\n DEFAULT_RPC_URLS,\n detectPlatform,\n EIP155_MAINNET,\n extractAccounts,\n WalletError,\n WC_DISCONNECT_USER,\n} from \"@naculus/connect-core\";\nimport { base58 } from \"@scure/base\";\nimport SignClient from \"@walletconnect/sign-client\";\nimport type { ProposalTypes } from \"@walletconnect/types\";\nimport { type CAIP25NamespaceProposal, validateCAIP25Proposal } from \"./caip25\";\nimport {\n buildRequiredNamespaces,\n extractAddress,\n isValidCAIP10,\n mapNamespaces,\n parseCAIP10,\n toHexValue,\n type WalletConnectConfig,\n} from \"./namespaces\";\n\nexport type {\n WalletConnectConfig,\n WalletConnectConnectInput,\n WalletConnectMetadata,\n} from \"./namespaces\";\nexport {\n buildRequiredNamespaces,\n extractAddress,\n isValidCAIP10,\n mapNamespaces,\n parseCAIP10,\n toHexValue,\n} from \"./namespaces\";\n\n/**\n * WalletConnect v2 Connector for connect SDK\n *\n * Supports EVM chains and Solana through WalletConnect's multi-chain namespace.\n * Provides QR code pairing for desktop and deep link support for mobile.\n *\n * @example\n * ```typescript\n * const connector = new WalletConnectConnector({\n * projectId: process.env.VITE_WALLETCONNECT_PROJECT_ID,\n * metadata: {\n * name: \"My DApp\",\n * description: \"Connect to My DApp\",\n * url: window.location.origin,\n * icons: [window.location.origin + \"/icon.png\"]\n * }\n * });\n * ```\n */\nexport class WalletConnectConnector implements UniversalConnector {\n /** Unique connector identifier */\n readonly id = \"walletconnect\";\n\n /** Display name for UI */\n readonly name = \"WalletConnect\";\n\n /** Connector type identifier */\n readonly kind: \"walletconnect\" = \"walletconnect\";\n\n /** Supported chain namespaces */\n readonly namespaces = [\"eip155\", \"solana\"];\n\n /** Feature support flags */\n readonly supports = {\n desktop: true,\n mobile: true,\n deepLink: true,\n qr: true,\n trustedReconnect: true,\n } as const;\n\n /** Connector configuration */\n readonly config: WalletConnectConfig;\n\n private client: SignClient | undefined;\n private lastSession?: UniversalWalletSession;\n private lastUri?: string;\n private pendingApproval?: () => Promise<UniversalWalletSession>;\n private sessionExpiryHandler?: () => void;\n\n constructor(config: WalletConnectConfig) {\n this.config = config;\n this.client = config.client;\n }\n\n private async getClient(): Promise<SignClient> {\n if (this.client) {\n return this.client;\n }\n\n this.client = await SignClient.init({\n projectId: this.config.projectId,\n relayUrl: this.config.relayUrl,\n metadata: this.config.metadata,\n });\n\n this.client.on(\"session_delete\", (event: { topic: string }) => {\n if (event.topic === this.lastSession?.topic) {\n this.sessionExpiryHandler?.();\n }\n });\n this.client.on(\"session_expire\", (event: { topic: string }) => {\n if (event.topic === this.lastSession?.topic) {\n this.sessionExpiryHandler?.();\n }\n });\n\n return this.client;\n }\n\n async connect(input?: unknown): Promise<UniversalWalletSession> {\n const client = await this.getClient();\n const connectInput =\n input && typeof input === \"object\"\n ? (input as Record<string, unknown>)\n : undefined;\n\n const requiredNamespacesRaw = connectInput?.requiredNamespaces as\n | ProposalTypes.RequiredNamespaces\n | undefined;\n const optionalNamespacesRaw = connectInput?.optionalNamespaces as\n | ProposalTypes.OptionalNamespaces\n | undefined;\n\n const requiredNamespaces =\n requiredNamespacesRaw ?? buildRequiredNamespaces();\n\n const validation = validateCAIP25Proposal({\n requiredNamespaces: requiredNamespaces as Record<\n string,\n CAIP25NamespaceProposal\n >,\n optionalNamespaces: optionalNamespacesRaw as\n | Record<string, CAIP25NamespaceProposal>\n | undefined,\n });\n\n if (!validation.valid) {\n throw new WalletError(\n \"invalid_proposal\",\n `CAIP-25 validation failed: ${validation.errors.join(\", \")}`,\n );\n }\n\n try {\n const connectParams: Record<string, unknown> = { requiredNamespaces };\n if (optionalNamespacesRaw) {\n connectParams.optionalNamespaces = optionalNamespacesRaw;\n }\n const { uri, approval } = await client.connect(connectParams as any);\n if (uri) {\n this.lastUri = uri;\n }\n\n const session = await approval();\n const namespaces = mapNamespaces(session.namespaces);\n\n const walletSession = createEmptySession({\n id: crypto.randomUUID(),\n topic: session.topic,\n walletId: session.peer.metadata?.name ?? \"walletconnect\",\n walletType: \"walletconnect\",\n namespaces,\n platform: detectPlatform(),\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n\n this.lastSession = walletSession;\n return walletSession;\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"WalletConnect connect failed.\";\n if (message.toLowerCase().includes(\"rejected\")) {\n throw new WalletError(\"user_rejected\", message, error);\n }\n\n throw new WalletError(\"wallet_unavailable\", message, error);\n }\n }\n\n async reconnect(\n session: UniversalWalletSession,\n ): Promise<UniversalWalletSession> {\n const client = await this.getClient();\n\n try {\n const existing = client.session.get(session.topic ?? \"\");\n if (!existing) {\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session not found.\",\n );\n }\n\n const namespaces = mapNamespaces(existing.namespaces);\n const walletSession = createEmptySession({\n id: session.id,\n topic: existing.topic,\n walletId: existing.peer.metadata?.name ?? \"walletconnect\",\n walletType: \"walletconnect\",\n namespaces,\n platform: detectPlatform(),\n createdAt: session.createdAt,\n updatedAt: new Date().toISOString(),\n });\n\n this.lastSession = walletSession;\n return walletSession;\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session not found.\",\n error,\n );\n }\n }\n\n async disconnect(session: UniversalWalletSession): Promise<void> {\n if (!session.topic) {\n return;\n }\n\n const client = await this.getClient();\n await client.disconnect({\n topic: session.topic,\n reason: {\n code: WC_DISCONNECT_USER,\n message: \"User disconnected\",\n },\n });\n }\n\n async getAccounts(session: UniversalWalletSession): Promise<string[]> {\n if (!session.topic) {\n return extractAccounts(session.namespaces);\n }\n\n const client = await this.getClient();\n const existing = client.session.get(session.topic);\n if (!existing) {\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session expired.\",\n );\n }\n\n return extractAccounts(mapNamespaces(existing.namespaces));\n }\n\n async signMessage(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const message =\n typeof inputObj.message === \"string\" ? inputObj.message : undefined;\n const rawAddress =\n typeof inputObj.address === \"string\" ? inputObj.address : undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!message || !rawAddress)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.MISSING_MESSAGE,\n );\n\n // Remove CAIP-10 prefix, keeping the raw chain address\n const address = rawAddress.includes(\":\")\n ? rawAddress.split(\":\").pop()!\n : rawAddress;\n\n // Solana chain → use solana_signMessage with base58 encoding (CAIP-25)\n // Reference: Reown AppKit's SolanaWalletConnectProvider sends\n // { message: base58.encode(message), pubkey: address }\n if (this.isSolanaChain(chainId)) {\n const messageBytes = new TextEncoder().encode(message);\n const base58Msg = base58.encode(messageBytes);\n return this.makeRequest(\n session,\n \"solana_signMessage\",\n [{ message: base58Msg, pubkey: address }],\n chainId,\n );\n }\n\n // EVM signing method fallback chain:\n // JSON messages → eth_signTypedData_v4 (no fallback)\n // Plain messages → personal_sign → eth_sign (fallback on method rejection)\n const tryMethods = message.startsWith(\"{\")\n ? [\"eth_signTypedData_v4\"]\n : [\"personal_sign\", \"eth_sign\"];\n\n let lastError: unknown;\n for (const tryMethod of tryMethods) {\n let tryParams: unknown[];\n if (tryMethod === \"personal_sign\") {\n tryParams = [address, this.hexEncode(message)];\n } else if (tryMethod === \"eth_sign\") {\n // eth_sign takes [address, messageToSign]\n // Use the raw hex-encoded message; wallets will show a hash\n tryParams = [address, this.hexEncode(message)];\n } else {\n // eth_signTypedData_v4\n tryParams = [message, address];\n }\n\n try {\n return await this.makeRequest(session, tryMethod, tryParams, chainId);\n } catch (error) {\n lastError = error;\n // Only fall through on method-not-authorized errors\n const errMsg =\n error instanceof Error ? error.message.toLowerCase() : \"\";\n const isMethodRejection =\n // Exact WalletConnect wording: \"has not been authorized by the user\"\n errMsg.includes(\"not been authorized\") ||\n errMsg.includes(\"not authorized\") ||\n errMsg.includes(\"not approved\") ||\n errMsg.includes(\"method not found\") ||\n errMsg.includes(\"method_not_allowed\");\n\n if (!isMethodRejection || tryMethods.length === 1) {\n // Unrecoverable error or no more fallbacks\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect signature rejected.\",\n error,\n );\n }\n // Otherwise, continue to next fallback method\n }\n }\n\n // If all methods failed, throw the last error\n if (lastError instanceof WalletError) {\n throw lastError;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect signature rejected.\",\n lastError,\n );\n }\n\n async signTransaction(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const transaction = inputObj.transaction as\n | Record<string, unknown>\n | undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!transaction)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.MISSING_TX,\n );\n\n const isSolana = this.isSolanaChain(chainId);\n const method = isSolana ? \"solana_signTransaction\" : \"eth_signTransaction\";\n\n try {\n return await this.makeRequest(session, method, [transaction], chainId);\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect sign transaction rejected.\",\n error,\n );\n }\n }\n\n async sendRawTransaction(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const signedTx =\n typeof inputObj.signedTransaction === \"string\"\n ? inputObj.signedTransaction\n : undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!signedTx)\n throw new WalletError(\n \"method_not_allowed\",\n \"Missing signedTransaction parameter.\",\n );\n\n if (this.isSolanaChain(chainId)) {\n throw new WalletError(\n \"method_not_allowed\",\n \"sendRawTransaction not supported for Solana via WalletConnect.\",\n );\n }\n\n try {\n return await this.makeRequest<string>(\n session,\n \"eth_sendRawTransaction\",\n [signedTx],\n chainId,\n );\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"tx_failed\",\n \"WalletConnect sendRawTransaction failed.\",\n error,\n );\n }\n }\n\n async sendTransaction(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const transaction = inputObj.transaction as\n | Record<string, unknown>\n | undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!transaction)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.MISSING_TX,\n );\n\n const isSolana = this.isSolanaChain(chainId);\n const method = isSolana ? \"solana_sendTransaction\" : \"eth_sendTransaction\";\n\n const tx = isSolana\n ? transaction\n : {\n ...transaction,\n value:\n typeof transaction.value === \"string\"\n ? toHexValue(transaction.value)\n : transaction.value,\n };\n\n try {\n return await this.makeRequest(session, method, [tx], chainId);\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"tx_failed\",\n \"WalletConnect transaction failed.\",\n error,\n );\n }\n }\n\n async switchChain(\n session: UniversalWalletSession,\n chainId: string,\n ): Promise<void> {\n if (!chainId.startsWith(\"eip155:\")) {\n throw new WalletError(\n \"chain_unsupported\",\n \"WalletConnect switchChain only supports EVM chains.\",\n );\n }\n\n try {\n await this.makeRequest(\n session,\n \"wallet_switchEthereumChain\",\n [{ chainId: `0x${Number(chainId.split(\":\")[1]).toString(16)}` }],\n chainId,\n );\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"chain_unsupported\",\n \"WalletConnect switch chain failed.\",\n error,\n );\n }\n }\n\n async sendCalls(\n session: UniversalWalletSession,\n calls: BatchCall[],\n chainId?: string,\n ): Promise<string> {\n const resolvedChainId = chainId ?? this.getDefaultChainId(session);\n\n try {\n return await this.makeRequest<string>(\n session,\n \"wallet_sendCalls\",\n [{ calls, chainId: resolvedChainId }],\n resolvedChainId,\n );\n } catch {\n const accounts = session.namespaces.eip155?.accounts ?? [];\n const fromAccount = accounts[0]?.split(\":\").pop();\n if (!fromAccount) {\n throw new WalletError(\n \"session_expired\",\n CONNECTOR_ERROR_MESSAGES.NO_ACCOUNT_TX,\n );\n }\n const txHashes: string[] = [];\n for (const call of calls) {\n const hash = await this.makeRequest<string>(\n session,\n \"eth_sendTransaction\",\n [\n {\n from: fromAccount,\n to: call.to,\n value: call.value,\n data: call.data,\n },\n ],\n resolvedChainId,\n );\n txHashes.push(hash);\n }\n return txHashes.length === 1 ? txHashes[0] : txHashes.join(\",\");\n }\n }\n\n async getCapabilities(\n session: UniversalWalletSession,\n ): Promise<Record<string, WalletCapabilities>> {\n const capabilities: Record<string, WalletCapabilities> = {};\n\n for (const ns of Object.values(session.namespaces)) {\n const nsCaps = (ns.capabilities ?? {}) as Record<string, unknown>;\n const atomicBatchSupported = Boolean(nsCaps.atomicBatch);\n\n for (const chain of ns.chains) {\n capabilities[chain] = {\n atomicBatch: atomicBatchSupported\n ? { supported: true, maxBatchSize: 5 }\n : { supported: false },\n paymasterService: nsCaps.paymasterService\n ? { supported: true }\n : undefined,\n };\n }\n }\n\n return capabilities;\n }\n\n async getCallsStatus(\n session: UniversalWalletSession,\n bundleHash: string,\n ): Promise<import(\"@naculus/connect-core\").CallsStatus> {\n try {\n return await this.makeRequest<\n import(\"@naculus/connect-core\").CallsStatus\n >(session, \"wallet_getCallsStatus\", [bundleHash]);\n } catch {\n return { status: \"PENDING\" };\n }\n }\n\n async request(request: {\n method: string;\n params: unknown[];\n }): Promise<unknown> {\n const session = this.lastSession;\n if (!session)\n throw new WalletError(\n \"session_expired\",\n CONNECTOR_ERROR_MESSAGES.SESSION_EXPIRED,\n );\n return this.makeRequest(\n session,\n request.method,\n request.params,\n this.getDefaultChainId(session),\n );\n }\n\n async getBalance(chainId?: string): Promise<string> {\n const session = this.lastSession;\n if (!session)\n throw new WalletError(\n \"session_expired\",\n CONNECTOR_ERROR_MESSAGES.SESSION_EXPIRED,\n );\n const cId = chainId ?? this.getDefaultChainId(session);\n const rpcUrl = DEFAULT_RPC_URLS[cId];\n if (!rpcUrl)\n throw new WalletError(\"chain_unsupported\", \"No RPC URL for chain \" + cId);\n const allAccounts = extractAccounts(session.namespaces);\n const address = allAccounts[0]?.split(\":\").pop();\n if (!address)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.NO_ACCOUNTS,\n );\n const response = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n }),\n });\n const data = await response.json();\n return data.result;\n }\n\n async deepLink(target: string): Promise<void> {\n if (typeof window === \"undefined\") {\n return;\n }\n\n const uri = this.lastUri;\n if (!uri) {\n throw new WalletError(\n \"deeplink_timeout\",\n \"WalletConnect URI unavailable.\",\n );\n }\n\n const url = `${target}${target.includes(\"?\") ? \"&\" : \"?\"}uri=${encodeURIComponent(uri)}`;\n window.location.assign(url);\n }\n\n private getDefaultChainId(session: UniversalWalletSession): string {\n const evmNamespace = session.namespaces[\"eip155\"];\n if (evmNamespace && evmNamespace.chains.length > 0) {\n return evmNamespace.chains[0];\n }\n\n const solanaNamespace = session.namespaces[\"solana\"];\n if (solanaNamespace && solanaNamespace.chains.length > 0) {\n return solanaNamespace.chains[0];\n }\n\n return EIP155_MAINNET;\n }\n\n /**\n * Ensures session has a topic for WalletConnect operations\n * @throws WalletError if session topic is missing\n */\n private requireSessionTopic(session: UniversalWalletSession): string {\n if (!session.topic) {\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session missing topic.\",\n );\n }\n return session.topic;\n }\n\n /**\n * Determines if a chain ID is a Solana chain\n */\n private isSolanaChain(chainId: string | undefined): boolean {\n return chainId?.startsWith(\"solana:\") ?? false;\n }\n\n /**\n * Hex-encodes a message for Ethereum JSON-RPC personal_sign\n * Converts a UTF-8 string to a 0x-prefixed hex string\n */\n private hexEncode(message: string): string {\n // Already hex-encoded\n if (/^0x[0-9a-fA-F]*$/.test(message)) return message;\n\n const bytes = new TextEncoder().encode(message);\n let hex = \"0x\";\n for (let i = 0; i < bytes.length; i++) {\n hex += bytes[i].toString(16).padStart(2, \"0\");\n }\n return hex;\n }\n\n /**\n * Signs typed data using eth_signTypedData_v4\n * Convenience method that wraps signMessage with explicit typed data handling.\n *\n * @param session - Active wallet session\n * @param input - Object with `typedData` (stringified EIP-712 typed data) and `address`\n * @returns Signature hex string\n */\n async signTypedData(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const typedData =\n typeof inputObj.typedData === \"string\" ? inputObj.typedData : undefined;\n const rawAddress =\n typeof inputObj.address === \"string\" ? inputObj.address : undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n\n if (!typedData || !rawAddress)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n\n const address = rawAddress.includes(\":\")\n ? rawAddress.split(\":\").pop()!\n : rawAddress;\n\n if (this.isSolanaChain(chainId)) {\n throw new WalletError(\n \"method_not_allowed\",\n \"signTypedData not supported for Solana.\",\n );\n }\n\n try {\n return await this.makeRequest(\n session,\n \"eth_signTypedData_v4\",\n [address, typedData],\n chainId,\n );\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect signTypedData_v4 rejected.\",\n error,\n );\n }\n }\n\n /**\n * Makes a request to WalletConnect with standardized error handling\n */\n private async makeRequest<T>(\n session: UniversalWalletSession,\n method: string,\n params: unknown[],\n chainId?: string,\n ): Promise<T> {\n const client = await this.getClient();\n const topic = this.requireSessionTopic(session);\n const resolvedChainId = chainId ?? this.getDefaultChainId(session);\n\n try {\n return (await client.request({\n topic,\n chainId: resolvedChainId,\n request: { method, params },\n })) as T;\n } catch (error) {\n // Preserve original error message so callers (e.g. signMessage fallback)\n // can detect specific rejection patterns like \"not authorized\".\n // WalletConnect wraps errors from mobile wallets (MetaMask Mobile, Rainbow, etc.)\n // as generic JSON-RPC errors — we need the original message to distinguish\n // between \"method not authorized\" and actual signing failures.\n const originalMessage =\n error instanceof Error ? error.message : String(error);\n throw new WalletError(\"signature_rejected\", originalMessage, {\n method,\n originalError: error,\n });\n }\n }\n\n onSessionExpiry(handler: () => void): void {\n this.sessionExpiryHandler = handler;\n }\n\n /** URI for QR code display */\n get uri(): string | undefined {\n return this.lastUri;\n }\n\n /**\n * Start WalletConnect pairing, returns URI for QR code\n * Call this to get the pairing URI, then display the QR code\n */\n async startPairing(): Promise<string> {\n const client = await this.getClient();\n const requiredNamespaces = buildRequiredNamespaces();\n const result = await client.connect({ requiredNamespaces });\n if (!result.uri) throw new WalletError(\"wallet_unavailable\", \"No URI\");\n this.lastUri = result.uri;\n this.pendingApproval =\n result.approval as unknown as () => Promise<UniversalWalletSession>;\n return result.uri;\n }\n\n /**\n * Complete pairing after user scans QR code\n * Should be called after displaying the QR and user has scanned it\n */\n async completePairing(): Promise<UniversalWalletSession> {\n if (!this.pendingApproval)\n throw new WalletError(\"wallet_unavailable\", \"No pending approval\");\n\n const pendingResult = await this.pendingApproval();\n const pendingSession = pendingResult as unknown as Record<string, unknown>;\n const pendingNamespaces = pendingSession.namespaces as Record<\n string,\n {\n chains?: string[];\n accounts: string[];\n methods: string[];\n events: string[];\n capabilities?: Record<string, unknown>;\n }\n >;\n const pendingTopic = pendingSession.topic as string | undefined;\n const pendingPeerName = (\n pendingSession.peer as Record<string, unknown> | undefined\n )?.metadata as Record<string, unknown> | undefined;\n const peerName =\n typeof pendingPeerName?.name === \"string\"\n ? pendingPeerName.name\n : \"walletconnect\";\n this.pendingApproval = undefined;\n\n const namespaces = mapNamespaces(pendingNamespaces);\n const ws = createEmptySession({\n id: crypto.randomUUID(),\n topic: pendingTopic,\n walletId: peerName,\n walletType: \"walletconnect\",\n namespaces,\n platform: detectPlatform(),\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n this.lastSession = ws;\n return ws;\n }\n}\n\nexport function createWalletConnectConnector(\n config: WalletConnectConfig,\n): WalletConnectConnector {\n return new WalletConnectConnector(config);\n}\n","export interface CAIP25NamespaceProposal {\n chains?: string[];\n methods: string[];\n events: string[];\n}\n\nexport interface CAIP25SessionProposal {\n requiredNamespaces: Record<string, CAIP25NamespaceProposal>;\n optionalNamespaces?: Record<string, CAIP25NamespaceProposal>;\n}\n\nexport interface CAIP25ValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\nconst CAIP2_REGEX = /^[-a-z0-9]{1,32}:[-a-zA-Z0-9]{1,64}$/;\n\nexport function isValidCAIP2(chainId: string): boolean {\n return CAIP2_REGEX.test(chainId);\n}\n\nexport function validateCAIP25Namespace(\n namespace: string,\n proposal: CAIP25NamespaceProposal,\n required: boolean,\n): string[] {\n const errors: string[] = [];\n\n if (required && (!proposal.chains || proposal.chains.length === 0)) {\n errors.push(`Namespace \"${namespace}\": chains are required`);\n }\n\n if (proposal.chains) {\n for (const chainId of proposal.chains) {\n if (!isValidCAIP2(chainId)) {\n errors.push(\n `Namespace \"${namespace}\": invalid CAIP-2 chain \"${chainId}\"`,\n );\n }\n }\n }\n\n if (required && (!proposal.methods || proposal.methods.length === 0)) {\n errors.push(`Namespace \"${namespace}\": methods are required`);\n }\n\n if (!proposal.events) {\n errors.push(`Namespace \"${namespace}\": events array is required`);\n }\n\n return errors;\n}\n\nexport function validateCAIP25Proposal(\n proposal: CAIP25SessionProposal,\n): CAIP25ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (\n !proposal.requiredNamespaces ||\n Object.keys(proposal.requiredNamespaces).length === 0\n ) {\n errors.push(\"requiredNamespaces is required and cannot be empty\");\n } else {\n for (const [namespace, nsProposal] of Object.entries(\n proposal.requiredNamespaces,\n )) {\n const namespaceErrors = validateCAIP25Namespace(\n namespace,\n nsProposal,\n true,\n );\n errors.push(...namespaceErrors);\n }\n }\n\n if (proposal.optionalNamespaces) {\n for (const [namespace, nsProposal] of Object.entries(\n proposal.optionalNamespaces,\n )) {\n if (!proposal.requiredNamespaces[namespace]) {\n const namespaceErrors = validateCAIP25Namespace(\n namespace,\n nsProposal,\n false,\n );\n warnings.push(...namespaceErrors.map((e) => `optional: ${e}`));\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n","import type { Namespace, SessionNamespace } from \"@naculus/connect-core\";\nimport type SignClient from \"@walletconnect/sign-client\";\nimport type { ProposalTypes } from \"@walletconnect/types\";\n\n/**\n * WalletConnect v2 configuration metadata\n */\nexport type WalletConnectMetadata = {\n /** Application name displayed in WalletConnect modal */\n name: string;\n /** Application description */\n description: string;\n /** Application website URL */\n url: string;\n /** Application icon URLs */\n icons: string[];\n};\n\n/**\n * Configuration options for WalletConnectConnector\n */\nexport type WalletConnectConfig = {\n /** WalletConnect v2 project ID from cloud.walletconnect.com */\n projectId: string;\n /** Optional custom relay URL (defaults to WalletConnect cloud) */\n relayUrl?: string;\n /** Application metadata for WalletConnect pairing */\n metadata: WalletConnectMetadata;\n /** Pre-initialized SignClient instance (for testing) */\n client?: SignClient;\n};\n\n/**\n * Input options for connect method\n */\nexport type WalletConnectConnectInput = {\n /** Custom required namespaces override */\n requiredNamespaces?: ProposalTypes.RequiredNamespaces;\n /** Optional namespaces (informational validation only) */\n optionalNamespaces?: ProposalTypes.OptionalNamespaces;\n};\n\n/** Default EVM RPC methods for WalletConnect */\nexport const DEFAULT_EVM_METHODS = [\n \"eth_accounts\",\n \"eth_requestAccounts\",\n \"personal_sign\",\n \"eth_sign\",\n \"eth_signTransaction\",\n \"eth_sendTransaction\",\n \"eth_sendRawTransaction\",\n \"eth_signTypedData_v4\",\n \"wallet_switchEthereumChain\",\n] as const;\n\n/** Default EVM event subscriptions */\nexport const DEFAULT_EVM_EVENTS = [\n \"accountsChanged\",\n \"chainChanged\",\n \"disconnect\",\n \"connect\",\n \"message\",\n] as const;\n\n/** Default Solana methods for WalletConnect */\nexport const DEFAULT_SOLANA_METHODS = [\n \"solana_signMessage\",\n \"solana_signTransaction\",\n \"solana_sendTransaction\",\n] as const;\n\n/** Default Solana event subscriptions */\nexport const DEFAULT_SOLANA_EVENTS = [\"accountChanged\", \"disconnect\"] as const;\n\nexport function toHexValue(value: string): string {\n if (value.startsWith(\"0x\")) return value;\n return `0x${BigInt(value).toString(16)}`;\n}\n\n// ── CAIP-10 Helpers ─────────────────────────────────────────────────────\n\n/**\n * Parses a CAIP-10 address (namespace:chainId:address) into components.\n * Returns undefined if the address doesn't match CAIP-10 format.\n */\nexport function parseCAIP10(\n caip10: string,\n): { namespace: string; chainId: string; address: string } | undefined {\n const parts = caip10.split(\":\");\n // CAIP-10: namespace:chainId:address (3 parts)\n if (parts.length === 3) {\n return { namespace: parts[0], chainId: parts[1], address: parts[2] };\n }\n return undefined;\n}\n\n/**\n * Extracts the raw address from a CAIP-10 string.\n * If already a plain address, returns it as-is.\n */\nexport function extractAddress(caipOrAddress: string): string {\n const parsed = parseCAIP10(caipOrAddress);\n return parsed ? parsed.address : caipOrAddress;\n}\n\n/**\n * Builds a CAIP-10 address string from components.\n */\nexport function buildCAIP10(\n namespace: string,\n chainId: string,\n address: string,\n): string {\n const cleanAddress = address.replace(/^0x/, \"\");\n return `${namespace}:${chainId}:${cleanAddress}`;\n}\n\n/**\n * Resolves an account address to its CAIP-10 representation using the session's\n * namespace information. If no matching namespace is found, returns the raw address.\n */\nexport function resolveCAIP10(\n address: string,\n namespaces: Record<string, { chains?: string[]; accounts: string[] }>,\n preferredNamespace?: string,\n): string {\n // If already CAIP-10, return as-is\n if (address.includes(\":\") && address.split(\":\").length === 3) {\n return address;\n }\n\n const nsKeys = preferredNamespace\n ? [\n preferredNamespace,\n ...Object.keys(namespaces).filter((k) => k !== preferredNamespace),\n ]\n : Object.keys(namespaces);\n\n for (const ns of nsKeys) {\n const nsData = namespaces[ns];\n if (!nsData) continue;\n\n for (const account of nsData.accounts) {\n const parsed = parseCAIP10(account);\n if (parsed && parsed.address.toLowerCase() === address.toLowerCase()) {\n return account;\n }\n }\n\n // If chains exist, construct from first chain\n if (nsData.chains && nsData.chains.length > 0) {\n return buildCAIP10(\n ns,\n nsData.chains[0].split(\":\")[1] || nsData.chains[0],\n address,\n );\n }\n }\n\n // Fallback: use eip155:1 as default\n return buildCAIP10(\"eip155\", \"1\", address);\n}\n\n/**\n * Resolves multiple accounts to their CAIP-10 representations.\n */\nexport function resolveCAIP10List(\n addresses: string[],\n namespaces: Record<string, { chains?: string[]; accounts: string[] }>,\n): string[] {\n return addresses.map((addr) => resolveCAIP10(addr, namespaces));\n}\n\n/**\n * Validates a CAIP-10 address string.\n * Format: namespace:chainId:address\n */\nexport function isValidCAIP10(addr: string): boolean {\n return addr.includes(\":\") && addr.split(\":\").length === 3;\n}\n\n/**\n * Maps WalletConnect namespace format to SDK namespace format\n * @param namespaces - Raw namespace object from WalletConnect session\n * @returns Normalized namespace record\n */\nexport function mapNamespaces(\n namespaces: Record<\n string,\n {\n chains?: string[];\n accounts: string[];\n methods: string[];\n events: string[];\n capabilities?: Record<string, unknown>;\n }\n >,\n): Record<Namespace, SessionNamespace> {\n return Object.entries(namespaces).reduce<Record<Namespace, SessionNamespace>>(\n (acc, [key, value]) => {\n acc[key as Namespace] = {\n chains: value.chains ?? [],\n accounts: value.accounts,\n methods: value.methods,\n events: value.events,\n capabilities: value.capabilities ?? {},\n };\n\n return acc;\n },\n {} as Record<Namespace, SessionNamespace>,\n );\n}\n\n/**\n * Builds default required namespaces for EIP-155 and Solana\n * Includes mainnet, testnet, and popular L2 chains\n */\nexport function buildRequiredNamespaces(): ProposalTypes.RequiredNamespaces {\n return {\n eip155: {\n chains: [\n \"eip155:1\", // Ethereum Mainnet\n \"eip155:11155111\", // Sepolia Testnet\n \"eip155:137\", // Polygon Mainnet\n \"eip155:42161\", // Arbitrum One\n \"eip155:10\", // Optimism\n \"eip155:8453\", // Base\n ],\n methods: [...DEFAULT_EVM_METHODS],\n events: [...DEFAULT_EVM_EVENTS],\n },\n solana: {\n chains: [\n \"solana:0\", // Solana Mainnet\n \"solana:1\", // Solana Devnet\n \"solana:2\", // Solana Testnet\n ],\n methods: [...DEFAULT_SOLANA_METHODS],\n events: [...DEFAULT_SOLANA_EVENTS],\n },\n };\n}\n"],"mappings":"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","names":["index_exports","__export","WalletConnectConnector","buildRequiredNamespaces","createWalletConnectConnector","extractAddress","isValidCAIP10","mapNamespaces","parseCAIP10","toHexValue","__toCommonJS","import_connect_core","import_base","import_sign_client","CAIP2_REGEX","isValidCAIP2","chainId","validateCAIP25Namespace","namespace","proposal","required","errors","validateCAIP25Proposal","warnings","nsProposal","namespaceErrors","e","DEFAULT_EVM_METHODS","DEFAULT_EVM_EVENTS","DEFAULT_SOLANA_METHODS","DEFAULT_SOLANA_EVENTS","toHexValue","value","parseCAIP10","caip10","parts","extractAddress","caipOrAddress","parsed","isValidCAIP10","addr","mapNamespaces","namespaces","acc","key","value","buildRequiredNamespaces","DEFAULT_EVM_METHODS","DEFAULT_EVM_EVENTS","DEFAULT_SOLANA_METHODS","DEFAULT_SOLANA_EVENTS","WalletConnectConnector","config","SignClient","event","input","client","connectInput","requiredNamespacesRaw","optionalNamespacesRaw","requiredNamespaces","buildRequiredNamespaces","validation","validateCAIP25Proposal","connectParams","uri","approval","session","namespaces","mapNamespaces","walletSession","error","message","existing","inputObj","rawAddress","chainId","address","messageBytes","base58Msg","tryMethods","lastError","tryMethod","tryParams","errMsg","transaction","method","signedTx","isSolana","tx","toHexValue","calls","resolvedChainId","fromAccount","txHashes","call","hash","capabilities","ns","nsCaps","atomicBatchSupported","chain","bundleHash","request","cId","rpcUrl","target","url","evmNamespace","solanaNamespace","bytes","hex","i","typedData","params","topic","originalMessage","handler","result","pendingSession","pendingNamespaces","pendingTopic","pendingPeerName","peerName","ws","createWalletConnectConnector"]}
@@ -0,0 +1,186 @@
1
+ import * as _naculus_connect_core from '@naculus/connect-core';
2
+ import { Namespace, SessionNamespace, UniversalConnector, UniversalWalletSession, BatchCall, WalletCapabilities } from '@naculus/connect-core';
3
+ import SignClient from '@walletconnect/sign-client';
4
+ import { ProposalTypes } from '@walletconnect/types';
5
+
6
+ /**
7
+ * WalletConnect v2 configuration metadata
8
+ */
9
+ type WalletConnectMetadata = {
10
+ /** Application name displayed in WalletConnect modal */
11
+ name: string;
12
+ /** Application description */
13
+ description: string;
14
+ /** Application website URL */
15
+ url: string;
16
+ /** Application icon URLs */
17
+ icons: string[];
18
+ };
19
+ /**
20
+ * Configuration options for WalletConnectConnector
21
+ */
22
+ type WalletConnectConfig = {
23
+ /** WalletConnect v2 project ID from cloud.walletconnect.com */
24
+ projectId: string;
25
+ /** Optional custom relay URL (defaults to WalletConnect cloud) */
26
+ relayUrl?: string;
27
+ /** Application metadata for WalletConnect pairing */
28
+ metadata: WalletConnectMetadata;
29
+ /** Pre-initialized SignClient instance (for testing) */
30
+ client?: SignClient;
31
+ };
32
+ /**
33
+ * Input options for connect method
34
+ */
35
+ type WalletConnectConnectInput = {
36
+ /** Custom required namespaces override */
37
+ requiredNamespaces?: ProposalTypes.RequiredNamespaces;
38
+ /** Optional namespaces (informational validation only) */
39
+ optionalNamespaces?: ProposalTypes.OptionalNamespaces;
40
+ };
41
+ declare function toHexValue(value: string): string;
42
+ /**
43
+ * Parses a CAIP-10 address (namespace:chainId:address) into components.
44
+ * Returns undefined if the address doesn't match CAIP-10 format.
45
+ */
46
+ declare function parseCAIP10(caip10: string): {
47
+ namespace: string;
48
+ chainId: string;
49
+ address: string;
50
+ } | undefined;
51
+ /**
52
+ * Extracts the raw address from a CAIP-10 string.
53
+ * If already a plain address, returns it as-is.
54
+ */
55
+ declare function extractAddress(caipOrAddress: string): string;
56
+ /**
57
+ * Validates a CAIP-10 address string.
58
+ * Format: namespace:chainId:address
59
+ */
60
+ declare function isValidCAIP10(addr: string): boolean;
61
+ /**
62
+ * Maps WalletConnect namespace format to SDK namespace format
63
+ * @param namespaces - Raw namespace object from WalletConnect session
64
+ * @returns Normalized namespace record
65
+ */
66
+ declare function mapNamespaces(namespaces: Record<string, {
67
+ chains?: string[];
68
+ accounts: string[];
69
+ methods: string[];
70
+ events: string[];
71
+ capabilities?: Record<string, unknown>;
72
+ }>): Record<Namespace, SessionNamespace>;
73
+ /**
74
+ * Builds default required namespaces for EIP-155 and Solana
75
+ * Includes mainnet, testnet, and popular L2 chains
76
+ */
77
+ declare function buildRequiredNamespaces(): ProposalTypes.RequiredNamespaces;
78
+
79
+ /**
80
+ * WalletConnect v2 Connector for connect SDK
81
+ *
82
+ * Supports EVM chains and Solana through WalletConnect's multi-chain namespace.
83
+ * Provides QR code pairing for desktop and deep link support for mobile.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const connector = new WalletConnectConnector({
88
+ * projectId: process.env.VITE_WALLETCONNECT_PROJECT_ID,
89
+ * metadata: {
90
+ * name: "My DApp",
91
+ * description: "Connect to My DApp",
92
+ * url: window.location.origin,
93
+ * icons: [window.location.origin + "/icon.png"]
94
+ * }
95
+ * });
96
+ * ```
97
+ */
98
+ declare class WalletConnectConnector implements UniversalConnector {
99
+ /** Unique connector identifier */
100
+ readonly id = "walletconnect";
101
+ /** Display name for UI */
102
+ readonly name = "WalletConnect";
103
+ /** Connector type identifier */
104
+ readonly kind: "walletconnect";
105
+ /** Supported chain namespaces */
106
+ readonly namespaces: string[];
107
+ /** Feature support flags */
108
+ readonly supports: {
109
+ readonly desktop: true;
110
+ readonly mobile: true;
111
+ readonly deepLink: true;
112
+ readonly qr: true;
113
+ readonly trustedReconnect: true;
114
+ };
115
+ /** Connector configuration */
116
+ readonly config: WalletConnectConfig;
117
+ private client;
118
+ private lastSession?;
119
+ private lastUri?;
120
+ private pendingApproval?;
121
+ private sessionExpiryHandler?;
122
+ constructor(config: WalletConnectConfig);
123
+ private getClient;
124
+ connect(input?: unknown): Promise<UniversalWalletSession>;
125
+ reconnect(session: UniversalWalletSession): Promise<UniversalWalletSession>;
126
+ disconnect(session: UniversalWalletSession): Promise<void>;
127
+ getAccounts(session: UniversalWalletSession): Promise<string[]>;
128
+ signMessage(session: UniversalWalletSession, input: unknown): Promise<unknown>;
129
+ signTransaction(session: UniversalWalletSession, input: unknown): Promise<unknown>;
130
+ sendRawTransaction(session: UniversalWalletSession, input: unknown): Promise<unknown>;
131
+ sendTransaction(session: UniversalWalletSession, input: unknown): Promise<unknown>;
132
+ switchChain(session: UniversalWalletSession, chainId: string): Promise<void>;
133
+ sendCalls(session: UniversalWalletSession, calls: BatchCall[], chainId?: string): Promise<string>;
134
+ getCapabilities(session: UniversalWalletSession): Promise<Record<string, WalletCapabilities>>;
135
+ getCallsStatus(session: UniversalWalletSession, bundleHash: string): Promise<_naculus_connect_core.CallsStatus>;
136
+ request(request: {
137
+ method: string;
138
+ params: unknown[];
139
+ }): Promise<unknown>;
140
+ getBalance(chainId?: string): Promise<string>;
141
+ deepLink(target: string): Promise<void>;
142
+ private getDefaultChainId;
143
+ /**
144
+ * Ensures session has a topic for WalletConnect operations
145
+ * @throws WalletError if session topic is missing
146
+ */
147
+ private requireSessionTopic;
148
+ /**
149
+ * Determines if a chain ID is a Solana chain
150
+ */
151
+ private isSolanaChain;
152
+ /**
153
+ * Hex-encodes a message for Ethereum JSON-RPC personal_sign
154
+ * Converts a UTF-8 string to a 0x-prefixed hex string
155
+ */
156
+ private hexEncode;
157
+ /**
158
+ * Signs typed data using eth_signTypedData_v4
159
+ * Convenience method that wraps signMessage with explicit typed data handling.
160
+ *
161
+ * @param session - Active wallet session
162
+ * @param input - Object with `typedData` (stringified EIP-712 typed data) and `address`
163
+ * @returns Signature hex string
164
+ */
165
+ signTypedData(session: UniversalWalletSession, input: unknown): Promise<unknown>;
166
+ /**
167
+ * Makes a request to WalletConnect with standardized error handling
168
+ */
169
+ private makeRequest;
170
+ onSessionExpiry(handler: () => void): void;
171
+ /** URI for QR code display */
172
+ get uri(): string | undefined;
173
+ /**
174
+ * Start WalletConnect pairing, returns URI for QR code
175
+ * Call this to get the pairing URI, then display the QR code
176
+ */
177
+ startPairing(): Promise<string>;
178
+ /**
179
+ * Complete pairing after user scans QR code
180
+ * Should be called after displaying the QR and user has scanned it
181
+ */
182
+ completePairing(): Promise<UniversalWalletSession>;
183
+ }
184
+ declare function createWalletConnectConnector(config: WalletConnectConfig): WalletConnectConnector;
185
+
186
+ export { type WalletConnectConfig, type WalletConnectConnectInput, WalletConnectConnector, type WalletConnectMetadata, buildRequiredNamespaces, createWalletConnectConnector, extractAddress, isValidCAIP10, mapNamespaces, parseCAIP10, toHexValue };
@@ -0,0 +1,186 @@
1
+ import * as _naculus_connect_core from '@naculus/connect-core';
2
+ import { Namespace, SessionNamespace, UniversalConnector, UniversalWalletSession, BatchCall, WalletCapabilities } from '@naculus/connect-core';
3
+ import SignClient from '@walletconnect/sign-client';
4
+ import { ProposalTypes } from '@walletconnect/types';
5
+
6
+ /**
7
+ * WalletConnect v2 configuration metadata
8
+ */
9
+ type WalletConnectMetadata = {
10
+ /** Application name displayed in WalletConnect modal */
11
+ name: string;
12
+ /** Application description */
13
+ description: string;
14
+ /** Application website URL */
15
+ url: string;
16
+ /** Application icon URLs */
17
+ icons: string[];
18
+ };
19
+ /**
20
+ * Configuration options for WalletConnectConnector
21
+ */
22
+ type WalletConnectConfig = {
23
+ /** WalletConnect v2 project ID from cloud.walletconnect.com */
24
+ projectId: string;
25
+ /** Optional custom relay URL (defaults to WalletConnect cloud) */
26
+ relayUrl?: string;
27
+ /** Application metadata for WalletConnect pairing */
28
+ metadata: WalletConnectMetadata;
29
+ /** Pre-initialized SignClient instance (for testing) */
30
+ client?: SignClient;
31
+ };
32
+ /**
33
+ * Input options for connect method
34
+ */
35
+ type WalletConnectConnectInput = {
36
+ /** Custom required namespaces override */
37
+ requiredNamespaces?: ProposalTypes.RequiredNamespaces;
38
+ /** Optional namespaces (informational validation only) */
39
+ optionalNamespaces?: ProposalTypes.OptionalNamespaces;
40
+ };
41
+ declare function toHexValue(value: string): string;
42
+ /**
43
+ * Parses a CAIP-10 address (namespace:chainId:address) into components.
44
+ * Returns undefined if the address doesn't match CAIP-10 format.
45
+ */
46
+ declare function parseCAIP10(caip10: string): {
47
+ namespace: string;
48
+ chainId: string;
49
+ address: string;
50
+ } | undefined;
51
+ /**
52
+ * Extracts the raw address from a CAIP-10 string.
53
+ * If already a plain address, returns it as-is.
54
+ */
55
+ declare function extractAddress(caipOrAddress: string): string;
56
+ /**
57
+ * Validates a CAIP-10 address string.
58
+ * Format: namespace:chainId:address
59
+ */
60
+ declare function isValidCAIP10(addr: string): boolean;
61
+ /**
62
+ * Maps WalletConnect namespace format to SDK namespace format
63
+ * @param namespaces - Raw namespace object from WalletConnect session
64
+ * @returns Normalized namespace record
65
+ */
66
+ declare function mapNamespaces(namespaces: Record<string, {
67
+ chains?: string[];
68
+ accounts: string[];
69
+ methods: string[];
70
+ events: string[];
71
+ capabilities?: Record<string, unknown>;
72
+ }>): Record<Namespace, SessionNamespace>;
73
+ /**
74
+ * Builds default required namespaces for EIP-155 and Solana
75
+ * Includes mainnet, testnet, and popular L2 chains
76
+ */
77
+ declare function buildRequiredNamespaces(): ProposalTypes.RequiredNamespaces;
78
+
79
+ /**
80
+ * WalletConnect v2 Connector for connect SDK
81
+ *
82
+ * Supports EVM chains and Solana through WalletConnect's multi-chain namespace.
83
+ * Provides QR code pairing for desktop and deep link support for mobile.
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const connector = new WalletConnectConnector({
88
+ * projectId: process.env.VITE_WALLETCONNECT_PROJECT_ID,
89
+ * metadata: {
90
+ * name: "My DApp",
91
+ * description: "Connect to My DApp",
92
+ * url: window.location.origin,
93
+ * icons: [window.location.origin + "/icon.png"]
94
+ * }
95
+ * });
96
+ * ```
97
+ */
98
+ declare class WalletConnectConnector implements UniversalConnector {
99
+ /** Unique connector identifier */
100
+ readonly id = "walletconnect";
101
+ /** Display name for UI */
102
+ readonly name = "WalletConnect";
103
+ /** Connector type identifier */
104
+ readonly kind: "walletconnect";
105
+ /** Supported chain namespaces */
106
+ readonly namespaces: string[];
107
+ /** Feature support flags */
108
+ readonly supports: {
109
+ readonly desktop: true;
110
+ readonly mobile: true;
111
+ readonly deepLink: true;
112
+ readonly qr: true;
113
+ readonly trustedReconnect: true;
114
+ };
115
+ /** Connector configuration */
116
+ readonly config: WalletConnectConfig;
117
+ private client;
118
+ private lastSession?;
119
+ private lastUri?;
120
+ private pendingApproval?;
121
+ private sessionExpiryHandler?;
122
+ constructor(config: WalletConnectConfig);
123
+ private getClient;
124
+ connect(input?: unknown): Promise<UniversalWalletSession>;
125
+ reconnect(session: UniversalWalletSession): Promise<UniversalWalletSession>;
126
+ disconnect(session: UniversalWalletSession): Promise<void>;
127
+ getAccounts(session: UniversalWalletSession): Promise<string[]>;
128
+ signMessage(session: UniversalWalletSession, input: unknown): Promise<unknown>;
129
+ signTransaction(session: UniversalWalletSession, input: unknown): Promise<unknown>;
130
+ sendRawTransaction(session: UniversalWalletSession, input: unknown): Promise<unknown>;
131
+ sendTransaction(session: UniversalWalletSession, input: unknown): Promise<unknown>;
132
+ switchChain(session: UniversalWalletSession, chainId: string): Promise<void>;
133
+ sendCalls(session: UniversalWalletSession, calls: BatchCall[], chainId?: string): Promise<string>;
134
+ getCapabilities(session: UniversalWalletSession): Promise<Record<string, WalletCapabilities>>;
135
+ getCallsStatus(session: UniversalWalletSession, bundleHash: string): Promise<_naculus_connect_core.CallsStatus>;
136
+ request(request: {
137
+ method: string;
138
+ params: unknown[];
139
+ }): Promise<unknown>;
140
+ getBalance(chainId?: string): Promise<string>;
141
+ deepLink(target: string): Promise<void>;
142
+ private getDefaultChainId;
143
+ /**
144
+ * Ensures session has a topic for WalletConnect operations
145
+ * @throws WalletError if session topic is missing
146
+ */
147
+ private requireSessionTopic;
148
+ /**
149
+ * Determines if a chain ID is a Solana chain
150
+ */
151
+ private isSolanaChain;
152
+ /**
153
+ * Hex-encodes a message for Ethereum JSON-RPC personal_sign
154
+ * Converts a UTF-8 string to a 0x-prefixed hex string
155
+ */
156
+ private hexEncode;
157
+ /**
158
+ * Signs typed data using eth_signTypedData_v4
159
+ * Convenience method that wraps signMessage with explicit typed data handling.
160
+ *
161
+ * @param session - Active wallet session
162
+ * @param input - Object with `typedData` (stringified EIP-712 typed data) and `address`
163
+ * @returns Signature hex string
164
+ */
165
+ signTypedData(session: UniversalWalletSession, input: unknown): Promise<unknown>;
166
+ /**
167
+ * Makes a request to WalletConnect with standardized error handling
168
+ */
169
+ private makeRequest;
170
+ onSessionExpiry(handler: () => void): void;
171
+ /** URI for QR code display */
172
+ get uri(): string | undefined;
173
+ /**
174
+ * Start WalletConnect pairing, returns URI for QR code
175
+ * Call this to get the pairing URI, then display the QR code
176
+ */
177
+ startPairing(): Promise<string>;
178
+ /**
179
+ * Complete pairing after user scans QR code
180
+ * Should be called after displaying the QR and user has scanned it
181
+ */
182
+ completePairing(): Promise<UniversalWalletSession>;
183
+ }
184
+ declare function createWalletConnectConnector(config: WalletConnectConfig): WalletConnectConnector;
185
+
186
+ export { type WalletConnectConfig, type WalletConnectConnectInput, WalletConnectConnector, type WalletConnectMetadata, buildRequiredNamespaces, createWalletConnectConnector, extractAddress, isValidCAIP10, mapNamespaces, parseCAIP10, toHexValue };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import{CONNECTOR_ERROR_MESSAGES as p,createEmptySession as y,DEFAULT_RPC_URLS as b,detectPlatform as _,EIP155_MAINNET as j,extractAccounts as S,WalletError as a,WC_DISCONNECT_USER as q}from"@naculus/connect-core";import{base58 as D}from"@scure/base";import O from"@walletconnect/sign-client";var R=/^[-a-z0-9]{1,32}:[-a-zA-Z0-9]{1,64}$/;function A(c){return R.test(c)}function N(c,e,t){let n=[];if(t&&(!e.chains||e.chains.length===0)&&n.push(`Namespace "${c}": chains are required`),e.chains)for(let s of e.chains)A(s)||n.push(`Namespace "${c}": invalid CAIP-2 chain "${s}"`);return t&&(!e.methods||e.methods.length===0)&&n.push(`Namespace "${c}": methods are required`),e.events||n.push(`Namespace "${c}": events array is required`),n}function P(c){let e=[],t=[];if(!c.requiredNamespaces||Object.keys(c.requiredNamespaces).length===0)e.push("requiredNamespaces is required and cannot be empty");else for(let[n,s]of Object.entries(c.requiredNamespaces)){let i=N(n,s,!0);e.push(...i)}if(c.optionalNamespaces){for(let[n,s]of Object.entries(c.optionalNamespaces))if(!c.requiredNamespaces[n]){let i=N(n,s,!1);t.push(...i.map(r=>`optional: ${r}`))}}return{valid:e.length===0,errors:e,warnings:t}}var T=["eth_accounts","eth_requestAccounts","personal_sign","eth_sign","eth_signTransaction","eth_sendTransaction","eth_sendRawTransaction","eth_signTypedData_v4","wallet_switchEthereumChain"],x=["accountsChanged","chainChanged","disconnect","connect","message"],W=["solana_signMessage","solana_signTransaction","solana_sendTransaction"],U=["accountChanged","disconnect"];function C(c){return c.startsWith("0x")?c:`0x${BigInt(c).toString(16)}`}function v(c){let e=c.split(":");if(e.length===3)return{namespace:e[0],chainId:e[1],address:e[2]}}function k(c){let e=v(c);return e?e.address:c}function E(c){return c.includes(":")&&c.split(":").length===3}function w(c){return Object.entries(c).reduce((e,[t,n])=>(e[t]={chains:n.chains??[],accounts:n.accounts,methods:n.methods,events:n.events,capabilities:n.capabilities??{}},e),{})}function f(){return{eip155:{chains:["eip155:1","eip155:11155111","eip155:137","eip155:42161","eip155:10","eip155:8453"],methods:[...T],events:[...x]},solana:{chains:["solana:0","solana:1","solana:2"],methods:[...W],events:[...U]}}}var I=class{id="walletconnect";name="WalletConnect";kind="walletconnect";namespaces=["eip155","solana"];supports={desktop:!0,mobile:!0,deepLink:!0,qr:!0,trustedReconnect:!0};config;client;lastSession;lastUri;pendingApproval;sessionExpiryHandler;constructor(e){this.config=e,this.client=e.client}async getClient(){return this.client?this.client:(this.client=await O.init({projectId:this.config.projectId,relayUrl:this.config.relayUrl,metadata:this.config.metadata}),this.client.on("session_delete",e=>{e.topic===this.lastSession?.topic&&this.sessionExpiryHandler?.()}),this.client.on("session_expire",e=>{e.topic===this.lastSession?.topic&&this.sessionExpiryHandler?.()}),this.client)}async connect(e){let t=await this.getClient(),n=e&&typeof e=="object"?e:void 0,s=n?.requiredNamespaces,i=n?.optionalNamespaces,r=s??f(),l=P({requiredNamespaces:r,optionalNamespaces:i});if(!l.valid)throw new a("invalid_proposal",`CAIP-25 validation failed: ${l.errors.join(", ")}`);try{let o={requiredNamespaces:r};i&&(o.optionalNamespaces=i);let{uri:d,approval:m}=await t.connect(o);d&&(this.lastUri=d);let u=await m(),h=w(u.namespaces),g=y({id:crypto.randomUUID(),topic:u.topic,walletId:u.peer.metadata?.name??"walletconnect",walletType:"walletconnect",namespaces:h,platform:_(),createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});return this.lastSession=g,g}catch(o){let d=o instanceof Error?o.message:"WalletConnect connect failed.";throw d.toLowerCase().includes("rejected")?new a("user_rejected",d,o):new a("wallet_unavailable",d,o)}}async reconnect(e){let t=await this.getClient();try{let n=t.session.get(e.topic??"");if(!n)throw new a("session_expired","WalletConnect session not found.");let s=w(n.namespaces),i=y({id:e.id,topic:n.topic,walletId:n.peer.metadata?.name??"walletconnect",walletType:"walletconnect",namespaces:s,platform:_(),createdAt:e.createdAt,updatedAt:new Date().toISOString()});return this.lastSession=i,i}catch(n){throw n instanceof a?n:new a("session_expired","WalletConnect session not found.",n)}}async disconnect(e){if(!e.topic)return;await(await this.getClient()).disconnect({topic:e.topic,reason:{code:q,message:"User disconnected"}})}async getAccounts(e){if(!e.topic)return S(e.namespaces);let n=(await this.getClient()).session.get(e.topic);if(!n)throw new a("session_expired","WalletConnect session expired.");return S(w(n.namespaces))}async signMessage(e,t){if(!t||typeof t!="object")throw new a("method_not_allowed",p.INVALID_INPUT);let n=t,s=typeof n.message=="string"?n.message:void 0,i=typeof n.address=="string"?n.address:void 0,r=typeof n.chainId=="string"?n.chainId:void 0;if(!s||!i)throw new a("method_not_allowed",p.MISSING_MESSAGE);let l=i.includes(":")?i.split(":").pop():i;if(this.isSolanaChain(r)){let m=new TextEncoder().encode(s),u=D.encode(m);return this.makeRequest(e,"solana_signMessage",[{message:u,pubkey:l}],r)}let o=s.startsWith("{")?["eth_signTypedData_v4"]:["personal_sign","eth_sign"],d;for(let m of o){let u;m==="personal_sign"?u=[l,this.hexEncode(s)]:m==="eth_sign"?u=[l,this.hexEncode(s)]:u=[s,l];try{return await this.makeRequest(e,m,u,r)}catch(h){d=h;let g=h instanceof Error?h.message.toLowerCase():"";if(!(g.includes("not been authorized")||g.includes("not authorized")||g.includes("not approved")||g.includes("method not found")||g.includes("method_not_allowed"))||o.length===1)throw h instanceof a?h:new a("signature_rejected","WalletConnect signature rejected.",h)}}throw d instanceof a?d:new a("signature_rejected","WalletConnect signature rejected.",d)}async signTransaction(e,t){if(!t||typeof t!="object")throw new a("method_not_allowed",p.INVALID_INPUT);let n=t,s=n.transaction,i=typeof n.chainId=="string"?n.chainId:void 0;if(!s)throw new a("method_not_allowed",p.MISSING_TX);let l=this.isSolanaChain(i)?"solana_signTransaction":"eth_signTransaction";try{return await this.makeRequest(e,l,[s],i)}catch(o){throw o instanceof a?o:new a("signature_rejected","WalletConnect sign transaction rejected.",o)}}async sendRawTransaction(e,t){if(!t||typeof t!="object")throw new a("method_not_allowed",p.INVALID_INPUT);let n=t,s=typeof n.signedTransaction=="string"?n.signedTransaction:void 0,i=typeof n.chainId=="string"?n.chainId:void 0;if(!s)throw new a("method_not_allowed","Missing signedTransaction parameter.");if(this.isSolanaChain(i))throw new a("method_not_allowed","sendRawTransaction not supported for Solana via WalletConnect.");try{return await this.makeRequest(e,"eth_sendRawTransaction",[s],i)}catch(r){throw r instanceof a?r:new a("tx_failed","WalletConnect sendRawTransaction failed.",r)}}async sendTransaction(e,t){if(!t||typeof t!="object")throw new a("method_not_allowed",p.INVALID_INPUT);let n=t,s=n.transaction,i=typeof n.chainId=="string"?n.chainId:void 0;if(!s)throw new a("method_not_allowed",p.MISSING_TX);let r=this.isSolanaChain(i),l=r?"solana_sendTransaction":"eth_sendTransaction",o=r?s:{...s,value:typeof s.value=="string"?C(s.value):s.value};try{return await this.makeRequest(e,l,[o],i)}catch(d){throw d instanceof a?d:new a("tx_failed","WalletConnect transaction failed.",d)}}async switchChain(e,t){if(!t.startsWith("eip155:"))throw new a("chain_unsupported","WalletConnect switchChain only supports EVM chains.");try{await this.makeRequest(e,"wallet_switchEthereumChain",[{chainId:`0x${Number(t.split(":")[1]).toString(16)}`}],t)}catch(n){throw n instanceof a?n:new a("chain_unsupported","WalletConnect switch chain failed.",n)}}async sendCalls(e,t,n){let s=n??this.getDefaultChainId(e);try{return await this.makeRequest(e,"wallet_sendCalls",[{calls:t,chainId:s}],s)}catch{let r=(e.namespaces.eip155?.accounts??[])[0]?.split(":").pop();if(!r)throw new a("session_expired",p.NO_ACCOUNT_TX);let l=[];for(let o of t){let d=await this.makeRequest(e,"eth_sendTransaction",[{from:r,to:o.to,value:o.value,data:o.data}],s);l.push(d)}return l.length===1?l[0]:l.join(",")}}async getCapabilities(e){let t={};for(let n of Object.values(e.namespaces)){let s=n.capabilities??{},i=!!s.atomicBatch;for(let r of n.chains)t[r]={atomicBatch:i?{supported:!0,maxBatchSize:5}:{supported:!1},paymasterService:s.paymasterService?{supported:!0}:void 0}}return t}async getCallsStatus(e,t){try{return await this.makeRequest(e,"wallet_getCallsStatus",[t])}catch{return{status:"PENDING"}}}async request(e){let t=this.lastSession;if(!t)throw new a("session_expired",p.SESSION_EXPIRED);return this.makeRequest(t,e.method,e.params,this.getDefaultChainId(t))}async getBalance(e){let t=this.lastSession;if(!t)throw new a("session_expired",p.SESSION_EXPIRED);let n=e??this.getDefaultChainId(t),s=b[n];if(!s)throw new a("chain_unsupported","No RPC URL for chain "+n);let r=S(t.namespaces)[0]?.split(":").pop();if(!r)throw new a("method_not_allowed",p.NO_ACCOUNTS);return(await(await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:"eth_getBalance",params:[r,"latest"]})})).json()).result}async deepLink(e){if(typeof window>"u")return;let t=this.lastUri;if(!t)throw new a("deeplink_timeout","WalletConnect URI unavailable.");let n=`${e}${e.includes("?")?"&":"?"}uri=${encodeURIComponent(t)}`;window.location.assign(n)}getDefaultChainId(e){let t=e.namespaces.eip155;if(t&&t.chains.length>0)return t.chains[0];let n=e.namespaces.solana;return n&&n.chains.length>0?n.chains[0]:j}requireSessionTopic(e){if(!e.topic)throw new a("session_expired","WalletConnect session missing topic.");return e.topic}isSolanaChain(e){return e?.startsWith("solana:")??!1}hexEncode(e){if(/^0x[0-9a-fA-F]*$/.test(e))return e;let t=new TextEncoder().encode(e),n="0x";for(let s=0;s<t.length;s++)n+=t[s].toString(16).padStart(2,"0");return n}async signTypedData(e,t){if(!t||typeof t!="object")throw new a("method_not_allowed",p.INVALID_INPUT);let n=t,s=typeof n.typedData=="string"?n.typedData:void 0,i=typeof n.address=="string"?n.address:void 0,r=typeof n.chainId=="string"?n.chainId:void 0;if(!s||!i)throw new a("method_not_allowed",p.INVALID_INPUT);let l=i.includes(":")?i.split(":").pop():i;if(this.isSolanaChain(r))throw new a("method_not_allowed","signTypedData not supported for Solana.");try{return await this.makeRequest(e,"eth_signTypedData_v4",[l,s],r)}catch(o){throw o instanceof a?o:new a("signature_rejected","WalletConnect signTypedData_v4 rejected.",o)}}async makeRequest(e,t,n,s){let i=await this.getClient(),r=this.requireSessionTopic(e),l=s??this.getDefaultChainId(e);try{return await i.request({topic:r,chainId:l,request:{method:t,params:n}})}catch(o){let d=o instanceof Error?o.message:String(o);throw new a("signature_rejected",d,{method:t,originalError:o})}}onSessionExpiry(e){this.sessionExpiryHandler=e}get uri(){return this.lastUri}async startPairing(){let e=await this.getClient(),t=f(),n=await e.connect({requiredNamespaces:t});if(!n.uri)throw new a("wallet_unavailable","No URI");return this.lastUri=n.uri,this.pendingApproval=n.approval,n.uri}async completePairing(){if(!this.pendingApproval)throw new a("wallet_unavailable","No pending approval");let t=await this.pendingApproval(),n=t.namespaces,s=t.topic,i=t.peer?.metadata,r=typeof i?.name=="string"?i.name:"walletconnect";this.pendingApproval=void 0;let l=w(n),o=y({id:crypto.randomUUID(),topic:s,walletId:r,walletType:"walletconnect",namespaces:l,platform:_(),createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});return this.lastSession=o,o}};function K(c){return new I(c)}export{I as WalletConnectConnector,f as buildRequiredNamespaces,K as createWalletConnectConnector,k as extractAddress,E as isValidCAIP10,w as mapNamespaces,v as parseCAIP10,C as toHexValue};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/caip25.ts","../src/namespaces.ts"],"sourcesContent":["import type {\n BatchCall,\n Namespace,\n SessionNamespace,\n UniversalConnector,\n UniversalWalletSession,\n WalletCapabilities,\n} from \"@naculus/connect-core\";\nimport {\n CONNECTOR_ERROR_MESSAGES,\n createEmptySession,\n DEFAULT_RPC_URLS,\n detectPlatform,\n EIP155_MAINNET,\n extractAccounts,\n WalletError,\n WC_DISCONNECT_USER,\n} from \"@naculus/connect-core\";\nimport { base58 } from \"@scure/base\";\nimport SignClient from \"@walletconnect/sign-client\";\nimport type { ProposalTypes } from \"@walletconnect/types\";\nimport { type CAIP25NamespaceProposal, validateCAIP25Proposal } from \"./caip25\";\nimport {\n buildRequiredNamespaces,\n extractAddress,\n isValidCAIP10,\n mapNamespaces,\n parseCAIP10,\n toHexValue,\n type WalletConnectConfig,\n} from \"./namespaces\";\n\nexport type {\n WalletConnectConfig,\n WalletConnectConnectInput,\n WalletConnectMetadata,\n} from \"./namespaces\";\nexport {\n buildRequiredNamespaces,\n extractAddress,\n isValidCAIP10,\n mapNamespaces,\n parseCAIP10,\n toHexValue,\n} from \"./namespaces\";\n\n/**\n * WalletConnect v2 Connector for connect SDK\n *\n * Supports EVM chains and Solana through WalletConnect's multi-chain namespace.\n * Provides QR code pairing for desktop and deep link support for mobile.\n *\n * @example\n * ```typescript\n * const connector = new WalletConnectConnector({\n * projectId: process.env.VITE_WALLETCONNECT_PROJECT_ID,\n * metadata: {\n * name: \"My DApp\",\n * description: \"Connect to My DApp\",\n * url: window.location.origin,\n * icons: [window.location.origin + \"/icon.png\"]\n * }\n * });\n * ```\n */\nexport class WalletConnectConnector implements UniversalConnector {\n /** Unique connector identifier */\n readonly id = \"walletconnect\";\n\n /** Display name for UI */\n readonly name = \"WalletConnect\";\n\n /** Connector type identifier */\n readonly kind: \"walletconnect\" = \"walletconnect\";\n\n /** Supported chain namespaces */\n readonly namespaces = [\"eip155\", \"solana\"];\n\n /** Feature support flags */\n readonly supports = {\n desktop: true,\n mobile: true,\n deepLink: true,\n qr: true,\n trustedReconnect: true,\n } as const;\n\n /** Connector configuration */\n readonly config: WalletConnectConfig;\n\n private client: SignClient | undefined;\n private lastSession?: UniversalWalletSession;\n private lastUri?: string;\n private pendingApproval?: () => Promise<UniversalWalletSession>;\n private sessionExpiryHandler?: () => void;\n\n constructor(config: WalletConnectConfig) {\n this.config = config;\n this.client = config.client;\n }\n\n private async getClient(): Promise<SignClient> {\n if (this.client) {\n return this.client;\n }\n\n this.client = await SignClient.init({\n projectId: this.config.projectId,\n relayUrl: this.config.relayUrl,\n metadata: this.config.metadata,\n });\n\n this.client.on(\"session_delete\", (event: { topic: string }) => {\n if (event.topic === this.lastSession?.topic) {\n this.sessionExpiryHandler?.();\n }\n });\n this.client.on(\"session_expire\", (event: { topic: string }) => {\n if (event.topic === this.lastSession?.topic) {\n this.sessionExpiryHandler?.();\n }\n });\n\n return this.client;\n }\n\n async connect(input?: unknown): Promise<UniversalWalletSession> {\n const client = await this.getClient();\n const connectInput =\n input && typeof input === \"object\"\n ? (input as Record<string, unknown>)\n : undefined;\n\n const requiredNamespacesRaw = connectInput?.requiredNamespaces as\n | ProposalTypes.RequiredNamespaces\n | undefined;\n const optionalNamespacesRaw = connectInput?.optionalNamespaces as\n | ProposalTypes.OptionalNamespaces\n | undefined;\n\n const requiredNamespaces =\n requiredNamespacesRaw ?? buildRequiredNamespaces();\n\n const validation = validateCAIP25Proposal({\n requiredNamespaces: requiredNamespaces as Record<\n string,\n CAIP25NamespaceProposal\n >,\n optionalNamespaces: optionalNamespacesRaw as\n | Record<string, CAIP25NamespaceProposal>\n | undefined,\n });\n\n if (!validation.valid) {\n throw new WalletError(\n \"invalid_proposal\",\n `CAIP-25 validation failed: ${validation.errors.join(\", \")}`,\n );\n }\n\n try {\n const connectParams: Record<string, unknown> = { requiredNamespaces };\n if (optionalNamespacesRaw) {\n connectParams.optionalNamespaces = optionalNamespacesRaw;\n }\n const { uri, approval } = await client.connect(connectParams as any);\n if (uri) {\n this.lastUri = uri;\n }\n\n const session = await approval();\n const namespaces = mapNamespaces(session.namespaces);\n\n const walletSession = createEmptySession({\n id: crypto.randomUUID(),\n topic: session.topic,\n walletId: session.peer.metadata?.name ?? \"walletconnect\",\n walletType: \"walletconnect\",\n namespaces,\n platform: detectPlatform(),\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n\n this.lastSession = walletSession;\n return walletSession;\n } catch (error) {\n const message =\n error instanceof Error\n ? error.message\n : \"WalletConnect connect failed.\";\n if (message.toLowerCase().includes(\"rejected\")) {\n throw new WalletError(\"user_rejected\", message, error);\n }\n\n throw new WalletError(\"wallet_unavailable\", message, error);\n }\n }\n\n async reconnect(\n session: UniversalWalletSession,\n ): Promise<UniversalWalletSession> {\n const client = await this.getClient();\n\n try {\n const existing = client.session.get(session.topic ?? \"\");\n if (!existing) {\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session not found.\",\n );\n }\n\n const namespaces = mapNamespaces(existing.namespaces);\n const walletSession = createEmptySession({\n id: session.id,\n topic: existing.topic,\n walletId: existing.peer.metadata?.name ?? \"walletconnect\",\n walletType: \"walletconnect\",\n namespaces,\n platform: detectPlatform(),\n createdAt: session.createdAt,\n updatedAt: new Date().toISOString(),\n });\n\n this.lastSession = walletSession;\n return walletSession;\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session not found.\",\n error,\n );\n }\n }\n\n async disconnect(session: UniversalWalletSession): Promise<void> {\n if (!session.topic) {\n return;\n }\n\n const client = await this.getClient();\n await client.disconnect({\n topic: session.topic,\n reason: {\n code: WC_DISCONNECT_USER,\n message: \"User disconnected\",\n },\n });\n }\n\n async getAccounts(session: UniversalWalletSession): Promise<string[]> {\n if (!session.topic) {\n return extractAccounts(session.namespaces);\n }\n\n const client = await this.getClient();\n const existing = client.session.get(session.topic);\n if (!existing) {\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session expired.\",\n );\n }\n\n return extractAccounts(mapNamespaces(existing.namespaces));\n }\n\n async signMessage(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const message =\n typeof inputObj.message === \"string\" ? inputObj.message : undefined;\n const rawAddress =\n typeof inputObj.address === \"string\" ? inputObj.address : undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!message || !rawAddress)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.MISSING_MESSAGE,\n );\n\n // Remove CAIP-10 prefix, keeping the raw chain address\n const address = rawAddress.includes(\":\")\n ? rawAddress.split(\":\").pop()!\n : rawAddress;\n\n // Solana chain → use solana_signMessage with base58 encoding (CAIP-25)\n // Reference: Reown AppKit's SolanaWalletConnectProvider sends\n // { message: base58.encode(message), pubkey: address }\n if (this.isSolanaChain(chainId)) {\n const messageBytes = new TextEncoder().encode(message);\n const base58Msg = base58.encode(messageBytes);\n return this.makeRequest(\n session,\n \"solana_signMessage\",\n [{ message: base58Msg, pubkey: address }],\n chainId,\n );\n }\n\n // EVM signing method fallback chain:\n // JSON messages → eth_signTypedData_v4 (no fallback)\n // Plain messages → personal_sign → eth_sign (fallback on method rejection)\n const tryMethods = message.startsWith(\"{\")\n ? [\"eth_signTypedData_v4\"]\n : [\"personal_sign\", \"eth_sign\"];\n\n let lastError: unknown;\n for (const tryMethod of tryMethods) {\n let tryParams: unknown[];\n if (tryMethod === \"personal_sign\") {\n tryParams = [address, this.hexEncode(message)];\n } else if (tryMethod === \"eth_sign\") {\n // eth_sign takes [address, messageToSign]\n // Use the raw hex-encoded message; wallets will show a hash\n tryParams = [address, this.hexEncode(message)];\n } else {\n // eth_signTypedData_v4\n tryParams = [message, address];\n }\n\n try {\n return await this.makeRequest(session, tryMethod, tryParams, chainId);\n } catch (error) {\n lastError = error;\n // Only fall through on method-not-authorized errors\n const errMsg =\n error instanceof Error ? error.message.toLowerCase() : \"\";\n const isMethodRejection =\n // Exact WalletConnect wording: \"has not been authorized by the user\"\n errMsg.includes(\"not been authorized\") ||\n errMsg.includes(\"not authorized\") ||\n errMsg.includes(\"not approved\") ||\n errMsg.includes(\"method not found\") ||\n errMsg.includes(\"method_not_allowed\");\n\n if (!isMethodRejection || tryMethods.length === 1) {\n // Unrecoverable error or no more fallbacks\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect signature rejected.\",\n error,\n );\n }\n // Otherwise, continue to next fallback method\n }\n }\n\n // If all methods failed, throw the last error\n if (lastError instanceof WalletError) {\n throw lastError;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect signature rejected.\",\n lastError,\n );\n }\n\n async signTransaction(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const transaction = inputObj.transaction as\n | Record<string, unknown>\n | undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!transaction)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.MISSING_TX,\n );\n\n const isSolana = this.isSolanaChain(chainId);\n const method = isSolana ? \"solana_signTransaction\" : \"eth_signTransaction\";\n\n try {\n return await this.makeRequest(session, method, [transaction], chainId);\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect sign transaction rejected.\",\n error,\n );\n }\n }\n\n async sendRawTransaction(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const signedTx =\n typeof inputObj.signedTransaction === \"string\"\n ? inputObj.signedTransaction\n : undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!signedTx)\n throw new WalletError(\n \"method_not_allowed\",\n \"Missing signedTransaction parameter.\",\n );\n\n if (this.isSolanaChain(chainId)) {\n throw new WalletError(\n \"method_not_allowed\",\n \"sendRawTransaction not supported for Solana via WalletConnect.\",\n );\n }\n\n try {\n return await this.makeRequest<string>(\n session,\n \"eth_sendRawTransaction\",\n [signedTx],\n chainId,\n );\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"tx_failed\",\n \"WalletConnect sendRawTransaction failed.\",\n error,\n );\n }\n }\n\n async sendTransaction(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const transaction = inputObj.transaction as\n | Record<string, unknown>\n | undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n if (!transaction)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.MISSING_TX,\n );\n\n const isSolana = this.isSolanaChain(chainId);\n const method = isSolana ? \"solana_sendTransaction\" : \"eth_sendTransaction\";\n\n const tx = isSolana\n ? transaction\n : {\n ...transaction,\n value:\n typeof transaction.value === \"string\"\n ? toHexValue(transaction.value)\n : transaction.value,\n };\n\n try {\n return await this.makeRequest(session, method, [tx], chainId);\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"tx_failed\",\n \"WalletConnect transaction failed.\",\n error,\n );\n }\n }\n\n async switchChain(\n session: UniversalWalletSession,\n chainId: string,\n ): Promise<void> {\n if (!chainId.startsWith(\"eip155:\")) {\n throw new WalletError(\n \"chain_unsupported\",\n \"WalletConnect switchChain only supports EVM chains.\",\n );\n }\n\n try {\n await this.makeRequest(\n session,\n \"wallet_switchEthereumChain\",\n [{ chainId: `0x${Number(chainId.split(\":\")[1]).toString(16)}` }],\n chainId,\n );\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"chain_unsupported\",\n \"WalletConnect switch chain failed.\",\n error,\n );\n }\n }\n\n async sendCalls(\n session: UniversalWalletSession,\n calls: BatchCall[],\n chainId?: string,\n ): Promise<string> {\n const resolvedChainId = chainId ?? this.getDefaultChainId(session);\n\n try {\n return await this.makeRequest<string>(\n session,\n \"wallet_sendCalls\",\n [{ calls, chainId: resolvedChainId }],\n resolvedChainId,\n );\n } catch {\n const accounts = session.namespaces.eip155?.accounts ?? [];\n const fromAccount = accounts[0]?.split(\":\").pop();\n if (!fromAccount) {\n throw new WalletError(\n \"session_expired\",\n CONNECTOR_ERROR_MESSAGES.NO_ACCOUNT_TX,\n );\n }\n const txHashes: string[] = [];\n for (const call of calls) {\n const hash = await this.makeRequest<string>(\n session,\n \"eth_sendTransaction\",\n [\n {\n from: fromAccount,\n to: call.to,\n value: call.value,\n data: call.data,\n },\n ],\n resolvedChainId,\n );\n txHashes.push(hash);\n }\n return txHashes.length === 1 ? txHashes[0] : txHashes.join(\",\");\n }\n }\n\n async getCapabilities(\n session: UniversalWalletSession,\n ): Promise<Record<string, WalletCapabilities>> {\n const capabilities: Record<string, WalletCapabilities> = {};\n\n for (const ns of Object.values(session.namespaces)) {\n const nsCaps = (ns.capabilities ?? {}) as Record<string, unknown>;\n const atomicBatchSupported = Boolean(nsCaps.atomicBatch);\n\n for (const chain of ns.chains) {\n capabilities[chain] = {\n atomicBatch: atomicBatchSupported\n ? { supported: true, maxBatchSize: 5 }\n : { supported: false },\n paymasterService: nsCaps.paymasterService\n ? { supported: true }\n : undefined,\n };\n }\n }\n\n return capabilities;\n }\n\n async getCallsStatus(\n session: UniversalWalletSession,\n bundleHash: string,\n ): Promise<import(\"@naculus/connect-core\").CallsStatus> {\n try {\n return await this.makeRequest<\n import(\"@naculus/connect-core\").CallsStatus\n >(session, \"wallet_getCallsStatus\", [bundleHash]);\n } catch {\n return { status: \"PENDING\" };\n }\n }\n\n async request(request: {\n method: string;\n params: unknown[];\n }): Promise<unknown> {\n const session = this.lastSession;\n if (!session)\n throw new WalletError(\n \"session_expired\",\n CONNECTOR_ERROR_MESSAGES.SESSION_EXPIRED,\n );\n return this.makeRequest(\n session,\n request.method,\n request.params,\n this.getDefaultChainId(session),\n );\n }\n\n async getBalance(chainId?: string): Promise<string> {\n const session = this.lastSession;\n if (!session)\n throw new WalletError(\n \"session_expired\",\n CONNECTOR_ERROR_MESSAGES.SESSION_EXPIRED,\n );\n const cId = chainId ?? this.getDefaultChainId(session);\n const rpcUrl = DEFAULT_RPC_URLS[cId];\n if (!rpcUrl)\n throw new WalletError(\"chain_unsupported\", \"No RPC URL for chain \" + cId);\n const allAccounts = extractAccounts(session.namespaces);\n const address = allAccounts[0]?.split(\":\").pop();\n if (!address)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.NO_ACCOUNTS,\n );\n const response = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n }),\n });\n const data = await response.json();\n return data.result;\n }\n\n async deepLink(target: string): Promise<void> {\n if (typeof window === \"undefined\") {\n return;\n }\n\n const uri = this.lastUri;\n if (!uri) {\n throw new WalletError(\n \"deeplink_timeout\",\n \"WalletConnect URI unavailable.\",\n );\n }\n\n const url = `${target}${target.includes(\"?\") ? \"&\" : \"?\"}uri=${encodeURIComponent(uri)}`;\n window.location.assign(url);\n }\n\n private getDefaultChainId(session: UniversalWalletSession): string {\n const evmNamespace = session.namespaces[\"eip155\"];\n if (evmNamespace && evmNamespace.chains.length > 0) {\n return evmNamespace.chains[0];\n }\n\n const solanaNamespace = session.namespaces[\"solana\"];\n if (solanaNamespace && solanaNamespace.chains.length > 0) {\n return solanaNamespace.chains[0];\n }\n\n return EIP155_MAINNET;\n }\n\n /**\n * Ensures session has a topic for WalletConnect operations\n * @throws WalletError if session topic is missing\n */\n private requireSessionTopic(session: UniversalWalletSession): string {\n if (!session.topic) {\n throw new WalletError(\n \"session_expired\",\n \"WalletConnect session missing topic.\",\n );\n }\n return session.topic;\n }\n\n /**\n * Determines if a chain ID is a Solana chain\n */\n private isSolanaChain(chainId: string | undefined): boolean {\n return chainId?.startsWith(\"solana:\") ?? false;\n }\n\n /**\n * Hex-encodes a message for Ethereum JSON-RPC personal_sign\n * Converts a UTF-8 string to a 0x-prefixed hex string\n */\n private hexEncode(message: string): string {\n // Already hex-encoded\n if (/^0x[0-9a-fA-F]*$/.test(message)) return message;\n\n const bytes = new TextEncoder().encode(message);\n let hex = \"0x\";\n for (let i = 0; i < bytes.length; i++) {\n hex += bytes[i].toString(16).padStart(2, \"0\");\n }\n return hex;\n }\n\n /**\n * Signs typed data using eth_signTypedData_v4\n * Convenience method that wraps signMessage with explicit typed data handling.\n *\n * @param session - Active wallet session\n * @param input - Object with `typedData` (stringified EIP-712 typed data) and `address`\n * @returns Signature hex string\n */\n async signTypedData(\n session: UniversalWalletSession,\n input: unknown,\n ): Promise<unknown> {\n if (!input || typeof input !== \"object\")\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n const inputObj = input as Record<string, unknown>;\n const typedData =\n typeof inputObj.typedData === \"string\" ? inputObj.typedData : undefined;\n const rawAddress =\n typeof inputObj.address === \"string\" ? inputObj.address : undefined;\n const chainId =\n typeof inputObj.chainId === \"string\" ? inputObj.chainId : undefined;\n\n if (!typedData || !rawAddress)\n throw new WalletError(\n \"method_not_allowed\",\n CONNECTOR_ERROR_MESSAGES.INVALID_INPUT,\n );\n\n const address = rawAddress.includes(\":\")\n ? rawAddress.split(\":\").pop()!\n : rawAddress;\n\n if (this.isSolanaChain(chainId)) {\n throw new WalletError(\n \"method_not_allowed\",\n \"signTypedData not supported for Solana.\",\n );\n }\n\n try {\n return await this.makeRequest(\n session,\n \"eth_signTypedData_v4\",\n [address, typedData],\n chainId,\n );\n } catch (error) {\n if (error instanceof WalletError) {\n throw error;\n }\n throw new WalletError(\n \"signature_rejected\",\n \"WalletConnect signTypedData_v4 rejected.\",\n error,\n );\n }\n }\n\n /**\n * Makes a request to WalletConnect with standardized error handling\n */\n private async makeRequest<T>(\n session: UniversalWalletSession,\n method: string,\n params: unknown[],\n chainId?: string,\n ): Promise<T> {\n const client = await this.getClient();\n const topic = this.requireSessionTopic(session);\n const resolvedChainId = chainId ?? this.getDefaultChainId(session);\n\n try {\n return (await client.request({\n topic,\n chainId: resolvedChainId,\n request: { method, params },\n })) as T;\n } catch (error) {\n // Preserve original error message so callers (e.g. signMessage fallback)\n // can detect specific rejection patterns like \"not authorized\".\n // WalletConnect wraps errors from mobile wallets (MetaMask Mobile, Rainbow, etc.)\n // as generic JSON-RPC errors — we need the original message to distinguish\n // between \"method not authorized\" and actual signing failures.\n const originalMessage =\n error instanceof Error ? error.message : String(error);\n throw new WalletError(\"signature_rejected\", originalMessage, {\n method,\n originalError: error,\n });\n }\n }\n\n onSessionExpiry(handler: () => void): void {\n this.sessionExpiryHandler = handler;\n }\n\n /** URI for QR code display */\n get uri(): string | undefined {\n return this.lastUri;\n }\n\n /**\n * Start WalletConnect pairing, returns URI for QR code\n * Call this to get the pairing URI, then display the QR code\n */\n async startPairing(): Promise<string> {\n const client = await this.getClient();\n const requiredNamespaces = buildRequiredNamespaces();\n const result = await client.connect({ requiredNamespaces });\n if (!result.uri) throw new WalletError(\"wallet_unavailable\", \"No URI\");\n this.lastUri = result.uri;\n this.pendingApproval =\n result.approval as unknown as () => Promise<UniversalWalletSession>;\n return result.uri;\n }\n\n /**\n * Complete pairing after user scans QR code\n * Should be called after displaying the QR and user has scanned it\n */\n async completePairing(): Promise<UniversalWalletSession> {\n if (!this.pendingApproval)\n throw new WalletError(\"wallet_unavailable\", \"No pending approval\");\n\n const pendingResult = await this.pendingApproval();\n const pendingSession = pendingResult as unknown as Record<string, unknown>;\n const pendingNamespaces = pendingSession.namespaces as Record<\n string,\n {\n chains?: string[];\n accounts: string[];\n methods: string[];\n events: string[];\n capabilities?: Record<string, unknown>;\n }\n >;\n const pendingTopic = pendingSession.topic as string | undefined;\n const pendingPeerName = (\n pendingSession.peer as Record<string, unknown> | undefined\n )?.metadata as Record<string, unknown> | undefined;\n const peerName =\n typeof pendingPeerName?.name === \"string\"\n ? pendingPeerName.name\n : \"walletconnect\";\n this.pendingApproval = undefined;\n\n const namespaces = mapNamespaces(pendingNamespaces);\n const ws = createEmptySession({\n id: crypto.randomUUID(),\n topic: pendingTopic,\n walletId: peerName,\n walletType: \"walletconnect\",\n namespaces,\n platform: detectPlatform(),\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n this.lastSession = ws;\n return ws;\n }\n}\n\nexport function createWalletConnectConnector(\n config: WalletConnectConfig,\n): WalletConnectConnector {\n return new WalletConnectConnector(config);\n}\n","export interface CAIP25NamespaceProposal {\n chains?: string[];\n methods: string[];\n events: string[];\n}\n\nexport interface CAIP25SessionProposal {\n requiredNamespaces: Record<string, CAIP25NamespaceProposal>;\n optionalNamespaces?: Record<string, CAIP25NamespaceProposal>;\n}\n\nexport interface CAIP25ValidationResult {\n valid: boolean;\n errors: string[];\n warnings: string[];\n}\n\nconst CAIP2_REGEX = /^[-a-z0-9]{1,32}:[-a-zA-Z0-9]{1,64}$/;\n\nexport function isValidCAIP2(chainId: string): boolean {\n return CAIP2_REGEX.test(chainId);\n}\n\nexport function validateCAIP25Namespace(\n namespace: string,\n proposal: CAIP25NamespaceProposal,\n required: boolean,\n): string[] {\n const errors: string[] = [];\n\n if (required && (!proposal.chains || proposal.chains.length === 0)) {\n errors.push(`Namespace \"${namespace}\": chains are required`);\n }\n\n if (proposal.chains) {\n for (const chainId of proposal.chains) {\n if (!isValidCAIP2(chainId)) {\n errors.push(\n `Namespace \"${namespace}\": invalid CAIP-2 chain \"${chainId}\"`,\n );\n }\n }\n }\n\n if (required && (!proposal.methods || proposal.methods.length === 0)) {\n errors.push(`Namespace \"${namespace}\": methods are required`);\n }\n\n if (!proposal.events) {\n errors.push(`Namespace \"${namespace}\": events array is required`);\n }\n\n return errors;\n}\n\nexport function validateCAIP25Proposal(\n proposal: CAIP25SessionProposal,\n): CAIP25ValidationResult {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (\n !proposal.requiredNamespaces ||\n Object.keys(proposal.requiredNamespaces).length === 0\n ) {\n errors.push(\"requiredNamespaces is required and cannot be empty\");\n } else {\n for (const [namespace, nsProposal] of Object.entries(\n proposal.requiredNamespaces,\n )) {\n const namespaceErrors = validateCAIP25Namespace(\n namespace,\n nsProposal,\n true,\n );\n errors.push(...namespaceErrors);\n }\n }\n\n if (proposal.optionalNamespaces) {\n for (const [namespace, nsProposal] of Object.entries(\n proposal.optionalNamespaces,\n )) {\n if (!proposal.requiredNamespaces[namespace]) {\n const namespaceErrors = validateCAIP25Namespace(\n namespace,\n nsProposal,\n false,\n );\n warnings.push(...namespaceErrors.map((e) => `optional: ${e}`));\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n","import type { Namespace, SessionNamespace } from \"@naculus/connect-core\";\nimport type SignClient from \"@walletconnect/sign-client\";\nimport type { ProposalTypes } from \"@walletconnect/types\";\n\n/**\n * WalletConnect v2 configuration metadata\n */\nexport type WalletConnectMetadata = {\n /** Application name displayed in WalletConnect modal */\n name: string;\n /** Application description */\n description: string;\n /** Application website URL */\n url: string;\n /** Application icon URLs */\n icons: string[];\n};\n\n/**\n * Configuration options for WalletConnectConnector\n */\nexport type WalletConnectConfig = {\n /** WalletConnect v2 project ID from cloud.walletconnect.com */\n projectId: string;\n /** Optional custom relay URL (defaults to WalletConnect cloud) */\n relayUrl?: string;\n /** Application metadata for WalletConnect pairing */\n metadata: WalletConnectMetadata;\n /** Pre-initialized SignClient instance (for testing) */\n client?: SignClient;\n};\n\n/**\n * Input options for connect method\n */\nexport type WalletConnectConnectInput = {\n /** Custom required namespaces override */\n requiredNamespaces?: ProposalTypes.RequiredNamespaces;\n /** Optional namespaces (informational validation only) */\n optionalNamespaces?: ProposalTypes.OptionalNamespaces;\n};\n\n/** Default EVM RPC methods for WalletConnect */\nexport const DEFAULT_EVM_METHODS = [\n \"eth_accounts\",\n \"eth_requestAccounts\",\n \"personal_sign\",\n \"eth_sign\",\n \"eth_signTransaction\",\n \"eth_sendTransaction\",\n \"eth_sendRawTransaction\",\n \"eth_signTypedData_v4\",\n \"wallet_switchEthereumChain\",\n] as const;\n\n/** Default EVM event subscriptions */\nexport const DEFAULT_EVM_EVENTS = [\n \"accountsChanged\",\n \"chainChanged\",\n \"disconnect\",\n \"connect\",\n \"message\",\n] as const;\n\n/** Default Solana methods for WalletConnect */\nexport const DEFAULT_SOLANA_METHODS = [\n \"solana_signMessage\",\n \"solana_signTransaction\",\n \"solana_sendTransaction\",\n] as const;\n\n/** Default Solana event subscriptions */\nexport const DEFAULT_SOLANA_EVENTS = [\"accountChanged\", \"disconnect\"] as const;\n\nexport function toHexValue(value: string): string {\n if (value.startsWith(\"0x\")) return value;\n return `0x${BigInt(value).toString(16)}`;\n}\n\n// ── CAIP-10 Helpers ─────────────────────────────────────────────────────\n\n/**\n * Parses a CAIP-10 address (namespace:chainId:address) into components.\n * Returns undefined if the address doesn't match CAIP-10 format.\n */\nexport function parseCAIP10(\n caip10: string,\n): { namespace: string; chainId: string; address: string } | undefined {\n const parts = caip10.split(\":\");\n // CAIP-10: namespace:chainId:address (3 parts)\n if (parts.length === 3) {\n return { namespace: parts[0], chainId: parts[1], address: parts[2] };\n }\n return undefined;\n}\n\n/**\n * Extracts the raw address from a CAIP-10 string.\n * If already a plain address, returns it as-is.\n */\nexport function extractAddress(caipOrAddress: string): string {\n const parsed = parseCAIP10(caipOrAddress);\n return parsed ? parsed.address : caipOrAddress;\n}\n\n/**\n * Builds a CAIP-10 address string from components.\n */\nexport function buildCAIP10(\n namespace: string,\n chainId: string,\n address: string,\n): string {\n const cleanAddress = address.replace(/^0x/, \"\");\n return `${namespace}:${chainId}:${cleanAddress}`;\n}\n\n/**\n * Resolves an account address to its CAIP-10 representation using the session's\n * namespace information. If no matching namespace is found, returns the raw address.\n */\nexport function resolveCAIP10(\n address: string,\n namespaces: Record<string, { chains?: string[]; accounts: string[] }>,\n preferredNamespace?: string,\n): string {\n // If already CAIP-10, return as-is\n if (address.includes(\":\") && address.split(\":\").length === 3) {\n return address;\n }\n\n const nsKeys = preferredNamespace\n ? [\n preferredNamespace,\n ...Object.keys(namespaces).filter((k) => k !== preferredNamespace),\n ]\n : Object.keys(namespaces);\n\n for (const ns of nsKeys) {\n const nsData = namespaces[ns];\n if (!nsData) continue;\n\n for (const account of nsData.accounts) {\n const parsed = parseCAIP10(account);\n if (parsed && parsed.address.toLowerCase() === address.toLowerCase()) {\n return account;\n }\n }\n\n // If chains exist, construct from first chain\n if (nsData.chains && nsData.chains.length > 0) {\n return buildCAIP10(\n ns,\n nsData.chains[0].split(\":\")[1] || nsData.chains[0],\n address,\n );\n }\n }\n\n // Fallback: use eip155:1 as default\n return buildCAIP10(\"eip155\", \"1\", address);\n}\n\n/**\n * Resolves multiple accounts to their CAIP-10 representations.\n */\nexport function resolveCAIP10List(\n addresses: string[],\n namespaces: Record<string, { chains?: string[]; accounts: string[] }>,\n): string[] {\n return addresses.map((addr) => resolveCAIP10(addr, namespaces));\n}\n\n/**\n * Validates a CAIP-10 address string.\n * Format: namespace:chainId:address\n */\nexport function isValidCAIP10(addr: string): boolean {\n return addr.includes(\":\") && addr.split(\":\").length === 3;\n}\n\n/**\n * Maps WalletConnect namespace format to SDK namespace format\n * @param namespaces - Raw namespace object from WalletConnect session\n * @returns Normalized namespace record\n */\nexport function mapNamespaces(\n namespaces: Record<\n string,\n {\n chains?: string[];\n accounts: string[];\n methods: string[];\n events: string[];\n capabilities?: Record<string, unknown>;\n }\n >,\n): Record<Namespace, SessionNamespace> {\n return Object.entries(namespaces).reduce<Record<Namespace, SessionNamespace>>(\n (acc, [key, value]) => {\n acc[key as Namespace] = {\n chains: value.chains ?? [],\n accounts: value.accounts,\n methods: value.methods,\n events: value.events,\n capabilities: value.capabilities ?? {},\n };\n\n return acc;\n },\n {} as Record<Namespace, SessionNamespace>,\n );\n}\n\n/**\n * Builds default required namespaces for EIP-155 and Solana\n * Includes mainnet, testnet, and popular L2 chains\n */\nexport function buildRequiredNamespaces(): ProposalTypes.RequiredNamespaces {\n return {\n eip155: {\n chains: [\n \"eip155:1\", // Ethereum Mainnet\n \"eip155:11155111\", // Sepolia Testnet\n \"eip155:137\", // Polygon Mainnet\n \"eip155:42161\", // Arbitrum One\n \"eip155:10\", // Optimism\n \"eip155:8453\", // Base\n ],\n methods: [...DEFAULT_EVM_METHODS],\n events: [...DEFAULT_EVM_EVENTS],\n },\n solana: {\n chains: [\n \"solana:0\", // Solana Mainnet\n \"solana:1\", // Solana Devnet\n \"solana:2\", // Solana Testnet\n ],\n methods: [...DEFAULT_SOLANA_METHODS],\n events: [...DEFAULT_SOLANA_EVENTS],\n },\n };\n}\n"],"mappings":"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","names":["CONNECTOR_ERROR_MESSAGES","createEmptySession","DEFAULT_RPC_URLS","detectPlatform","EIP155_MAINNET","extractAccounts","WalletError","WC_DISCONNECT_USER","base58","SignClient","CAIP2_REGEX","isValidCAIP2","chainId","validateCAIP25Namespace","namespace","proposal","required","errors","validateCAIP25Proposal","warnings","nsProposal","namespaceErrors","e","DEFAULT_EVM_METHODS","DEFAULT_EVM_EVENTS","DEFAULT_SOLANA_METHODS","DEFAULT_SOLANA_EVENTS","toHexValue","value","parseCAIP10","caip10","parts","extractAddress","caipOrAddress","parsed","isValidCAIP10","addr","mapNamespaces","namespaces","acc","key","value","buildRequiredNamespaces","DEFAULT_EVM_METHODS","DEFAULT_EVM_EVENTS","DEFAULT_SOLANA_METHODS","DEFAULT_SOLANA_EVENTS","WalletConnectConnector","config","SignClient","event","input","client","connectInput","requiredNamespacesRaw","optionalNamespacesRaw","requiredNamespaces","buildRequiredNamespaces","validation","validateCAIP25Proposal","WalletError","connectParams","uri","approval","session","namespaces","mapNamespaces","walletSession","createEmptySession","detectPlatform","error","message","existing","WC_DISCONNECT_USER","extractAccounts","CONNECTOR_ERROR_MESSAGES","inputObj","rawAddress","chainId","address","messageBytes","base58Msg","base58","tryMethods","lastError","tryMethod","tryParams","errMsg","transaction","method","signedTx","isSolana","tx","toHexValue","calls","resolvedChainId","fromAccount","txHashes","call","hash","capabilities","ns","nsCaps","atomicBatchSupported","chain","bundleHash","request","cId","rpcUrl","DEFAULT_RPC_URLS","target","url","evmNamespace","solanaNamespace","EIP155_MAINNET","bytes","hex","i","typedData","params","topic","originalMessage","handler","result","pendingSession","pendingNamespaces","pendingTopic","pendingPeerName","peerName","ws","createWalletConnectConnector"]}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@naculus/connector-walletconnect",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "dependencies": {
17
+ "@scure/base": "^1.2.0",
18
+ "@walletconnect/sign-client": "^2.16.1",
19
+ "@walletconnect/types": "^2.16.1",
20
+ "@naculus/connect-core": "0.1.0"
21
+ },
22
+ "devDependencies": {
23
+ "tsup": "^8.3.6",
24
+ "typescript": "^5.9.3"
25
+ },
26
+ "sideEffects": false,
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "clean": "rm -rf dist"
30
+ }
31
+ }