@wangjinbao/wallet-connect 0.1.7 → 0.1.9

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/dist/cjs/index.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var e=require("react/jsx-runtime"),t=require("react");const n=t.createContext(null);class a extends Error{constructor(e,t,n){super(e),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name="WalletError",this.code=t,this.data=n}}const s={USER_REJECTED:4001,UNAUTHORIZED:4100,UNSUPPORTED_METHOD:4200,DISCONNECTED:4900,CHAIN_DISCONNECTED:4901,UNRECOGNIZED_CHAIN:4902,INVALID_PARAMS:-32602,INTERNAL_ERROR:-32603,PROVIDER_NOT_FOUND:-32e3,WALLET_NOT_INSTALLED:-32001,ALREADY_CONNECTED:-32002};function r(e,t,n){return new a(e,t,n)}function i(e){if(e instanceof a)return e;if("object"==typeof e&&null!==e){const t=e;return r(t.message||"未知错误",t.code||s.INTERNAL_ERROR,t.data)}return r("string"==typeof e?e:"发生未知错误",s.INTERNAL_ERROR)}class l{constructor(){Object.defineProperty(this,"provider",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"eventListeners",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"handleAccountsChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("accountsChanged",e)}}),Object.defineProperty(this,"handleChainChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("chainChanged",e)}}),Object.defineProperty(this,"handleDisconnect",{enumerable:!0,configurable:!0,writable:!0,value:()=>{this.emit("disconnect",null),this.cleanup()}})}async connect(){if(!this.isInstalled())throw r(`${this.getInfo().name} 未安装`,s.WALLET_NOT_INSTALLED);const e=this.getProvider();if(!e)throw r("未找到提供者",s.PROVIDER_NOT_FOUND);this.provider=e,this.setupEventListeners();try{const e=await this.request({method:"eth_requestAccounts"});if(!e||0===e.length)throw r("未返回账户",s.UNAUTHORIZED);return e}catch(e){throw this.cleanup(),i(e)}}async disconnect(){this.cleanup()}async getAccounts(){if(!this.provider)return[];try{return await this.request({method:"eth_accounts"})||[]}catch(e){return console.error("获取账户失败:",e),[]}}async getBalance(e){if(!this.provider)return"0x0";try{return await this.request({method:"eth_getBalance",params:[e,"latest"]})}catch(e){return console.error("获取余额失败:",e),"0x0"}}async getChainId(){if(!this.provider)throw r("提供者未连接",s.DISCONNECTED);try{return await this.request({method:"eth_chainId"})}catch(e){throw i(e)}}async switchChain(e){if(!this.provider)throw r("提供者未连接",s.DISCONNECTED);try{await this.request({method:"wallet_switchEthereumChain",params:[{chainId:e.chainId}]})}catch(t){if(!this.isUnrecognizedChainError(t))throw i(t);try{await this.request({method:"wallet_addEthereumChain",params:[{chainId:e.chainId,chainName:e.chainName,nativeCurrency:e.nativeCurrency,rpcUrls:e.rpcUrls,blockExplorerUrls:e.blockExplorerUrls,iconUrls:e.iconUrls}]})}catch(e){throw i(e)}}}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){const n=this.eventListeners.get(e);n&&n.delete(t)}async request(e){if(!this.provider)throw r("提供者未连接",s.DISCONNECTED);try{return await this.provider.request(e)}catch(e){throw i(e)}}setupEventListeners(){this.provider&&(this.provider.on("accountsChanged",this.handleAccountsChanged),this.provider.on("chainChanged",this.handleChainChanged),this.provider.on("disconnect",this.handleDisconnect))}cleanup(){this.provider&&(this.provider.removeListener("accountsChanged",this.handleAccountsChanged),this.provider.removeListener("chainChanged",this.handleChainChanged),this.provider.removeListener("disconnect",this.handleDisconnect)),this.provider=null,this.eventListeners.clear()}emit(e,t){const n=this.eventListeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`${e} 监听器错误:`,t)}})}isUnrecognizedChainError(e){return"object"==typeof e&&null!==e&&"code"in e&&e.code===s.UNRECOGNIZED_CHAIN}}class o extends l{getInfo(){return{id:"metamask",name:"MetaMask",downloadUrl:"https://metamask.io/download/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.ethereum?.isMetaMask)}getProvider(){return"undefined"==typeof window?null:window.ethereum?.isMetaMask?window.ethereum:null}}class c extends l{getInfo(){return{id:"okx",name:"OKX Wallet",downloadUrl:"https://www.okx.com/web3"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.okxwallet)}getProvider(){return"undefined"==typeof window?null:window.okxwallet||null}}class d extends l{getInfo(){return{id:"phantom",name:"Phantom",downloadUrl:"https://phantom.app/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.phantom?.ethereum)}getProvider(){return"undefined"==typeof window?null:window.phantom?.ethereum||null}}class h extends l{getInfo(){return{id:"coinbase",name:"Coinbase Wallet",downloadUrl:"https://www.coinbase.com/wallet"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.coinbaseWalletExtension)}getProvider(){return"undefined"==typeof window?null:window.coinbaseWalletExtension||null}}const u=[new o,new c,new d,new h];function w(e){return u.find(t=>t.getInfo().id===e)}const x={chainId:"0x1",chainName:"Ethereum Mainnet",nativeCurrency:{name:"Ether",symbol:"ETH",decimals:18},rpcUrls:["https://eth.llamarpc.com"],blockExplorerUrls:["https://etherscan.io"]},m={chainId:"0xaa36a7",chainName:"Sepolia",nativeCurrency:{name:"Sepolia Ether",symbol:"ETH",decimals:18},rpcUrls:["https://rpc.sepolia.org"],blockExplorerUrls:["https://sepolia.etherscan.io"]},p=[x,m];const b="wjb_wallet_connect";function g(){const e=t.useContext(n);if(!e)throw new Error("useWallet 必须在 WalletProvider 中使用");return e}function f({onClose:n}){const{connect:a,availableWallets:s}=g(),[r,i]=t.useState(!1),[l,o]=t.useState(null),c=t=>"metamask"===t?e.jsx("div",{className:"w-8 h-8 rounded-lg bg-orange-100 flex items-center justify-center text-orange-500",children:"🦊"}):"okx"===t?e.jsx("div",{className:"w-8 h-8 rounded-lg bg-black flex items-center justify-center text-white",children:"X"}):"phantom"===t?e.jsx("div",{className:"w-8 h-8 rounded-lg bg-purple-100 flex items-center justify-center text-purple-500",children:"P"}):"coinbase"===t?e.jsx("div",{className:"w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center text-blue-500",children:"C"}):e.jsx("div",{className:"w-8 h-8 rounded-lg bg-gray-200"});return e.jsx("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:e.jsxs("div",{className:"wjb-wallet-modal-content",children:[e.jsxs("div",{className:"wjb-modal-left",children:[e.jsx("div",{className:"wjb-modal-header",children:e.jsx("h2",{className:"wjb-modal-title",children:"连接钱包"})}),e.jsxs("div",{className:"wjb-wallet-list",children:[s.map(t=>e.jsxs("button",{onClick:()=>(async e=>{i(!0),o(null);try{await a(e),n()}catch(e){o(e instanceof Error?e.message:"连接失败")}finally{i(!1)}})(t.id),disabled:r,className:"wjb-wallet-option",children:[c(t.id),e.jsx("span",{className:"flex-1",children:t.name}),r&&e.jsx("span",{className:"text-xs text-blue-500 animate-pulse",children:"连接中..."})]},t.id)),u.filter(e=>!e.isInstalled()).map(t=>{const n=t.getInfo();return e.jsxs("a",{href:n.downloadUrl,target:"_blank",rel:"noopener noreferrer",className:"wjb-wallet-option opacity-60 hover:opacity-100",children:[c(n.id),e.jsx("span",{className:"flex-1",children:n.name}),e.jsx("span",{className:"text-xs font-bold text-blue-500 bg-blue-50 px-2 py-1 rounded",children:"安装"})]},n.id)})]}),l&&e.jsx("div",{className:"mt-4 p-3 bg-red-50 text-red-500 text-sm rounded-xl",children:l})]}),e.jsxs("div",{className:"wjb-modal-right hidden md:flex",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 mb-6 opacity-80",children:[e.jsx("div",{className:"w-12 h-12 bg-blue-500 rounded-xl shadow-lg -rotate-6"}),e.jsx("div",{className:"w-12 h-12 bg-purple-500 rounded-xl shadow-lg rotate-12"}),e.jsx("div",{className:"w-12 h-12 bg-orange-500 rounded-xl shadow-lg rotate-6"}),e.jsx("div",{className:"w-12 h-12 bg-green-500 rounded-xl shadow-lg -rotate-12"})]}),e.jsx("h3",{className:"text-lg font-bold text-gray-900 dark:text-white mb-2",children:"什么是钱包?"}),e.jsxs("ul",{className:"text-sm text-gray-500 dark:text-gray-400 space-y-3 text-left max-w-xs",children:[e.jsxs("li",{className:"flex items-start gap-2",children:[e.jsx("span",{className:"mt-1",children:"🏠"}),e.jsxs("span",{children:["您的数字资产之家",e.jsx("br",{}),"发送、接收和存储资产。"]})]}),e.jsxs("li",{className:"flex items-start gap-2",children:[e.jsx("span",{className:"mt-1",children:"🔐"}),e.jsxs("span",{children:["一种新的登录方式",e.jsx("br",{}),"无需创建账户和密码。"]})]})]}),e.jsx("button",{className:"mt-6 px-4 py-2 bg-gray-200 dark:bg-gray-700 rounded-lg text-sm font-bold text-gray-700 dark:text-white hover:bg-gray-300 transition-colors",children:"了解更多"})]})]})})}function j({onClose:t}){const{supportedChains:n,switchChain:a,state:s}=g();return e.jsx("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&t()},children:e.jsxs("div",{className:"wjb-chain-switcher-content",children:[e.jsxs("div",{className:"p-4 border-b border-gray-100 dark:border-gray-800 flex justify-between items-center",children:[e.jsx("h3",{className:"font-bold text-gray-900 dark:text-white",children:"切换网络"}),e.jsx("button",{onClick:t,className:"wjb-account-modal-close",children:"✕"})]}),e.jsx("div",{className:"p-2 space-y-1",children:n.map(n=>e.jsxs("button",{onClick:()=>(async e=>{s.chainId!==e&&await a(e),t()})(n.chainId),className:"wjb-chain-option "+(s.chainId===n.chainId?"active":""),children:[e.jsxs("div",{className:"flex items-center",children:[e.jsx("div",{className:"wjb-chain-icon flex items-center justify-center text-white text-xs "+("0x1"===n.chainId?"bg-blue-500":"bg-purple-500"),children:n.chainName[0]}),e.jsx("span",{children:n.chainName})]}),s.chainId===n.chainId&&e.jsx("span",{className:"text-sm font-bold text-green-500",children:"已连接"})]},n.chainId))})]})})}function N(e){if(!e||"0x0"===e)return"0 ETH";try{const t=e.startsWith("0x")?e:`0x${e}`,n=BigInt(t),a=1000000000000000000n,s=n/a,r=(n%a).toString().padStart(18,"0").slice(0,4).replace(/0+$/,"");return r?`${s}.${r} ETH`:`${s} ETH`}catch(e){return console.error("Error formatting balance:",e),"0 ETH"}}function v(e){return e?`${e.slice(0,6)}...${e.slice(-4)}`:""}function C({onClose:t}){const{state:n,disconnect:a}=g(),{account:s,balance:r}=n;return e.jsx("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&t()},children:e.jsxs("div",{className:"wjb-account-modal-content",children:[e.jsx("button",{onClick:t,className:"wjb-account-modal-close",children:"✕"}),e.jsx("div",{className:"wjb-account-avatar-large"}),e.jsx("div",{className:"wjb-account-address-large",children:v(s)}),e.jsx("div",{className:"wjb-account-balance-large",children:n.balance||"0 ETH"}),e.jsxs("div",{className:"wjb-account-actions",children:[e.jsxs("button",{onClick:async()=>{s&&await navigator.clipboard.writeText(s)},className:"wjb-action-button",children:[e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),e.jsx("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]}),"复制地址"]}),e.jsxs("button",{onClick:async()=>{await a(),t()},className:"wjb-action-button text-red-500 hover:text-red-600",children:[e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"}),e.jsx("polyline",{points:"16 17 21 12 16 7"}),e.jsx("line",{x1:"21",y1:"12",x2:"9",y2:"12"})]}),"断开连接"]})]})]})})}exports.BaseWallet=l,exports.CoinbaseWallet=h,exports.ConnectButton=function(){const{state:n}=g(),[a,s]=t.useState(!1),[r,i]=t.useState(!1),[l,o]=t.useState(!1);return n.isConnected?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"wjb-wallet-connected",children:e.jsxs("div",{className:"wjb-wallet-info-group",children:[e.jsxs("button",{onClick:()=>i(!0),className:"wjb-chain-button",children:[e.jsx("div",{className:`w-5 h-5 rounded-full ${"0x1"===n.chainId?"bg-blue-500":"0xaa36a7"===n.chainId?"bg-purple-500":"bg-gray-500"} flex items-center justify-center text-white text-[10px]`,children:"0x1"===n.chainId?"E":"0xaa36a7"===n.chainId?"S":"?"}),e.jsxs("span",{children:["0x1"===n.chainId&&"Ethereum","0xaa36a7"===n.chainId&&"Sepolia",n.chainId&&"0x1"!==n.chainId&&"0xaa36a7"!==n.chainId&&"Unknown"]}),e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"text-gray-400",children:e.jsx("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),e.jsx("div",{className:"wjb-balance",children:n.balance?N(n.balance):"0 ETH"}),e.jsxs("button",{onClick:()=>o(!0),className:"wjb-account-button",children:[e.jsx("span",{children:n.account&&v(n.account)}),e.jsx("div",{className:"wjb-account-avatar"}),e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"text-gray-400 ml-1",children:e.jsx("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})]})}),r&&e.jsx(j,{onClose:()=>i(!1)}),l&&e.jsx(C,{onClose:()=>o(!1)})]}):e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>s(!0),className:"wjb-connect-button wjb-connect-button-primary",children:"连接钱包"}),a&&e.jsx(f,{onClose:()=>s(!1)})]})},exports.ErrorCode=s,exports.MetaMaskWallet=o,exports.OKXWallet=c,exports.PhantomWallet=d,exports.WalletProvider=function({children:a,config:i}){const{chains:l=p,autoConnect:o=!0}=i,[c,d]=t.useState({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),[h,x]=t.useState(null),m=t.useMemo(()=>u.filter(e=>e.isInstalled()).map(e=>e.getInfo()),[]);t.useCallback(async(e,t)=>{try{const n=await e.getBalance(t);d(e=>({...e,balance:n}))}catch(e){console.error("更新余额失败:",e)}},[]);const g=t.useCallback(async e=>{try{if(c.isConnected&&c.wallet?.id===e)throw r("钱包已连接",s.ALREADY_CONNECTED);h&&await h.disconnect();const t=w(e);if(!t)throw r(`未找到钱包 ${e}`,s.PROVIDER_NOT_FOUND);const n=await t.connect(),a=await t.getChainId(),i=await t.getBalance(n[0]),l=t.getInfo();t.on("accountsChanged",async e=>{const n=e;if(0===n.length)f();else{const e=n[0],a=await t.getBalance(e);d(t=>({...t,account:e,balance:a}))}}),t.on("chainChanged",async e=>{const n=(await t.getAccounts())[0];let a="0x0";n&&(a=await t.getBalance(n)),d(t=>({...t,chainId:e,balance:a}))}),t.on("disconnect",()=>{f()}),x(t),d({isConnected:!0,account:n[0],chainId:a,balance:i,wallet:l}),"undefined"!=typeof window&&localStorage.setItem(b,JSON.stringify({walletId:e,account:n[0]}))}catch(e){throw console.error("连接钱包失败:",e),e}},[c.isConnected,c.wallet,h]),f=t.useCallback(async()=>{h&&await h.disconnect(),x(null),d({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),"undefined"!=typeof window&&localStorage.removeItem(b)},[h]),j=t.useCallback(async e=>{if(!h)throw r("未连接钱包",s.DISCONNECTED);const t=function(e,t){return t.find(t=>t.chainId.toLowerCase()===e.toLowerCase())}(e,l);if(!t)throw r(`不支持链 ${e}`,s.UNRECOGNIZED_CHAIN);await h.switchChain(t)},[h,l]);t.useEffect(()=>{if(!o)return;(async()=>{if("undefined"==typeof window)return;const e=localStorage.getItem(b);if(e)try{const{walletId:t}=JSON.parse(e),n=w(t);if(!n)return void localStorage.removeItem(b);let a=0;for(;!n.isInstalled()&&a<10;)await new Promise(e=>setTimeout(e,100)),a++;if(!n.isInstalled())return void localStorage.removeItem(b);await g(t)}catch(e){console.error("自动连接失败:",e),localStorage.removeItem(b)}})()},[o]);const N=t.useMemo(()=>({state:c,connect:g,disconnect:f,switchChain:j,availableWallets:m,supportedChains:l}),[c,g,f,j,m,l]);return e.jsx(n.Provider,{value:N,children:a})},exports.defaultChains=p,exports.mainnet=x,exports.sepolia=m,exports.useWallet=g;
1
+ "use strict";var e=require("react/jsx-runtime"),t=require("react");const n=t.createContext(null);class a extends Error{constructor(e,t,n){super(e),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name="WalletError",this.code=t,this.data=n}}const s={USER_REJECTED:4001,UNAUTHORIZED:4100,UNSUPPORTED_METHOD:4200,DISCONNECTED:4900,CHAIN_DISCONNECTED:4901,UNRECOGNIZED_CHAIN:4902,INVALID_PARAMS:-32602,INTERNAL_ERROR:-32603,PROVIDER_NOT_FOUND:-32e3,WALLET_NOT_INSTALLED:-32001,ALREADY_CONNECTED:-32002};function r(e,t,n){return new a(e,t,n)}function i(e){if(e instanceof a)return e;if("object"==typeof e&&null!==e){const t=e;return r(t.message||"未知错误",t.code||s.INTERNAL_ERROR,t.data)}return r("string"==typeof e?e:"发生未知错误",s.INTERNAL_ERROR)}class l{constructor(){Object.defineProperty(this,"provider",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"eventListeners",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"handleAccountsChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("accountsChanged",e)}}),Object.defineProperty(this,"handleChainChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("chainChanged",e)}}),Object.defineProperty(this,"handleDisconnect",{enumerable:!0,configurable:!0,writable:!0,value:()=>{this.emit("disconnect",null),this.cleanup()}})}async connect(){if(!this.isInstalled())throw r(`${this.getInfo().name} 未安装`,s.WALLET_NOT_INSTALLED);const e=this.getProvider();if(!e)throw r("未找到提供者",s.PROVIDER_NOT_FOUND);this.provider=e,this.setupEventListeners();try{const e=await this.request({method:"eth_requestAccounts"});if(!e||0===e.length)throw r("未返回账户",s.UNAUTHORIZED);return e}catch(e){throw this.cleanup(),i(e)}}async disconnect(){this.cleanup()}async getAccounts(){if(!this.provider)return[];try{return await this.request({method:"eth_accounts"})||[]}catch(e){return console.error("获取账户失败:",e),[]}}async getBalance(e){if(!this.provider)return"0x0";try{return await this.request({method:"eth_getBalance",params:[e,"latest"]})}catch(e){return console.error("获取余额失败:",e),"0x0"}}async getChainId(){if(!this.provider)throw r("提供者未连接",s.DISCONNECTED);try{return await this.request({method:"eth_chainId"})}catch(e){throw i(e)}}async switchChain(e){if(!this.provider)throw r("提供者未连接",s.DISCONNECTED);try{await this.request({method:"wallet_switchEthereumChain",params:[{chainId:e.chainId}]})}catch(t){if(!this.isUnrecognizedChainError(t))throw i(t);try{await this.request({method:"wallet_addEthereumChain",params:[{chainId:e.chainId,chainName:e.chainName,nativeCurrency:e.nativeCurrency,rpcUrls:e.rpcUrls,blockExplorerUrls:e.blockExplorerUrls,iconUrls:e.iconUrls}]})}catch(e){throw i(e)}}}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){const n=this.eventListeners.get(e);n&&n.delete(t)}async request(e){if(!this.provider)throw r("提供者未连接",s.DISCONNECTED);try{return await this.provider.request(e)}catch(e){throw i(e)}}setupEventListeners(){this.provider&&(this.provider.on("accountsChanged",this.handleAccountsChanged),this.provider.on("chainChanged",this.handleChainChanged),this.provider.on("disconnect",this.handleDisconnect))}cleanup(){this.provider&&(this.provider.removeListener("accountsChanged",this.handleAccountsChanged),this.provider.removeListener("chainChanged",this.handleChainChanged),this.provider.removeListener("disconnect",this.handleDisconnect)),this.provider=null,this.eventListeners.clear()}emit(e,t){const n=this.eventListeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`${e} 监听器错误:`,t)}})}isUnrecognizedChainError(e){return"object"==typeof e&&null!==e&&"code"in e&&e.code===s.UNRECOGNIZED_CHAIN}}class o extends l{getInfo(){return{id:"metamask",name:"MetaMask",downloadUrl:"https://metamask.io/download/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.ethereum?.isMetaMask)}getProvider(){return"undefined"==typeof window?null:window.ethereum?.isMetaMask?window.ethereum:null}}class c extends l{getInfo(){return{id:"okx",name:"OKX Wallet",downloadUrl:"https://www.okx.com/web3"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.okxwallet)}getProvider(){return"undefined"==typeof window?null:window.okxwallet||null}}class d extends l{getInfo(){return{id:"phantom",name:"Phantom",downloadUrl:"https://phantom.app/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.phantom?.ethereum)}getProvider(){return"undefined"==typeof window?null:window.phantom?.ethereum||null}}class w extends l{getInfo(){return{id:"coinbase",name:"Coinbase Wallet",downloadUrl:"https://www.coinbase.com/wallet"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.coinbaseWalletExtension)}getProvider(){return"undefined"==typeof window?null:window.coinbaseWalletExtension||null}}const h=[new o,new c,new d,new w];function b(e){return h.find(t=>t.getInfo().id===e)}const j={chainId:"0x1",chainName:"Ethereum Mainnet",nativeCurrency:{name:"Ether",symbol:"ETH",decimals:18},rpcUrls:["https://eth.llamarpc.com"],blockExplorerUrls:["https://etherscan.io"]},u={chainId:"0xaa36a7",chainName:"Sepolia",nativeCurrency:{name:"Sepolia Ether",symbol:"ETH",decimals:18},rpcUrls:["https://rpc.sepolia.org"],blockExplorerUrls:["https://sepolia.etherscan.io"]},x=[j,u];const m="wjb_wallet_connect";function p(){const e=t.useContext(n);if(!e)throw new Error("useWallet 必须在 WalletProvider 中使用");return e}function g({onClose:n}){const{connect:a,availableWallets:s}=p(),[r,i]=t.useState(!1),[l,o]=t.useState(null),c=t=>"metamask"===t?e.jsx("div",{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-orange-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-orange-500",children:"🦊"}):"okx"===t?e.jsx("div",{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-black wjb-flex wjb-items-center wjb-justify-center wjb-text-white",children:"X"}):"phantom"===t?e.jsx("div",{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-purple-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-purple-500",children:"P"}):"coinbase"===t?e.jsx("div",{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-blue-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-blue-500",children:"C"}):e.jsx("div",{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-gray-200"});return e.jsx("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:e.jsxs("div",{className:"wjb-wallet-modal-content",children:[e.jsxs("div",{className:"wjb-modal-left",children:[e.jsx("div",{className:"wjb-modal-header",children:e.jsx("h2",{className:"wjb-modal-title",children:"连接钱包"})}),e.jsxs("div",{className:"wjb-wallet-list",children:[s.map(t=>e.jsxs("button",{onClick:()=>(async e=>{i(!0),o(null);try{await a(e),n()}catch(e){o(e instanceof Error?e.message:"连接失败")}finally{i(!1)}})(t.id),disabled:r,className:"wjb-wallet-option",children:[c(t.id),e.jsx("span",{className:"wjb-flex-1",children:t.name}),r&&e.jsx("span",{className:"wjb-text-xs wjb-text-blue-500 wjb-animate-pulse",children:"连接中..."})]},t.id)),h.filter(e=>!e.isInstalled()).map(t=>{const n=t.getInfo();return e.jsxs("a",{href:n.downloadUrl,target:"_blank",rel:"noopener noreferrer",className:"wjb-wallet-option wjb-opacity-60 wjb-hover:opacity-100",children:[c(n.id),e.jsx("span",{className:"wjb-flex-1",children:n.name}),e.jsx("span",{className:"wjb-text-xs wjb-font-bold wjb-text-blue-500 wjb-bg-blue-50 wjb-px-2 wjb-py-1 wjb-rounded",children:"安装"})]},n.id)})]}),l&&e.jsx("div",{className:"wjb-mt-4 wjb-p-3 wjb-bg-red-50 wjb-text-red-500 wjb-text-sm wjb-rounded-xl",children:l})]}),e.jsxs("div",{className:"wjb-modal-right hidden md:flex",children:[e.jsxs("div",{className:"wjb-grid wjb-grid-cols-2 wjb-gap-4 wjb-mb-6 wjb-opacity-80",children:[e.jsx("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-blue-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-6"}),e.jsx("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-purple-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-12"}),e.jsx("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-orange-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-6"}),e.jsx("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-green-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-12"})]}),e.jsx("h3",{className:"wjb-text-lg wjb-font-bold wjb-text-gray-900 wjb-dark:text-white wjb-mb-2",children:"什么是钱包?"}),e.jsxs("ul",{className:"wjb-text-sm wjb-text-gray-500 wjb-dark:text-gray-400 wjb-space-y-3 wjb-text-left wjb-max-w-xs",children:[e.jsxs("li",{className:"wjb-flex wjb-items-start wjb-gap-2",children:[e.jsx("span",{className:"wjb-mt-1",children:"🏠"}),e.jsxs("span",{children:["您的数字资产之家",e.jsx("br",{}),"发送、接收和存储资产。"]})]}),e.jsxs("li",{className:"wjb-flex wjb-items-start wjb-gap-2",children:[e.jsx("span",{className:"wjb-mt-1",children:"🔐"}),e.jsxs("span",{children:["一种新的登录方式",e.jsx("br",{}),"无需创建账户和密码。"]})]})]}),e.jsx("button",{className:"wjb-mt-6 wjb-px-4 wjb-py-2 wjb-bg-gray-200 wjb-dark:bg-gray-700 wjb-rounded-lg wjb-text-sm wjb-font-bold wjb-text-gray-700 wjb-dark:text-white wjb-hover:bg-gray-300 wjb-transition-colors",children:"了解更多"})]})]})})}function f({onClose:t}){const{supportedChains:n,switchChain:a,state:s}=p();return e.jsx("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&t()},children:e.jsxs("div",{className:"wjb-chain-switcher-content",children:[e.jsxs("div",{className:"wjb-p-4 wjb-border-b wjb-border-gray-100 wjb-dark:border-gray-800 wjb-flex wjb-justify-between wjb-items-center",children:[e.jsx("h3",{className:"wjb-font-bold wjb-text-gray-900 wjb-dark:text-white",children:"切换网络"}),e.jsx("button",{onClick:t,className:"wjb-chain-modal-close",children:"✕"})]}),e.jsx("div",{className:"wjb-p-2 wjb-space-y-1",children:n.map(n=>e.jsxs("button",{onClick:()=>(async e=>{s.chainId!==e&&await a(e),t()})(n.chainId),className:"wjb-chain-option "+(s.chainId===n.chainId?"active":""),children:[e.jsxs("div",{className:"wjb-flex wjb-items-center",children:[e.jsx("div",{className:"wjb-chain-icon wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-xs "+("0x1"===n.chainId?"wjb-bg-blue-500":"wjb-bg-purple-500"),children:n.chainName[0]}),e.jsx("span",{children:n.chainName})]}),s.chainId===n.chainId&&e.jsx("span",{className:"wjb-text-sm wjb-font-bold wjb-text-green-500",children:"已连接"})]},n.chainId))})]})})}function N(e){if(!e||"0x0"===e)return"0 ETH";try{const t=e.startsWith("0x")?e:`0x${e}`,n=BigInt(t),a=1000000000000000000n,s=n/a,r=(n%a).toString().padStart(18,"0").slice(0,4).replace(/0+$/,"");return r?`${s}.${r} ETH`:`${s} ETH`}catch(e){return console.error("Error formatting balance:",e),"0 ETH"}}function v(e){return e?`${e.slice(0,6)}...${e.slice(-4)}`:""}function C({onClose:t}){const{state:n,disconnect:a}=p(),{account:s,balance:r}=n;return e.jsx("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&t()},children:e.jsxs("div",{className:"wjb-account-modal-content",children:[e.jsx("button",{onClick:t,className:"wjb-account-modal-close",children:"✕"}),e.jsx("div",{className:"wjb-account-avatar-large"}),e.jsx("div",{className:"wjb-account-address-large",children:v(s)}),e.jsx("div",{className:"wjb-account-balance-large",children:n.balance||"0 ETH"}),e.jsxs("div",{className:"wjb-account-actions",children:[e.jsxs("button",{onClick:async()=>{s&&await navigator.clipboard.writeText(s)},className:"wjb-action-button",children:[e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),e.jsx("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]}),"复制地址"]}),e.jsxs("button",{onClick:async()=>{await a(),t()},className:"wjb-action-button wjb-text-red-500 wjb-hover:text-red-600",children:[e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e.jsx("path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"}),e.jsx("polyline",{points:"16 17 21 12 16 7"}),e.jsx("line",{x1:"21",y1:"12",x2:"9",y2:"12"})]}),"断开连接"]})]})]})})}exports.BaseWallet=l,exports.CoinbaseWallet=w,exports.ConnectButton=function(){const{state:n}=p(),[a,s]=t.useState(!1),[r,i]=t.useState(!1),[l,o]=t.useState(!1);return n.isConnected?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"wjb-wallet-connected",children:e.jsxs("div",{className:"wjb-wallet-info-group",children:[e.jsxs("button",{onClick:()=>i(!0),className:"wjb-chain-button",children:[e.jsx("div",{className:`wjb-w-5 wjb-h-5 wjb-rounded-full ${"0x1"===n.chainId?"wjb-bg-blue-500":"0xaa36a7"===n.chainId?"wjb-bg-purple-500":"wjb-bg-gray-500"} wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-[10px]`,children:"0x1"===n.chainId?"E":"0xaa36a7"===n.chainId?"S":"?"}),e.jsxs("span",{children:["0x1"===n.chainId&&"Ethereum","0xaa36a7"===n.chainId&&"Sepolia",n.chainId&&"0x1"!==n.chainId&&"0xaa36a7"!==n.chainId&&"Unknown"]}),e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"wjb-text-gray-400",children:e.jsx("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),e.jsx("div",{className:"wjb-balance",children:n.balance?N(n.balance):"0 ETH"}),e.jsxs("button",{onClick:()=>o(!0),className:"wjb-account-button",children:[e.jsx("span",{children:n.account&&v(n.account)}),e.jsx("div",{className:"wjb-account-avatar"}),e.jsx("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"wjb-text-gray-400 wjb-ml-1",children:e.jsx("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})]})}),r&&e.jsx(f,{onClose:()=>i(!1)}),l&&e.jsx(C,{onClose:()=>o(!1)})]}):e.jsxs(e.Fragment,{children:[e.jsx("button",{onClick:()=>s(!0),className:"wjb-connect-button wjb-connect-button-primary",children:"连接钱包"}),a&&e.jsx(g,{onClose:()=>s(!1)})]})},exports.ErrorCode=s,exports.MetaMaskWallet=o,exports.OKXWallet=c,exports.PhantomWallet=d,exports.WalletProvider=function({children:a,config:i}){const{chains:l=x,autoConnect:o=!0}=i,[c,d]=t.useState({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),[w,j]=t.useState(null),u=t.useMemo(()=>h.filter(e=>e.isInstalled()).map(e=>e.getInfo()),[]);t.useCallback(async(e,t)=>{try{const n=await e.getBalance(t);d(e=>({...e,balance:n}))}catch(e){console.error("更新余额失败:",e)}},[]);const p=t.useCallback(async e=>{try{if(c.isConnected&&c.wallet?.id===e)throw r("钱包已连接",s.ALREADY_CONNECTED);w&&await w.disconnect();const t=b(e);if(!t)throw r(`未找到钱包 ${e}`,s.PROVIDER_NOT_FOUND);const n=await t.connect(),a=await t.getChainId(),i=await t.getBalance(n[0]),l=t.getInfo();t.on("accountsChanged",async e=>{const n=e;if(0===n.length)g();else{const e=n[0],a=await t.getBalance(e);d(t=>({...t,account:e,balance:a}))}}),t.on("chainChanged",async e=>{const n=(await t.getAccounts())[0];let a="0x0";n&&(a=await t.getBalance(n)),d(t=>({...t,chainId:e,balance:a}))}),t.on("disconnect",()=>{g()}),j(t),d({isConnected:!0,account:n[0],chainId:a,balance:i,wallet:l}),"undefined"!=typeof window&&localStorage.setItem(m,JSON.stringify({walletId:e,account:n[0]}))}catch(e){throw console.error("连接钱包失败:",e),e}},[c.isConnected,c.wallet,w]),g=t.useCallback(async()=>{w&&await w.disconnect(),j(null),d({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),"undefined"!=typeof window&&localStorage.removeItem(m)},[w]),f=t.useCallback(async e=>{if(!w)throw r("未连接钱包",s.DISCONNECTED);const t=function(e,t){return t.find(t=>t.chainId.toLowerCase()===e.toLowerCase())}(e,l);if(!t)throw r(`不支持链 ${e}`,s.UNRECOGNIZED_CHAIN);await w.switchChain(t)},[w,l]);t.useEffect(()=>{if(!o)return;(async()=>{if("undefined"==typeof window)return;const e=localStorage.getItem(m);if(e)try{const{walletId:t}=JSON.parse(e),n=b(t);if(!n)return void localStorage.removeItem(m);let a=0;for(;!n.isInstalled()&&a<10;)await new Promise(e=>setTimeout(e,100)),a++;if(!n.isInstalled())return void localStorage.removeItem(m);await p(t)}catch(e){console.error("自动连接失败:",e),localStorage.removeItem(m)}})()},[o]);const N=t.useMemo(()=>({state:c,connect:p,disconnect:g,switchChain:f,availableWallets:u,supportedChains:l}),[c,p,g,f,u,l]);return e.jsx(n.Provider,{value:N,children:a})},exports.defaultChains=x,exports.mainnet=j,exports.sepolia=u,exports.useWallet=p;
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/context/WalletContext.tsx","../../src/types/wallet.ts","../../src/utils/errors.ts","../../src/wallets/BaseWallet.ts","../../src/wallets/MetaMaskWallet.ts","../../src/wallets/OKXWallet.ts","../../src/wallets/PhantomWallet.ts","../../src/wallets/CoinbaseWallet.ts","../../src/wallets/index.ts","../../src/utils/chains.ts","../../src/components/WalletProvider.tsx","../../src/hooks/useWallet.ts","../../src/components/WalletModal.tsx","../../src/components/ChainSwitcher.tsx","../../src/utils/format.ts","../../src/components/AccountModal.tsx","../../src/components/ConnectButton.tsx"],"sourcesContent":["import { createContext } from \"react\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 钱包上下文\n */\nexport const WalletContext = createContext<WalletContextValue | null>(null);\n","/**\n * 基于 EIP-1193 的以太坊提供者接口\n */\nexport interface EthereumProvider {\n request(args: RequestArguments): Promise<unknown>;\n on(event: string, listener: (...args: unknown[]) => void): void;\n removeListener(event: string, listener: (...args: unknown[]) => void): void;\n isMetaMask?: boolean;\n isOkxWallet?: boolean;\n isCoinbaseWallet?: boolean;\n isPhantom?: boolean;\n}\n\n/**\n * JSON-RPC 调用请求参数\n */\nexport interface RequestArguments {\n method: string;\n params?: unknown[] | Record<string, unknown>;\n}\n\n/**\n * 链配置\n */\nexport interface Chain {\n chainId: string; // 十六进制字符串,例如 \"0x1\"\n chainName: string;\n nativeCurrency: {\n name: string;\n symbol: string;\n decimals: number;\n };\n rpcUrls: string[];\n blockExplorerUrls?: string[];\n iconUrls?: string[];\n}\n\n/**\n * 钱包信息\n */\nexport interface WalletInfo {\n id: string;\n name: string;\n icon?: string;\n downloadUrl?: string;\n}\n\n/**\n * 钱包连接状态\n */\nexport interface WalletState {\n isConnected: boolean;\n account: string | null;\n chainId: string | null;\n balance: string | null;\n wallet: WalletInfo | null;\n}\n\n/**\n * 钱包事件类型\n */\nexport type WalletEventType =\n | \"accountsChanged\"\n | \"chainChanged\"\n | \"connect\"\n | \"disconnect\";\n\n/**\n * 事件监听器类型\n */\nexport type WalletEventListener = (data: unknown) => void;\n\n/**\n * 钱包错误类型\n */\nexport class WalletError extends Error {\n code: number;\n data?: unknown;\n\n constructor(message: string, code: number, data?: unknown) {\n super(message);\n this.name = \"WalletError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/**\n * 钱包提供者上下文值\n */\nexport interface WalletContextValue {\n state: WalletState;\n connect: (walletId: string) => Promise<void>;\n disconnect: () => Promise<void>;\n switchChain: (chainId: string) => Promise<void>;\n availableWallets: WalletInfo[];\n supportedChains: Chain[];\n}\n\n/**\n * 钱包提供者配置\n */\nexport interface WalletProviderConfig {\n chains: Chain[];\n autoConnect?: boolean;\n appName?: string;\n}\n","import { WalletError } from \"../types\";\n\n/**\n * 基于 EIP-1193 的错误代码\n */\nexport const ErrorCode = {\n USER_REJECTED: 4001,\n UNAUTHORIZED: 4100,\n UNSUPPORTED_METHOD: 4200,\n DISCONNECTED: 4900,\n CHAIN_DISCONNECTED: 4901,\n UNRECOGNIZED_CHAIN: 4902,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n PROVIDER_NOT_FOUND: -32000,\n WALLET_NOT_INSTALLED: -32001,\n ALREADY_CONNECTED: -32002,\n} as const;\n\n/**\n * 创建钱包错误\n */\nexport function createWalletError(\n message: string,\n code: number,\n data?: unknown,\n): WalletError {\n return new WalletError(message, code, data);\n}\n\n/**\n * 检查错误是否为用户拒绝\n */\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof WalletError) {\n return error.code === ErrorCode.USER_REJECTED;\n }\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.USER_REJECTED;\n }\n return false;\n}\n\n/**\n * 解析提供者错误\n */\nexport function parseProviderError(error: unknown): WalletError {\n if (error instanceof WalletError) {\n return error;\n }\n\n if (typeof error === \"object\" && error !== null) {\n const err = error as {\n code?: number;\n message?: string;\n data?: unknown;\n };\n\n return createWalletError(\n err.message || \"未知错误\",\n err.code || ErrorCode.INTERNAL_ERROR,\n err.data,\n );\n }\n\n if (typeof error === \"string\") {\n return createWalletError(error, ErrorCode.INTERNAL_ERROR);\n }\n\n return createWalletError(\"发生未知错误\", ErrorCode.INTERNAL_ERROR);\n}\n","import {\n EthereumProvider,\n RequestArguments,\n Chain,\n WalletInfo,\n WalletEventListener,\n} from \"../types\";\nimport {\n ErrorCode,\n createWalletError,\n parseProviderError,\n} from \"../utils/errors\";\n\n/**\n * 钱包基类(抽象类)\n * 所有钱包实现都应继承此类\n */\nexport abstract class BaseWallet {\n protected provider: EthereumProvider | null = null;\n protected eventListeners: Map<string, Set<WalletEventListener>> = new Map();\n\n /**\n * 获取钱包信息\n */\n abstract getInfo(): WalletInfo;\n\n /**\n * 检查钱包是否安装\n */\n abstract isInstalled(): boolean;\n\n /**\n * 获取提供者实例\n */\n abstract getProvider(): EthereumProvider | null;\n\n /**\n * 连接钱包\n */\n async connect(): Promise<string[]> {\n if (!this.isInstalled()) {\n throw createWalletError(\n `${this.getInfo().name} 未安装`,\n ErrorCode.WALLET_NOT_INSTALLED,\n );\n }\n\n const provider = this.getProvider();\n if (!provider) {\n throw createWalletError(\"未找到提供者\", ErrorCode.PROVIDER_NOT_FOUND);\n }\n\n this.provider = provider;\n this.setupEventListeners();\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_requestAccounts\",\n });\n\n if (!accounts || accounts.length === 0) {\n throw createWalletError(\"未返回账户\", ErrorCode.UNAUTHORIZED);\n }\n\n return accounts;\n } catch (error) {\n this.cleanup();\n throw parseProviderError(error);\n }\n }\n\n /**\n * 断开钱包连接\n */\n async disconnect(): Promise<void> {\n this.cleanup();\n }\n\n /**\n * 获取当前账户\n */\n async getAccounts(): Promise<string[]> {\n if (!this.provider) {\n return [];\n }\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_accounts\",\n });\n return accounts || [];\n } catch (error) {\n console.error(\"获取账户失败:\", error);\n return [];\n }\n }\n\n /**\n * 获取当前账户余额\n */\n async getBalance(address: string): Promise<string> {\n if (!this.provider) {\n return \"0x0\";\n }\n\n try {\n const balance = await this.request<string>({\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n });\n return balance;\n } catch (error) {\n console.error(\"获取余额失败:\", error);\n return \"0x0\";\n }\n }\n\n /**\n * 获取当前链 ID\n */\n async getChainId(): Promise<string> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const chainId = await this.request<string>({\n method: \"eth_chainId\",\n });\n return chainId;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 切换到指定链\n */\n async switchChain(chain: Chain): Promise<void> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n // 尝试切换链\n await this.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: chain.chainId }],\n });\n } catch (error) {\n // 如果未添加该链,则尝试添加\n if (this.isUnrecognizedChainError(error)) {\n try {\n await this.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: chain.chainId,\n chainName: chain.chainName,\n nativeCurrency: chain.nativeCurrency,\n rpcUrls: chain.rpcUrls,\n blockExplorerUrls: chain.blockExplorerUrls,\n iconUrls: chain.iconUrls,\n },\n ],\n });\n } catch (addError) {\n throw parseProviderError(addError);\n }\n } else {\n throw parseProviderError(error);\n }\n }\n }\n\n /**\n * 添加事件监听器\n */\n on(event: string, listener: WalletEventListener): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(listener);\n }\n\n /**\n * 移除事件监听器\n */\n off(event: string, listener: WalletEventListener): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 发起 JSON-RPC 请求\n */\n protected async request<T = unknown>(args: RequestArguments): Promise<T> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const result = await this.provider.request(args);\n return result as T;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 设置提供者事件监听\n */\n protected setupEventListeners(): void {\n if (!this.provider) return;\n\n this.provider.on(\"accountsChanged\", this.handleAccountsChanged);\n this.provider.on(\"chainChanged\", this.handleChainChanged);\n this.provider.on(\"disconnect\", this.handleDisconnect);\n }\n\n /**\n * 清理资源和监听器\n */\n protected cleanup(): void {\n if (this.provider) {\n this.provider.removeListener(\n \"accountsChanged\",\n this.handleAccountsChanged,\n );\n this.provider.removeListener(\"chainChanged\", this.handleChainChanged);\n this.provider.removeListener(\"disconnect\", this.handleDisconnect);\n }\n this.provider = null;\n this.eventListeners.clear();\n }\n\n /**\n * 处理账户变更事件\n */\n protected handleAccountsChanged = (accounts: unknown): void => {\n this.emit(\"accountsChanged\", accounts);\n };\n\n /**\n * 处理链变更事件\n */\n protected handleChainChanged = (chainId: unknown): void => {\n this.emit(\"chainChanged\", chainId);\n };\n\n /**\n * 处理断开连接事件\n */\n protected handleDisconnect = (): void => {\n this.emit(\"disconnect\", null);\n this.cleanup();\n };\n\n /**\n * 向所有监听器触发事件\n */\n protected emit(event: string, data: unknown): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`${event} 监听器错误:`, error);\n }\n });\n }\n }\n\n /**\n * 检查错误是否为未知链错误\n */\n protected isUnrecognizedChainError(error: unknown): boolean {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.UNRECOGNIZED_CHAIN;\n }\n return false;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n ethereum?: EthereumProvider;\n }\n}\n\n/**\n * MetaMask 钱包实现\n */\nexport class MetaMaskWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"metamask\",\n name: \"MetaMask\",\n downloadUrl: \"https://metamask.io/download/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.ethereum?.isMetaMask);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n\n // MetaMask 可能会与其他钱包共享 window.ethereum\n // 尝试获取 MetaMask 专属的提供者\n if (window.ethereum?.isMetaMask) {\n return window.ethereum;\n }\n\n return null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n okxwallet?: EthereumProvider;\n }\n}\n\n/**\n * OKX 钱包实现\n */\nexport class OKXWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"okx\",\n name: \"OKX Wallet\",\n downloadUrl: \"https://www.okx.com/web3\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.okxwallet);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.okxwallet || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n phantom?: {\n ethereum?: EthereumProvider;\n };\n }\n}\n\n/**\n * Phantom 钱包实现\n * Phantom 支持 Solana 和 Ethereum\n * 我们使用 ethereum 属性以兼容 EVM\n */\nexport class PhantomWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"phantom\",\n name: \"Phantom\",\n downloadUrl: \"https://phantom.app/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.phantom?.ethereum);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.phantom?.ethereum || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n coinbaseWalletExtension?: EthereumProvider;\n }\n}\n\n/**\n * Coinbase 钱包实现\n */\nexport class CoinbaseWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"coinbase\",\n name: \"Coinbase Wallet\",\n downloadUrl: \"https://www.coinbase.com/wallet\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.coinbaseWalletExtension);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.coinbaseWalletExtension || null;\n }\n}\n","export { BaseWallet } from \"./BaseWallet\";\nexport { MetaMaskWallet } from \"./MetaMaskWallet\";\nexport { OKXWallet } from \"./OKXWallet\";\nexport { PhantomWallet } from \"./PhantomWallet\";\nexport { CoinbaseWallet } from \"./CoinbaseWallet\";\n\nimport { MetaMaskWallet } from \"./MetaMaskWallet\";\nimport { OKXWallet } from \"./OKXWallet\";\nimport { PhantomWallet } from \"./PhantomWallet\";\nimport { CoinbaseWallet } from \"./CoinbaseWallet\";\nimport { BaseWallet } from \"./BaseWallet\";\n\n/**\n * 所有可用钱包的注册表\n */\nexport const walletRegistry: BaseWallet[] = [\n new MetaMaskWallet(),\n new OKXWallet(),\n new PhantomWallet(),\n new CoinbaseWallet(),\n];\n\n/**\n * 根据 ID 获取钱包\n */\nexport function getWalletById(id: string): BaseWallet | undefined {\n return walletRegistry.find((wallet) => wallet.getInfo().id === id);\n}\n","import { Chain } from \"../types\";\n\n/**\n * 以太坊主网\n */\nexport const mainnet: Chain = {\n chainId: \"0x1\",\n chainName: \"Ethereum Mainnet\",\n nativeCurrency: {\n name: \"Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://eth.llamarpc.com\"],\n blockExplorerUrls: [\"https://etherscan.io\"],\n};\n\n/**\n * Sepolia 测试网\n */\nexport const sepolia: Chain = {\n chainId: \"0xaa36a7\",\n chainName: \"Sepolia\",\n nativeCurrency: {\n name: \"Sepolia Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://rpc.sepolia.org\"],\n blockExplorerUrls: [\"https://sepolia.etherscan.io\"],\n};\n\n/**\n * 默认链列表\n */\nexport const defaultChains: Chain[] = [mainnet, sepolia];\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(\n chainId: string,\n chains: Chain[],\n): Chain | undefined {\n return chains.find(\n (chain) => chain.chainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * 将 chainId 格式化为十六进制字符串\n */\nexport function formatChainId(chainId: number | string): string {\n if (typeof chainId === \"string\") {\n if (chainId.startsWith(\"0x\")) {\n return chainId;\n }\n return `0x${parseInt(chainId, 10).toString(16)}`;\n }\n return `0x${chainId.toString(16)}`;\n}\n\n/**\n * 将 chainId 解析为数字\n */\nexport function parseChainId(chainId: string): number {\n if (chainId.startsWith(\"0x\")) {\n return parseInt(chainId, 16);\n }\n return parseInt(chainId, 10);\n}\n","import React, { useState, useEffect, useCallback, useMemo } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletProviderConfig, WalletState, Chain, WalletInfo } from \"../types\";\nimport { walletRegistry, getWalletById, BaseWallet } from \"../wallets\";\nimport { ErrorCode, createWalletError } from \"../utils/errors\";\nimport { defaultChains, getChainById } from \"../utils/chains\";\n\ninterface WalletProviderProps {\n children: React.ReactNode;\n config: WalletProviderConfig;\n}\n\nconst STORAGE_KEY = \"wjb_wallet_connect\";\n\n/**\n * 钱包提供者组件\n * 管理钱包连接状态并向子组件提供钱包上下文\n */\nexport function WalletProvider({ children, config }: WalletProviderProps) {\n const { chains = defaultChains, autoConnect = true } = config;\n\n const [state, setState] = useState<WalletState>({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n const [currentWallet, setCurrentWallet] = useState<BaseWallet | null>(null);\n\n /**\n * 获取可用(已安装)的钱包\n */\n const availableWallets: WalletInfo[] = useMemo(() => {\n return walletRegistry\n .filter((wallet) => wallet.isInstalled())\n .map((wallet) => wallet.getInfo());\n }, []);\n\n /**\n * 更新余额\n */\n const updateBalance = useCallback(\n async (wallet: BaseWallet, account: string) => {\n try {\n const balance = await wallet.getBalance(account);\n setState((prev) => ({ ...prev, balance }));\n } catch (error) {\n console.error(\"更新余额失败:\", error);\n }\n },\n [],\n );\n\n /**\n * 连接到指定钱包\n */\n const connect = useCallback(\n async (walletId: string) => {\n try {\n // 检查是否已连接\n if (state.isConnected && state.wallet?.id === walletId) {\n throw createWalletError(\"钱包已连接\", ErrorCode.ALREADY_CONNECTED);\n }\n\n // 如果有当前连接的钱包,先断开\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n // 获取钱包实例\n const wallet = getWalletById(walletId);\n if (!wallet) {\n throw createWalletError(\n `未找到钱包 ${walletId}`,\n ErrorCode.PROVIDER_NOT_FOUND,\n );\n }\n\n // 连接钱包\n const accounts = await wallet.connect();\n const chainId = await wallet.getChainId();\n const balance = await wallet.getBalance(accounts[0]);\n\n const walletInfo = wallet.getInfo();\n\n // 设置事件监听器\n wallet.on(\"accountsChanged\", async (accounts) => {\n const accountList = accounts as string[];\n if (accountList.length === 0) {\n // 用户断开连接\n disconnect();\n } else {\n const newAccount = accountList[0];\n const newBalance = await wallet.getBalance(newAccount);\n setState((prev) => ({\n ...prev,\n account: newAccount,\n balance: newBalance,\n }));\n }\n });\n\n wallet.on(\"chainChanged\", async (chainId) => {\n // 链改变后重新获取余额\n const currentAccount = (await wallet.getAccounts())[0];\n let newBalance = \"0x0\";\n if (currentAccount) {\n newBalance = await wallet.getBalance(currentAccount);\n }\n\n setState((prev) => ({\n ...prev,\n chainId: chainId as string,\n balance: newBalance,\n }));\n });\n\n wallet.on(\"disconnect\", () => {\n disconnect();\n });\n\n setCurrentWallet(wallet);\n setState({\n isConnected: true,\n account: accounts[0],\n chainId,\n balance,\n wallet: walletInfo,\n });\n\n // 保存到 localStorage 以便自动连接\n if (typeof window !== \"undefined\") {\n localStorage.setItem(\n STORAGE_KEY,\n JSON.stringify({ walletId, account: accounts[0] }),\n );\n }\n } catch (error) {\n console.error(\"连接钱包失败:\", error);\n throw error;\n }\n },\n [state.isConnected, state.wallet, currentWallet],\n );\n\n /**\n * 断开钱包连接\n */\n const disconnect = useCallback(async () => {\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n setCurrentWallet(null);\n setState({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n // 清除 localStorage\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, [currentWallet]);\n\n /**\n * 切换链\n */\n const switchChain = useCallback(\n async (chainId: string) => {\n if (!currentWallet) {\n throw createWalletError(\"未连接钱包\", ErrorCode.DISCONNECTED);\n }\n\n const chain = getChainById(chainId, chains);\n if (!chain) {\n throw createWalletError(\n `不支持链 ${chainId}`,\n ErrorCode.UNRECOGNIZED_CHAIN,\n );\n }\n\n await currentWallet.switchChain(chain);\n\n // chainChanged 事件将更新状态\n },\n [currentWallet, chains],\n );\n\n /**\n * 组件挂载时自动连接\n */\n useEffect(() => {\n if (!autoConnect) return;\n\n const attemptAutoConnect = async () => {\n if (typeof window === \"undefined\") return;\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return;\n\n try {\n const { walletId } = JSON.parse(stored);\n const wallet = getWalletById(walletId);\n\n if (!wallet) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 尝试等待钱包注入(解决页面刷新时注入延迟问题)\n let retryCount = 0;\n while (!wallet.isInstalled() && retryCount < 10) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n retryCount++;\n }\n\n if (!wallet.isInstalled()) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 如果已安装钱包插件则自动连接\n await connect(walletId);\n } catch (error) {\n console.error(\"自动连接失败:\", error);\n localStorage.removeItem(STORAGE_KEY);\n }\n };\n\n attemptAutoConnect();\n }, [autoConnect]);\n\n const value = useMemo(\n () => ({\n state,\n connect,\n disconnect,\n switchChain,\n availableWallets,\n supportedChains: chains,\n }),\n [state, connect, disconnect, switchChain, availableWallets, chains],\n );\n\n return (\n <WalletContext.Provider value={value}>{children}</WalletContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 访问钱包上下文的 Hook\n */\nexport function useWallet(): WalletContextValue {\n const context = useContext(WalletContext);\n\n if (!context) {\n throw new Error(\"useWallet 必须在 WalletProvider 中使用\");\n }\n\n return context;\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { walletRegistry } from \"../wallets\";\n\ninterface WalletModalProps {\n onClose: () => void;\n}\n\nexport function WalletModal({ onClose }: WalletModalProps) {\n const { connect, availableWallets } = useWallet();\n const [connecting, setConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleConnect = async (walletId: string) => {\n setConnecting(true);\n setError(null);\n try {\n await connect(walletId);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"连接失败\");\n } finally {\n setConnecting(false);\n }\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n // Predefine icons/colors for known wallets or use generic\n const getWalletIcon = (id: string) => {\n // Allow flexible icon rendering. For now, simple colored squares or letters.\n // In a real app, these would be proper SVGs or helper components.\n if (id === \"metamask\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-orange-100 flex items-center justify-center text-orange-500\">\n 🦊\n </div>\n );\n if (id === \"okx\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-black flex items-center justify-center text-white\">\n X\n </div>\n );\n if (id === \"phantom\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-purple-100 flex items-center justify-center text-purple-500\">\n P\n </div>\n );\n if (id === \"coinbase\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center text-blue-500\">\n C\n </div>\n );\n return <div className=\"w-8 h-8 rounded-lg bg-gray-200\"></div>;\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-wallet-modal-content\">\n {/* Left Side: Wallet List */}\n <div className=\"wjb-modal-left\">\n <div className=\"wjb-modal-header\">\n <h2 className=\"wjb-modal-title\">连接钱包</h2>\n {/* Mobile close button could go here, but omitted for clean desktop design or added if needed */}\n </div>\n\n <div className=\"wjb-wallet-list\">\n {/* Installed Wallets */}\n {availableWallets.map((wallet) => (\n <button\n key={wallet.id}\n onClick={() => handleConnect(wallet.id)}\n disabled={connecting}\n className=\"wjb-wallet-option\"\n >\n {getWalletIcon(wallet.id)}\n <span className=\"flex-1\">{wallet.name}</span>\n {connecting && (\n <span className=\"text-xs text-blue-500 animate-pulse\">\n 连接中...\n </span>\n )}\n </button>\n ))}\n\n {/* Uninstalled Wallets */}\n {walletRegistry\n .filter((w) => !w.isInstalled())\n .map((wallet) => {\n const info = wallet.getInfo();\n return (\n <a\n key={info.id}\n href={info.downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"wjb-wallet-option opacity-60 hover:opacity-100\"\n >\n {getWalletIcon(info.id)}\n <span className=\"flex-1\">{info.name}</span>\n <span className=\"text-xs font-bold text-blue-500 bg-blue-50 px-2 py-1 rounded\">\n 安装\n </span>\n </a>\n );\n })}\n </div>\n\n {error && (\n <div className=\"mt-4 p-3 bg-red-50 text-red-500 text-sm rounded-xl\">\n {error}\n </div>\n )}\n </div>\n\n {/* Right Side: Education / Info */}\n <div className=\"wjb-modal-right hidden md:flex\">\n {/* Icon Grid Placeholder */}\n <div className=\"grid grid-cols-2 gap-4 mb-6 opacity-80\">\n <div className=\"w-12 h-12 bg-blue-500 rounded-xl shadow-lg -rotate-6\"></div>\n <div className=\"w-12 h-12 bg-purple-500 rounded-xl shadow-lg rotate-12\"></div>\n <div className=\"w-12 h-12 bg-orange-500 rounded-xl shadow-lg rotate-6\"></div>\n <div className=\"w-12 h-12 bg-green-500 rounded-xl shadow-lg -rotate-12\"></div>\n </div>\n\n <h3 className=\"text-lg font-bold text-gray-900 dark:text-white mb-2\">\n 什么是钱包?\n </h3>\n <ul className=\"text-sm text-gray-500 dark:text-gray-400 space-y-3 text-left max-w-xs\">\n <li className=\"flex items-start gap-2\">\n <span className=\"mt-1\">🏠</span>\n <span>\n 您的数字资产之家\n <br />\n 发送、接收和存储资产。\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"mt-1\">🔐</span>\n <span>\n 一种新的登录方式\n <br />\n 无需创建账户和密码。\n </span>\n </li>\n </ul>\n\n <button className=\"mt-6 px-4 py-2 bg-gray-200 dark:bg-gray-700 rounded-lg text-sm font-bold text-gray-700 dark:text-white hover:bg-gray-300 transition-colors\">\n 了解更多\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useRef, useEffect } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\n\ninterface ChainSwitcherProps {\n onClose: () => void;\n}\n\nexport function ChainSwitcher({ onClose }: ChainSwitcherProps) {\n const { supportedChains, switchChain, state } = useWallet();\n // We can use a backdrop for mobile, or click outside for desktop dropdown\n const handleSwitch = async (chainId: string) => {\n if (state.chainId !== chainId) {\n await switchChain(chainId);\n }\n onClose();\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-chain-switcher-content\">\n <div className=\"p-4 border-b border-gray-100 dark:border-gray-800 flex justify-between items-center\">\n <h3 className=\"font-bold text-gray-900 dark:text-white\">切换网络</h3>\n <button onClick={onClose} className=\"wjb-account-modal-close\">\n ✕\n </button>\n </div>\n\n <div className=\"p-2 space-y-1\">\n {supportedChains.map((chain) => (\n <button\n key={chain.chainId}\n onClick={() => handleSwitch(chain.chainId)}\n className={`wjb-chain-option ${state.chainId === chain.chainId ? \"active\" : \"\"}`}\n >\n <div className=\"flex items-center\">\n {/* Chain Icons */}\n <div\n className={`wjb-chain-icon flex items-center justify-center text-white text-xs ${\n chain.chainId === \"0x1\" ? \"bg-blue-500\" : \"bg-purple-500\"\n }`}\n >\n {chain.chainName[0]}\n </div>\n <span>{chain.chainName}</span>\n </div>\n\n {state.chainId === chain.chainId && (\n <span className=\"text-sm font-bold text-green-500\">已连接</span>\n )}\n </button>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * Format balance from hex/wei to formatted string\n */\nexport function formatBalance(rawBalance: string | undefined): string {\n if (!rawBalance || rawBalance === \"0x0\") return \"0 ETH\";\n\n try {\n const hex = rawBalance.startsWith(\"0x\") ? rawBalance : `0x${rawBalance}`;\n const wei = BigInt(hex);\n // Rough conversion to ETH (18 decimals), keeping 4 decimal places\n const divisor = 1000000000000000000n;\n const integerPart = wei / divisor;\n const remainder = wei % divisor;\n\n // Convert remainder to decimal string padded with zeros\n const decimals = remainder.toString().padStart(18, \"0\").slice(0, 4);\n\n // Remove trailing zeros if any\n const formattedDecimals = decimals.replace(/0+$/, \"\");\n\n return formattedDecimals\n ? `${integerPart}.${formattedDecimals} ETH`\n : `${integerPart} ETH`;\n } catch (error) {\n console.error(\"Error formatting balance:\", error);\n return \"0 ETH\";\n }\n}\n\n/**\n * Format address to short form 0x...1234\n */\nexport function formatAddress(address: string | null | undefined): string {\n if (!address) return \"\";\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n","import React from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { formatAddress } from \"../utils/format\";\n\ninterface AccountModalProps {\n onClose: () => void;\n}\n\nexport function AccountModal({ onClose }: AccountModalProps) {\n const { state, disconnect } = useWallet();\n const { account, balance } = state;\n\n const handleCopy = async () => {\n if (account) {\n await navigator.clipboard.writeText(account);\n // Could add toast here\n }\n };\n\n const handleDisconnect = async () => {\n await disconnect();\n onClose();\n };\n\n // Close when clicking overlay\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-account-modal-content\">\n <button onClick={onClose} className=\"wjb-account-modal-close\">\n ✕\n </button>\n\n <div className=\"wjb-account-avatar-large\" />\n\n <div className=\"wjb-account-address-large\">\n {formatAddress(account)}\n </div>\n\n <div className=\"wjb-account-balance-large\">\n {state.balance || \"0 ETH\"}\n {/* Fallback not really needed if state init correct, but safe */}\n </div>\n\n <div className=\"wjb-account-actions\">\n <button onClick={handleCopy} className=\"wjb-action-button\">\n {/* Copy Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n 复制地址\n </button>\n\n <button\n onClick={handleDisconnect}\n className=\"wjb-action-button text-red-500 hover:text-red-600\"\n >\n {/* Disconnect Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" />\n </svg>\n 断开连接\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { WalletModal } from \"./WalletModal\";\nimport { ChainSwitcher } from \"./ChainSwitcher\";\nimport { AccountModal } from \"./AccountModal\"; // Import new component\nimport { formatAddress, formatBalance } from \"../utils/format\";\n\nexport function ConnectButton() {\n const { state } = useWallet();\n const [showWalletModal, setShowWalletModal] = useState(false);\n const [showChainSwitcher, setShowChainSwitcher] = useState(false);\n const [showAccountModal, setShowAccountModal] = useState(false);\n\n if (!state.isConnected) {\n return (\n <>\n <button\n onClick={() => setShowWalletModal(true)}\n className=\"wjb-connect-button wjb-connect-button-primary\"\n >\n 连接钱包\n </button>\n {showWalletModal && (\n <WalletModal onClose={() => setShowWalletModal(false)} />\n )}\n </>\n );\n }\n\n return (\n <>\n <div className=\"wjb-wallet-connected\">\n <div className=\"wjb-wallet-info-group\">\n {/* Chain Switcher Trigger */}\n <button\n onClick={() => setShowChainSwitcher(true)}\n className=\"wjb-chain-button\"\n >\n {/* Simple Chain Icon Placeholder or check ChainID */}\n <div\n className={`w-5 h-5 rounded-full ${\n state.chainId === \"0x1\"\n ? \"bg-blue-500\"\n : state.chainId === \"0xaa36a7\"\n ? \"bg-purple-500\"\n : \"bg-gray-500\"\n } flex items-center justify-center text-white text-[10px]`}\n >\n {state.chainId === \"0x1\"\n ? \"E\"\n : state.chainId === \"0xaa36a7\"\n ? \"S\"\n : \"?\"}\n </div>\n <span>\n {state.chainId === \"0x1\" && \"Ethereum\"}\n {state.chainId === \"0xaa36a7\" && \"Sepolia\"}\n {state.chainId &&\n state.chainId !== \"0x1\" &&\n state.chainId !== \"0xaa36a7\" &&\n \"Unknown\"}\n </span>\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"text-gray-400\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n\n {/* Balance Display */}\n <div className=\"wjb-balance\">\n {state.balance ? formatBalance(state.balance) : \"0 ETH\"}\n </div>\n\n {/* Account Button */}\n <button\n onClick={() => setShowAccountModal(true)}\n className=\"wjb-account-button\"\n >\n <span>{state.account && formatAddress(state.account)}</span>\n <div className=\"wjb-account-avatar\" />\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"text-gray-400 ml-1\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n {showChainSwitcher && (\n <ChainSwitcher onClose={() => setShowChainSwitcher(false)} />\n )}\n\n {showAccountModal && (\n <AccountModal onClose={() => setShowAccountModal(false)} />\n )}\n </>\n );\n}\n"],"names":["WalletContext","createContext","WalletError","Error","constructor","message","code","data","super","Object","defineProperty","this","name","ErrorCode","USER_REJECTED","UNAUTHORIZED","UNSUPPORTED_METHOD","DISCONNECTED","CHAIN_DISCONNECTED","UNRECOGNIZED_CHAIN","INVALID_PARAMS","INTERNAL_ERROR","PROVIDER_NOT_FOUND","WALLET_NOT_INSTALLED","ALREADY_CONNECTED","createWalletError","parseProviderError","error","err","BaseWallet","value","Map","accounts","emit","chainId","cleanup","connect","isInstalled","getInfo","provider","getProvider","setupEventListeners","request","method","length","disconnect","getAccounts","console","getBalance","address","params","getChainId","switchChain","chain","isUnrecognizedChainError","chainName","nativeCurrency","rpcUrls","blockExplorerUrls","iconUrls","addError","on","event","listener","eventListeners","has","set","Set","get","add","off","listeners","delete","args","handleAccountsChanged","handleChainChanged","handleDisconnect","removeListener","clear","forEach","MetaMaskWallet","id","downloadUrl","window","Boolean","ethereum","isMetaMask","OKXWallet","okxwallet","PhantomWallet","phantom","CoinbaseWallet","coinbaseWalletExtension","walletRegistry","getWalletById","find","wallet","mainnet","symbol","decimals","sepolia","defaultChains","STORAGE_KEY","useWallet","context","useContext","WalletModal","onClose","availableWallets","connecting","setConnecting","useState","setError","getWalletIcon","_jsx","className","children","onClick","e","target","currentTarget","_jsxs","map","async","walletId","handleConnect","disabled","filter","w","info","href","rel","ChainSwitcher","supportedChains","state","handleSwitch","formatBalance","rawBalance","hex","startsWith","wei","BigInt","divisor","integerPart","formattedDecimals","toString","padStart","slice","replace","formatAddress","AccountModal","account","balance","navigator","clipboard","writeText","width","height","viewBox","fill","stroke","strokeWidth","x","y","rx","ry","d","points","x1","y1","x2","y2","showWalletModal","setShowWalletModal","showChainSwitcher","setShowChainSwitcher","showAccountModal","setShowAccountModal","isConnected","_Fragment","strokeLinecap","strokeLinejoin","config","chains","autoConnect","setState","currentWallet","setCurrentWallet","useMemo","useCallback","prev","walletInfo","accountList","newAccount","newBalance","currentAccount","localStorage","setItem","JSON","stringify","removeItem","toLowerCase","getChainById","useEffect","stored","getItem","parse","retryCount","Promise","resolve","setTimeout","attemptAutoConnect","Provider"],"mappings":"mEAMO,MAAMA,EAAgBC,EAAAA,cAAyC,MCqEhE,MAAOC,UAAoBC,MAI/BC,WAAAA,CAAYC,EAAiBC,EAAcC,GACzCC,MAAMH,GAJRI,OAAAC,eAAAC,KAAA,OAAA,0DACAF,OAAAC,eAAAC,KAAA,OAAA,0DAIEA,KAAKC,KAAO,cACZD,KAAKL,KAAOA,EACZK,KAAKJ,KAAOA,CACd,EC/EK,MAAMM,EAAY,CACvBC,cAAe,KACfC,aAAc,KACdC,mBAAoB,KACpBC,aAAc,KACdC,mBAAoB,KACpBC,mBAAoB,KACpBC,gBAAgB,MAChBC,gBAAgB,MAChBC,oBAAoB,KACpBC,sBAAsB,MACtBC,mBAAmB,gBAMLC,EACdpB,EACAC,EACAC,GAEA,OAAO,IAAIL,EAAYG,EAASC,EAAMC,EACxC,CAkBM,SAAUmB,EAAmBC,GACjC,GAAIA,aAAiBzB,EACnB,OAAOyB,EAGT,GAAqB,iBAAVA,GAAgC,OAAVA,EAAgB,CAC/C,MAAMC,EAAMD,EAMZ,OAAOF,EACLG,EAAIvB,SAAW,OACfuB,EAAItB,MAAQO,EAAUQ,eACtBO,EAAIrB,KAER,CAEA,OACSkB,EADY,iBAAVE,EACgBA,EAGF,SAHSd,EAAUQ,eAI9C,OCrDsBQ,EAAtBzB,WAAAA,GACYK,OAAAC,eAAAC,KAAA,WAAA,iDAAoC,OACpCF,OAAAC,eAAAC,KAAA,iBAAA,2CAAwDmB,MAAA,IAAIC,MA8N5DtB,OAAAC,eAAAC,KAAA,wBAAA,iDAAyBqB,IACjCrB,KAAKsB,KAAK,kBAAmBD,MAMrBvB,OAAAC,eAAAC,KAAA,qBAAA,iDAAsBuB,IAC9BvB,KAAKsB,KAAK,eAAgBC,MAMlBzB,OAAAC,eAAAC,KAAA,mBAAA,2CAAmBmB,MAAAA,KAC3BnB,KAAKsB,KAAK,aAAc,MACxBtB,KAAKwB,YA4BT,CAtPE,aAAMC,GACJ,IAAKzB,KAAK0B,cACR,MAAMZ,EACJ,GAAGd,KAAK2B,UAAU1B,WAClBC,EAAUU,sBAId,MAAMgB,EAAW5B,KAAK6B,cACtB,IAAKD,EACH,MAAMd,EAAkB,SAAUZ,EAAUS,oBAG9CX,KAAK4B,SAAWA,EAChB5B,KAAK8B,sBAEL,IACE,MAAMT,QAAiBrB,KAAK+B,QAAkB,CAC5CC,OAAQ,wBAGV,IAAKX,GAAgC,IAApBA,EAASY,OACxB,MAAMnB,EAAkB,QAASZ,EAAUE,cAG7C,OAAOiB,CACT,CAAE,MAAOL,GAEP,MADAhB,KAAKwB,UACCT,EAAmBC,EAC3B,CACF,CAKA,gBAAMkB,GACJlC,KAAKwB,SACP,CAKA,iBAAMW,GACJ,IAAKnC,KAAK4B,SACR,MAAO,GAGT,IAIE,aAHuB5B,KAAK+B,QAAkB,CAC5CC,OAAQ,kBAES,EACrB,CAAE,MAAOhB,GAEP,OADAoB,QAAQpB,MAAM,UAAWA,GAClB,EACT,CACF,CAKA,gBAAMqB,CAAWC,GACf,IAAKtC,KAAK4B,SACR,MAAO,MAGT,IAKE,aAJsB5B,KAAK+B,QAAgB,CACzCC,OAAQ,iBACRO,OAAQ,CAACD,EAAS,WAGtB,CAAE,MAAOtB,GAEP,OADAoB,QAAQpB,MAAM,UAAWA,GAClB,KACT,CACF,CAKA,gBAAMwB,GACJ,IAAKxC,KAAK4B,SACR,MAAMd,EAAkB,SAAUZ,EAAUI,cAG9C,IAIE,aAHsBN,KAAK+B,QAAgB,CACzCC,OAAQ,eAGZ,CAAE,MAAOhB,GACP,MAAMD,EAAmBC,EAC3B,CACF,CAKA,iBAAMyB,CAAYC,GAChB,IAAK1C,KAAK4B,SACR,MAAMd,EAAkB,SAAUZ,EAAUI,cAG9C,UAEQN,KAAK+B,QAAQ,CACjBC,OAAQ,6BACRO,OAAQ,CAAC,CAAEhB,QAASmB,EAAMnB,WAE9B,CAAE,MAAOP,GAEP,IAAIhB,KAAK2C,yBAAyB3B,GAmBhC,MAAMD,EAAmBC,GAlBzB,UACQhB,KAAK+B,QAAQ,CACjBC,OAAQ,0BACRO,OAAQ,CACN,CACEhB,QAASmB,EAAMnB,QACfqB,UAAWF,EAAME,UACjBC,eAAgBH,EAAMG,eACtBC,QAASJ,EAAMI,QACfC,kBAAmBL,EAAMK,kBACzBC,SAAUN,EAAMM,YAIxB,CAAE,MAAOC,GACP,MAAMlC,EAAmBkC,EAC3B,CAIJ,CACF,CAKAC,EAAAA,CAAGC,EAAeC,GACXpD,KAAKqD,eAAeC,IAAIH,IAC3BnD,KAAKqD,eAAeE,IAAIJ,EAAO,IAAIK,KAErCxD,KAAKqD,eAAeI,IAAIN,GAAQO,IAAIN,EACtC,CAKAO,GAAAA,CAAIR,EAAeC,GACjB,MAAMQ,EAAY5D,KAAKqD,eAAeI,IAAIN,GACtCS,GACFA,EAAUC,OAAOT,EAErB,CAKU,aAAMrB,CAAqB+B,GACnC,IAAK9D,KAAK4B,SACR,MAAMd,EAAkB,SAAUZ,EAAUI,cAG9C,IAEE,aADqBN,KAAK4B,SAASG,QAAQ+B,EAE7C,CAAE,MAAO9C,GACP,MAAMD,EAAmBC,EAC3B,CACF,CAKUc,mBAAAA,GACH9B,KAAK4B,WAEV5B,KAAK4B,SAASsB,GAAG,kBAAmBlD,KAAK+D,uBACzC/D,KAAK4B,SAASsB,GAAG,eAAgBlD,KAAKgE,oBACtChE,KAAK4B,SAASsB,GAAG,aAAclD,KAAKiE,kBACtC,CAKUzC,OAAAA,GACJxB,KAAK4B,WACP5B,KAAK4B,SAASsC,eACZ,kBACAlE,KAAK+D,uBAEP/D,KAAK4B,SAASsC,eAAe,eAAgBlE,KAAKgE,oBAClDhE,KAAK4B,SAASsC,eAAe,aAAclE,KAAKiE,mBAElDjE,KAAK4B,SAAW,KAChB5B,KAAKqD,eAAec,OACtB,CA2BU7C,IAAAA,CAAK6B,EAAevD,GAC5B,MAAMgE,EAAY5D,KAAKqD,eAAeI,IAAIN,GACtCS,GACFA,EAAUQ,QAAShB,IACjB,IACEA,EAASxD,EACX,CAAE,MAAOoB,GACPoB,QAAQpB,MAAM,GAAGmC,WAAgBnC,EACnC,GAGN,CAKU2B,wBAAAA,CAAyB3B,GACjC,MAAqB,iBAAVA,GAAgC,OAAVA,GAAkB,SAAUA,GACnDA,EAA2BrB,OAASO,EAAUM,kBAG1D,EChRI,MAAO6D,UAAuBnD,EAClCS,OAAAA,GACE,MAAO,CACL2C,GAAI,WACJrE,KAAM,WACNsE,YAAa,gCAEjB,CAEA7C,WAAAA,GACE,MAAsB,oBAAX8C,QACJC,QAAQD,OAAOE,UAAUC,WAClC,CAEA9C,WAAAA,GACE,MAAsB,oBAAX2C,OAA+B,KAItCA,OAAOE,UAAUC,WACZH,OAAOE,SAGT,IACT,ECxBI,MAAOE,UAAkB1D,EAC7BS,OAAAA,GACE,MAAO,CACL2C,GAAI,MACJrE,KAAM,aACNsE,YAAa,2BAEjB,CAEA7C,WAAAA,GACE,MAAsB,oBAAX8C,QACJC,QAAQD,OAAOK,UACxB,CAEAhD,WAAAA,GACE,MAAsB,oBAAX2C,OAA+B,KACnCA,OAAOK,WAAa,IAC7B,ECbI,MAAOC,UAAsB5D,EACjCS,OAAAA,GACE,MAAO,CACL2C,GAAI,UACJrE,KAAM,UACNsE,YAAa,uBAEjB,CAEA7C,WAAAA,GACE,MAAsB,oBAAX8C,QACJC,QAAQD,OAAOO,SAASL,SACjC,CAEA7C,WAAAA,GACE,MAAsB,oBAAX2C,OAA+B,KACnCA,OAAOO,SAASL,UAAY,IACrC,ECrBI,MAAOM,UAAuB9D,EAClCS,OAAAA,GACE,MAAO,CACL2C,GAAI,WACJrE,KAAM,kBACNsE,YAAa,kCAEjB,CAEA7C,WAAAA,GACE,MAAsB,oBAAX8C,QACJC,QAAQD,OAAOS,wBACxB,CAEApD,WAAAA,GACE,MAAsB,oBAAX2C,OAA+B,KACnCA,OAAOS,yBAA2B,IAC3C,ECdK,MAAMC,EAA+B,CAC1C,IAAIb,EACJ,IAAIO,EACJ,IAAIE,EACJ,IAAIE,GAMA,SAAUG,EAAcb,GAC5B,OAAOY,EAAeE,KAAMC,GAAWA,EAAO1D,UAAU2C,KAAOA,EACjE,CCtBO,MAAMgB,EAAiB,CAC5B/D,QAAS,MACTqB,UAAW,mBACXC,eAAgB,CACd5C,KAAM,QACNsF,OAAQ,MACRC,SAAU,IAEZ1C,QAAS,CAAC,4BACVC,kBAAmB,CAAC,yBAMT0C,EAAiB,CAC5BlE,QAAS,WACTqB,UAAW,UACXC,eAAgB,CACd5C,KAAM,gBACNsF,OAAQ,MACRC,SAAU,IAEZ1C,QAAS,CAAC,2BACVC,kBAAmB,CAAC,iCAMT2C,EAAyB,CAACJ,EAASG,GCvBhD,MAAME,EAAc,8BCLJC,IACd,MAAMC,EAAUC,EAAAA,WAAWzG,GAE3B,IAAKwG,EACH,MAAM,IAAIrG,MAAM,oCAGlB,OAAOqG,CACT,CCPM,SAAUE,GAAYC,QAAEA,IAC5B,MAAMvE,QAAEA,EAAOwE,iBAAEA,GAAqBL,KAC/BM,EAAYC,GAAiBC,EAAAA,UAAS,IACtCpF,EAAOqF,GAAYD,EAAAA,SAAwB,MAoB5CE,EAAiBhC,GAGV,aAAPA,EAEAiC,EAAAA,IAAA,MAAA,CAAKC,UAAU,oFAAmFC,SAAA,OAI3F,QAAPnC,EAEAiC,EAAAA,IAAA,MAAA,CAAKC,UAAU,0EAAyEC,SAAA,MAIjF,YAAPnC,EAEAiC,EAAAA,IAAA,MAAA,CAAKC,UAAU,oFAAmFC,SAAA,MAI3F,aAAPnC,EAEAiC,EAAAA,IAAA,MAAA,CAAKC,UAAU,gFAA+EC,SAAA,MAI3FF,EAAAA,IAAA,MAAA,CAAKC,UAAU,mCAGxB,OACED,EAAAA,WAAKC,UAAU,oBAAoBE,QApCRC,IACvBA,EAAEC,SAAWD,EAAEE,eAAeb,KAmC6BS,SAC7DK,EAAAA,KAAA,MAAA,CAAKN,UAAU,qCAEbM,EAAAA,KAAA,MAAA,CAAKN,UAAU,iBAAgBC,SAAA,CAC7BF,EAAAA,IAAA,MAAA,CAAKC,UAAU,4BACbD,EAAAA,IAAA,KAAA,CAAIC,UAAU,kBAAiBC,SAAA,WAIjCK,EAAAA,KAAA,MAAA,CAAKN,UAAU,kBAAiBC,SAAA,CAE7BR,EAAiBc,IAAK1B,GACrByB,EAAAA,KAAA,SAAA,CAEEJ,QAASA,IA/DDM,WACpBb,GAAc,GACdE,EAAS,MACT,UACQ5E,EAAQwF,GACdjB,GACF,CAAE,MAAO/E,GACPoF,EAASpF,aAAezB,MAAQyB,EAAIvB,QAAU,OAChD,CAAC,QACCyG,GAAc,EAChB,GAqD2Be,CAAc7B,EAAOf,IACpC6C,SAAUjB,EACVM,UAAU,8BAETF,EAAcjB,EAAOf,IACtBiC,EAAAA,IAAA,OAAA,CAAMC,UAAU,SAAQC,SAAEpB,EAAOpF,OAChCiG,GACCK,EAAAA,IAAA,OAAA,CAAMC,UAAU,sCAAqCC,SAAA,aARlDpB,EAAOf,KAgBfY,EACEkC,OAAQC,IAAOA,EAAE3F,eACjBqF,IAAK1B,IACJ,MAAMiC,EAAOjC,EAAO1D,UACpB,OACEmF,EAAAA,UAEES,KAAMD,EAAK/C,YACXqC,OAAO,SACPY,IAAI,sBACJhB,UAAU,iDAAgDC,SAAA,CAEzDH,EAAcgB,EAAKhD,IACpBiC,EAAAA,YAAMC,UAAU,SAAQC,SAAEa,EAAKrH,OAC/BsG,EAAAA,YAAMC,UAAU,+DAA8DC,SAAA,SARzEa,EAAKhD,SAgBnBtD,GACCuF,EAAAA,IAAA,MAAA,CAAKC,UAAU,qDAAoDC,SAChEzF,OAMP8F,EAAAA,KAAA,MAAA,CAAKN,UAAU,iCAAgCC,SAAA,CAE7CK,EAAAA,KAAA,MAAA,CAAKN,UAAU,mDACbD,EAAAA,IAAA,MAAA,CAAKC,UAAU,yDACfD,EAAAA,IAAA,MAAA,CAAKC,UAAU,2DACfD,EAAAA,WAAKC,UAAU,0DACfD,EAAAA,IAAA,MAAA,CAAKC,UAAU,8DAGjBD,EAAAA,IAAA,KAAA,CAAIC,UAAU,2EAGdM,EAAAA,KAAA,KAAA,CAAIN,UAAU,wEAAuEC,SAAA,CACnFK,EAAAA,KAAA,KAAA,CAAIN,UAAU,yBAAwBC,SAAA,CACpCF,EAAAA,IAAA,OAAA,CAAMC,UAAU,OAAMC,SAAA,OACtBK,EAAAA,KAAA,OAAA,CAAAL,SAAA,CAAA,WAEEF,EAAAA,IAAA,KAAA,CAAA,GAAM,oBAIVO,EAAAA,KAAA,KAAA,CAAIN,UAAU,mCACZD,EAAAA,IAAA,OAAA,CAAMC,UAAU,OAAMC,SAAA,OACtBK,EAAAA,KAAA,OAAA,CAAAL,SAAA,CAAA,WAEEF,EAAAA,IAAA,KAAA,CAAA,GAAM,sBAMZA,EAAAA,IAAA,SAAA,CAAQC,UAAU,sKAO5B,CCxJM,SAAUiB,GAAczB,QAAEA,IAC9B,MAAM0B,gBAAEA,EAAejF,YAAEA,EAAWkF,MAAEA,GAAU/B,IAahD,OACEW,EAAAA,IAAA,MAAA,CAAKC,UAAU,oBAAoBE,QALRC,IACvBA,EAAEC,SAAWD,EAAEE,eAAeb,cAKhCc,EAAAA,KAAA,MAAA,CAAKN,UAAU,uCACbM,EAAAA,KAAA,MAAA,CAAKN,UAAU,sFAAqFC,SAAA,CAClGF,EAAAA,IAAA,KAAA,CAAIC,UAAU,0CAAyCC,SAAA,SACvDF,EAAAA,IAAA,SAAA,CAAQG,QAASV,EAASQ,UAAU,0BAAyBC,SAAA,SAK/DF,EAAAA,IAAA,MAAA,CAAKC,UAAU,gBAAeC,SAC3BiB,EAAgBX,IAAKrE,GACpBoE,EAAAA,eAEEJ,QAASA,IAzBAM,WACfW,EAAMpG,UAAYA,SACdkB,EAAYlB,GAEpByE,KAqByB4B,CAAalF,EAAMnB,SAClCiF,UAAW,qBAAoBmB,EAAMpG,UAAYmB,EAAMnB,QAAU,SAAW,IAAIkF,SAAA,CAEhFK,EAAAA,KAAA,MAAA,CAAKN,UAAU,oBAAmBC,SAAA,CAEhCF,EAAAA,IAAA,MAAA,CACEC,UAAW,uEACS,QAAlB9D,EAAMnB,QAAoB,cAAgB,iBAC1CkF,SAED/D,EAAME,UAAU,KAEnB2D,EAAAA,IAAA,OAAA,CAAAE,SAAO/D,EAAME,eAGd+E,EAAMpG,UAAYmB,EAAMnB,SACvBgF,EAAAA,IAAA,OAAA,CAAMC,UAAU,mCAAkCC,SAAA,UAjB/C/D,EAAMnB,gBAyBzB,CCxDM,SAAUsG,EAAcC,GAC5B,IAAKA,GAA6B,QAAfA,EAAsB,MAAO,QAEhD,IACE,MAAMC,EAAMD,EAAWE,WAAW,MAAQF,EAAa,KAAKA,IACtDG,EAAMC,OAAOH,GAEbI,EAAU,qBACVC,EAAcH,EAAME,EAOpBE,GANYJ,EAAME,GAGGG,WAAWC,SAAS,GAAI,KAAKC,MAAM,EAAG,GAG9BC,QAAQ,MAAO,IAElD,OAAOJ,EACH,GAAGD,KAAeC,QAClB,GAAGD,OACT,CAAE,MAAOpH,GAEP,OADAoB,QAAQpB,MAAM,4BAA6BA,GACpC,OACT,CACF,CAKM,SAAU0H,EAAcpG,GAC5B,OAAKA,EACE,GAAGA,EAAQkG,MAAM,EAAG,QAAQlG,EAAQkG,OAAM,KAD5B,EAEvB,CC3BM,SAAUG,GAAa3C,QAAEA,IAC7B,MAAM2B,MAAEA,EAAKzF,WAAEA,GAAe0D,KACxBgD,QAAEA,EAAOC,QAAEA,GAAYlB,EAqB7B,OACEpB,EAAAA,WAAKC,UAAU,oBAAoBE,QAPRC,IACvBA,EAAEC,SAAWD,EAAEE,eACjBb,KAK6DS,SAC7DK,EAAAA,YAAKN,UAAU,4BAA2BC,SAAA,CACxCF,EAAAA,IAAA,SAAA,CAAQG,QAASV,EAASQ,UAAU,yCAIpCD,EAAAA,IAAA,MAAA,CAAKC,UAAU,6BAEfD,EAAAA,IAAA,MAAA,CAAKC,UAAU,qCACZkC,EAAcE,KAGjBrC,EAAAA,IAAA,MAAA,CAAKC,UAAU,4BAA2BC,SACvCkB,EAAMkB,SAAW,UAIpB/B,EAAAA,YAAKN,UAAU,sBAAqBC,SAAA,CAClCK,EAAAA,KAAA,SAAA,CAAQJ,QAtCGM,UACb4B,SACIE,UAAUC,UAAUC,UAAUJ,IAoCHpC,UAAU,oBAAmBC,SAAA,CAExDK,EAAAA,KAAA,MAAA,CACEmC,MAAM,KACNC,OAAO,KACPC,QAAQ,YACRC,KAAK,OACLC,OAAO,eACPC,YAAY,IAAG7C,SAAA,CAEfF,EAAAA,IAAA,OAAA,CAAMgD,EAAE,IAAIC,EAAE,IAAIP,MAAM,KAAKC,OAAO,KAAKO,GAAG,IAAIC,GAAG,MACnDnD,EAAAA,IAAA,OAAA,CAAMoD,EAAE,+DACJ,UAIR7C,EAAAA,KAAA,SAAA,CACEJ,QAhDeM,gBACjB9E,IACN8D,KA+CQQ,UAAU,8DAGVM,EAAAA,KAAA,MAAA,CACEmC,MAAM,KACNC,OAAO,KACPC,QAAQ,YACRC,KAAK,OACLC,OAAO,eACPC,YAAY,cAEZ/C,EAAAA,IAAA,OAAA,CAAMoD,EAAE,4CACRpD,EAAAA,IAAA,WAAA,CAAUqD,OAAO,qBACjBrD,EAAAA,YAAMsD,GAAG,KAAKC,GAAG,KAAKC,GAAG,IAAIC,GAAG,2BAQ9C,gFCjFE,MAAMrC,MAAEA,GAAU/B,KACXqE,EAAiBC,GAAsB9D,EAAAA,UAAS,IAChD+D,EAAmBC,GAAwBhE,EAAAA,UAAS,IACpDiE,EAAkBC,GAAuBlE,EAAAA,UAAS,GAEzD,OAAKuB,EAAM4C,YAiBTzD,EAAAA,KAAA0D,EAAAA,SAAA,CAAA/D,SAAA,CACEF,EAAAA,IAAA,MAAA,CAAKC,UAAU,uBAAsBC,SACnCK,EAAAA,KAAA,MAAA,CAAKN,UAAU,wBAAuBC,SAAA,CAEpCK,EAAAA,KAAA,SAAA,CACEJ,QAASA,IAAM0D,GAAqB,GACpC5D,UAAU,mBAAkBC,SAAA,CAG5BF,EAAAA,IAAA,MAAA,CACEC,UAAW,wBACS,QAAlBmB,EAAMpG,QACF,cACkB,aAAlBoG,EAAMpG,QACJ,gBACA,wEACkDkF,SAEvC,QAAlBkB,EAAMpG,QACH,IACkB,aAAlBoG,EAAMpG,QACJ,IACA,MAERuF,EAAAA,uBACqB,QAAlBa,EAAMpG,SAAqB,WACT,aAAlBoG,EAAMpG,SAA0B,UAChCoG,EAAMpG,SACa,QAAlBoG,EAAMpG,SACY,aAAlBoG,EAAMpG,SACN,aAEJgF,EAAAA,IAAA,MAAA,CACE0C,MAAM,KACNC,OAAO,KACPC,QAAQ,YACRC,KAAK,OACL5C,UAAU,yBAEVD,EAAAA,IAAA,OAAA,CACEoD,EAAE,uBACFN,OAAO,eACPC,YAAY,MACZmB,cAAc,QACdC,eAAe,eAMrBnE,EAAAA,IAAA,MAAA,CAAKC,UAAU,cAAaC,SACzBkB,EAAMkB,QAAUhB,EAAcF,EAAMkB,SAAW,UAIlD/B,EAAAA,eACEJ,QAASA,IAAM4D,GAAoB,GACnC9D,UAAU,qBAAoBC,SAAA,CAE9BF,EAAAA,qBAAOoB,EAAMiB,SAAWF,EAAcf,EAAMiB,WAC5CrC,EAAAA,IAAA,MAAA,CAAKC,UAAU,uBACfD,EAAAA,IAAA,MAAA,CACE0C,MAAM,KACNC,OAAO,KACPC,QAAQ,YACRC,KAAK,OACL5C,UAAU,8BAEVD,EAAAA,IAAA,OAAA,CACEoD,EAAE,uBACFN,OAAO,eACPC,YAAY,MACZmB,cAAc,QACdC,eAAe,oBAOxBP,GACC5D,EAAAA,IAACkB,EAAa,CAACzB,QAASA,IAAMoE,GAAqB,KAGpDC,GACC9D,EAAAA,IAACoC,EAAY,CAAC3C,QAASA,IAAMsE,GAAoB,QApGnDxD,EAAAA,KAAA0D,EAAAA,SAAA,CAAA/D,SAAA,CACEF,EAAAA,IAAA,SAAA,CACEG,QAASA,IAAMwD,GAAmB,GAClC1D,UAAU,gDAA+CC,SAAA,SAI1DwD,GACC1D,EAAAA,IAACR,EAAW,CAACC,QAASA,IAAMkE,GAAmB,OAgGzD,4HNrG+BzD,SAAEA,EAAQkE,OAAEA,IACzC,MAAMC,OAAEA,EAASlF,EAAamF,YAAEA,GAAc,GAASF,GAEhDhD,EAAOmD,GAAY1E,WAAsB,CAC9CmE,aAAa,EACb3B,QAAS,KACTrH,QAAS,KACTsH,QAAS,KACTxD,OAAQ,QAGH0F,EAAeC,GAAoB5E,EAAAA,SAA4B,MAKhEH,EAAiCgF,EAAAA,QAAQ,IACtC/F,EACJkC,OAAQ/B,GAAWA,EAAO3D,eAC1BqF,IAAK1B,GAAWA,EAAO1D,WACzB,IAKmBuJ,cACpBlE,MAAO3B,EAAoBuD,KACzB,IACE,MAAMC,QAAgBxD,EAAOhD,WAAWuG,GACxCkC,EAAUK,IAAI,IAAWA,EAAMtC,YACjC,CAAE,MAAO7H,GACPoB,QAAQpB,MAAM,UAAWA,EAC3B,GAEF,IAMF,MAAMS,EAAUyJ,cACdlE,UACE,IAEE,GAAIW,EAAM4C,aAAe5C,EAAMtC,QAAQf,KAAO2C,EAC5C,MAAMnG,EAAkB,QAASZ,EAAUW,mBAIzCkK,SACIA,EAAc7I,aAItB,MAAMmD,EAASF,EAAc8B,GAC7B,IAAK5B,EACH,MAAMvE,EACJ,SAASmG,IACT/G,EAAUS,oBAKd,MAAMU,QAAiBgE,EAAO5D,UACxBF,QAAgB8D,EAAO7C,aACvBqG,QAAgBxD,EAAOhD,WAAWhB,EAAS,IAE3C+J,EAAa/F,EAAO1D,UAG1B0D,EAAOnC,GAAG,kBAAmB8D,UAC3B,MAAMqE,EAAchK,EACpB,GAA2B,IAAvBgK,EAAYpJ,OAEdC,QACK,CACL,MAAMoJ,EAAaD,EAAY,GACzBE,QAAmBlG,EAAOhD,WAAWiJ,GAC3CR,EAAUK,IAAI,IACTA,EACHvC,QAAS0C,EACTzC,QAAS0C,IAEb,IAGFlG,EAAOnC,GAAG,eAAgB8D,UAExB,MAAMwE,SAAwBnG,EAAOlD,eAAe,GACpD,IAAIoJ,EAAa,MACbC,IACFD,QAAmBlG,EAAOhD,WAAWmJ,IAGvCV,EAAUK,IAAI,IACTA,EACH5J,QAASA,EACTsH,QAAS0C,OAIblG,EAAOnC,GAAG,aAAc,KACtBhB,MAGF8I,EAAiB3F,GACjByF,EAAS,CACPP,aAAa,EACb3B,QAASvH,EAAS,GAClBE,UACAsH,UACAxD,OAAQ+F,IAIY,oBAAX5G,QACTiH,aAAaC,QACX/F,EACAgG,KAAKC,UAAU,CAAE3E,WAAU2B,QAASvH,EAAS,KAGnD,CAAE,MAAOL,GAEP,MADAoB,QAAQpB,MAAM,UAAWA,GACnBA,CACR,GAEF,CAAC2G,EAAM4C,YAAa5C,EAAMtC,OAAQ0F,IAM9B7I,EAAagJ,EAAAA,YAAYlE,UACzB+D,SACIA,EAAc7I,aAGtB8I,EAAiB,MACjBF,EAAS,CACPP,aAAa,EACb3B,QAAS,KACTrH,QAAS,KACTsH,QAAS,KACTxD,OAAQ,OAIY,oBAAXb,QACTiH,aAAaI,WAAWlG,IAEzB,CAACoF,IAKEtI,EAAcyI,cAClBlE,UACE,IAAK+D,EACH,MAAMjK,EAAkB,QAASZ,EAAUI,cAG7C,MAAMoC,ED3IN,SACJnB,EACAqJ,GAEA,OAAOA,EAAOxF,KACX1C,GAAUA,EAAMnB,QAAQuK,gBAAkBvK,EAAQuK,cAEvD,CCoIoBC,CAAaxK,EAASqJ,GACpC,IAAKlI,EACH,MAAM5B,EACJ,QAAQS,IACRrB,EAAUM,0BAIRuK,EAActI,YAAYC,IAIlC,CAACqI,EAAeH,IAMlBoB,EAAAA,UAAU,KACR,IAAKnB,EAAa,OAES7D,WACzB,GAAsB,oBAAXxC,OAAwB,OAEnC,MAAMyH,EAASR,aAAaS,QAAQvG,GACpC,GAAKsG,EAEL,IACE,MAAMhF,SAAEA,GAAa0E,KAAKQ,MAAMF,GAC1B5G,EAASF,EAAc8B,GAE7B,IAAK5B,EAEH,YADAoG,aAAaI,WAAWlG,GAK1B,IAAIyG,EAAa,EACjB,MAAQ/G,EAAO3D,eAAiB0K,EAAa,UACrC,IAAIC,QAASC,GAAYC,WAAWD,EAAS,MACnDF,IAGF,IAAK/G,EAAO3D,cAEV,YADA+J,aAAaI,WAAWlG,SAKpBlE,EAAQwF,EAChB,CAAE,MAAOjG,GACPoB,QAAQpB,MAAM,UAAWA,GACzByK,aAAaI,WAAWlG,EAC1B,GAGF6G,IACC,CAAC3B,IAEJ,MAAM1J,EAAQ8J,EAAAA,QACZ,KAAA,CACEtD,QACAlG,UACAS,aACAO,cACAwD,mBACAyB,gBAAiBkD,IAEnB,CAACjD,EAAOlG,EAASS,EAAYO,EAAawD,EAAkB2E,IAG9D,OACErE,EAAAA,IAAClH,EAAcoN,SAAQ,CAACtL,MAAOA,EAAKsF,SAAGA,GAE3C"}
1
+ {"version":3,"file":"index.js","sources":["../../src/context/WalletContext.tsx","../../src/types/wallet.ts","../../src/utils/errors.ts","../../src/wallets/BaseWallet.ts","../../src/wallets/MetaMaskWallet.ts","../../src/wallets/OKXWallet.ts","../../src/wallets/PhantomWallet.ts","../../src/wallets/CoinbaseWallet.ts","../../src/wallets/index.ts","../../src/utils/chains.ts","../../src/components/WalletProvider.tsx","../../src/hooks/useWallet.ts","../../src/components/WalletModal.tsx","../../src/components/ChainSwitcher.tsx","../../src/utils/format.ts","../../src/components/AccountModal.tsx","../../src/components/ConnectButton.tsx"],"sourcesContent":["import { createContext } from \"react\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 钱包上下文\n */\nexport const WalletContext = createContext<WalletContextValue | null>(null);\n","/**\n * 基于 EIP-1193 的以太坊提供者接口\n */\nexport interface EthereumProvider {\n request(args: RequestArguments): Promise<unknown>;\n on(event: string, listener: (...args: unknown[]) => void): void;\n removeListener(event: string, listener: (...args: unknown[]) => void): void;\n isMetaMask?: boolean;\n isOkxWallet?: boolean;\n isCoinbaseWallet?: boolean;\n isPhantom?: boolean;\n}\n\n/**\n * JSON-RPC 调用请求参数\n */\nexport interface RequestArguments {\n method: string;\n params?: unknown[] | Record<string, unknown>;\n}\n\n/**\n * 链配置\n */\nexport interface Chain {\n chainId: string; // 十六进制字符串,例如 \"0x1\"\n chainName: string;\n nativeCurrency: {\n name: string;\n symbol: string;\n decimals: number;\n };\n rpcUrls: string[];\n blockExplorerUrls?: string[];\n iconUrls?: string[];\n}\n\n/**\n * 钱包信息\n */\nexport interface WalletInfo {\n id: string;\n name: string;\n icon?: string;\n downloadUrl?: string;\n}\n\n/**\n * 钱包连接状态\n */\nexport interface WalletState {\n isConnected: boolean;\n account: string | null;\n chainId: string | null;\n balance: string | null;\n wallet: WalletInfo | null;\n}\n\n/**\n * 钱包事件类型\n */\nexport type WalletEventType =\n | \"accountsChanged\"\n | \"chainChanged\"\n | \"connect\"\n | \"disconnect\";\n\n/**\n * 事件监听器类型\n */\nexport type WalletEventListener = (data: unknown) => void;\n\n/**\n * 钱包错误类型\n */\nexport class WalletError extends Error {\n code: number;\n data?: unknown;\n\n constructor(message: string, code: number, data?: unknown) {\n super(message);\n this.name = \"WalletError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/**\n * 钱包提供者上下文值\n */\nexport interface WalletContextValue {\n state: WalletState;\n connect: (walletId: string) => Promise<void>;\n disconnect: () => Promise<void>;\n switchChain: (chainId: string) => Promise<void>;\n availableWallets: WalletInfo[];\n supportedChains: Chain[];\n}\n\n/**\n * 钱包提供者配置\n */\nexport interface WalletProviderConfig {\n chains: Chain[];\n autoConnect?: boolean;\n appName?: string;\n}\n","import { WalletError } from \"../types\";\n\n/**\n * 基于 EIP-1193 的错误代码\n */\nexport const ErrorCode = {\n USER_REJECTED: 4001,\n UNAUTHORIZED: 4100,\n UNSUPPORTED_METHOD: 4200,\n DISCONNECTED: 4900,\n CHAIN_DISCONNECTED: 4901,\n UNRECOGNIZED_CHAIN: 4902,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n PROVIDER_NOT_FOUND: -32000,\n WALLET_NOT_INSTALLED: -32001,\n ALREADY_CONNECTED: -32002,\n} as const;\n\n/**\n * 创建钱包错误\n */\nexport function createWalletError(\n message: string,\n code: number,\n data?: unknown,\n): WalletError {\n return new WalletError(message, code, data);\n}\n\n/**\n * 检查错误是否为用户拒绝\n */\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof WalletError) {\n return error.code === ErrorCode.USER_REJECTED;\n }\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.USER_REJECTED;\n }\n return false;\n}\n\n/**\n * 解析提供者错误\n */\nexport function parseProviderError(error: unknown): WalletError {\n if (error instanceof WalletError) {\n return error;\n }\n\n if (typeof error === \"object\" && error !== null) {\n const err = error as {\n code?: number;\n message?: string;\n data?: unknown;\n };\n\n return createWalletError(\n err.message || \"未知错误\",\n err.code || ErrorCode.INTERNAL_ERROR,\n err.data,\n );\n }\n\n if (typeof error === \"string\") {\n return createWalletError(error, ErrorCode.INTERNAL_ERROR);\n }\n\n return createWalletError(\"发生未知错误\", ErrorCode.INTERNAL_ERROR);\n}\n","import {\n EthereumProvider,\n RequestArguments,\n Chain,\n WalletInfo,\n WalletEventListener,\n} from \"../types\";\nimport {\n ErrorCode,\n createWalletError,\n parseProviderError,\n} from \"../utils/errors\";\n\n/**\n * 钱包基类(抽象类)\n * 所有钱包实现都应继承此类\n */\nexport abstract class BaseWallet {\n protected provider: EthereumProvider | null = null;\n protected eventListeners: Map<string, Set<WalletEventListener>> = new Map();\n\n /**\n * 获取钱包信息\n */\n abstract getInfo(): WalletInfo;\n\n /**\n * 检查钱包是否安装\n */\n abstract isInstalled(): boolean;\n\n /**\n * 获取提供者实例\n */\n abstract getProvider(): EthereumProvider | null;\n\n /**\n * 连接钱包\n */\n async connect(): Promise<string[]> {\n if (!this.isInstalled()) {\n throw createWalletError(\n `${this.getInfo().name} 未安装`,\n ErrorCode.WALLET_NOT_INSTALLED,\n );\n }\n\n const provider = this.getProvider();\n if (!provider) {\n throw createWalletError(\"未找到提供者\", ErrorCode.PROVIDER_NOT_FOUND);\n }\n\n this.provider = provider;\n this.setupEventListeners();\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_requestAccounts\",\n });\n\n if (!accounts || accounts.length === 0) {\n throw createWalletError(\"未返回账户\", ErrorCode.UNAUTHORIZED);\n }\n\n return accounts;\n } catch (error) {\n this.cleanup();\n throw parseProviderError(error);\n }\n }\n\n /**\n * 断开钱包连接\n */\n async disconnect(): Promise<void> {\n this.cleanup();\n }\n\n /**\n * 获取当前账户\n */\n async getAccounts(): Promise<string[]> {\n if (!this.provider) {\n return [];\n }\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_accounts\",\n });\n return accounts || [];\n } catch (error) {\n console.error(\"获取账户失败:\", error);\n return [];\n }\n }\n\n /**\n * 获取当前账户余额\n */\n async getBalance(address: string): Promise<string> {\n if (!this.provider) {\n return \"0x0\";\n }\n\n try {\n const balance = await this.request<string>({\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n });\n return balance;\n } catch (error) {\n console.error(\"获取余额失败:\", error);\n return \"0x0\";\n }\n }\n\n /**\n * 获取当前链 ID\n */\n async getChainId(): Promise<string> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const chainId = await this.request<string>({\n method: \"eth_chainId\",\n });\n return chainId;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 切换到指定链\n */\n async switchChain(chain: Chain): Promise<void> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n // 尝试切换链\n await this.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: chain.chainId }],\n });\n } catch (error) {\n // 如果未添加该链,则尝试添加\n if (this.isUnrecognizedChainError(error)) {\n try {\n await this.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: chain.chainId,\n chainName: chain.chainName,\n nativeCurrency: chain.nativeCurrency,\n rpcUrls: chain.rpcUrls,\n blockExplorerUrls: chain.blockExplorerUrls,\n iconUrls: chain.iconUrls,\n },\n ],\n });\n } catch (addError) {\n throw parseProviderError(addError);\n }\n } else {\n throw parseProviderError(error);\n }\n }\n }\n\n /**\n * 添加事件监听器\n */\n on(event: string, listener: WalletEventListener): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(listener);\n }\n\n /**\n * 移除事件监听器\n */\n off(event: string, listener: WalletEventListener): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 发起 JSON-RPC 请求\n */\n protected async request<T = unknown>(args: RequestArguments): Promise<T> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const result = await this.provider.request(args);\n return result as T;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 设置提供者事件监听\n */\n protected setupEventListeners(): void {\n if (!this.provider) return;\n\n this.provider.on(\"accountsChanged\", this.handleAccountsChanged);\n this.provider.on(\"chainChanged\", this.handleChainChanged);\n this.provider.on(\"disconnect\", this.handleDisconnect);\n }\n\n /**\n * 清理资源和监听器\n */\n protected cleanup(): void {\n if (this.provider) {\n this.provider.removeListener(\n \"accountsChanged\",\n this.handleAccountsChanged,\n );\n this.provider.removeListener(\"chainChanged\", this.handleChainChanged);\n this.provider.removeListener(\"disconnect\", this.handleDisconnect);\n }\n this.provider = null;\n this.eventListeners.clear();\n }\n\n /**\n * 处理账户变更事件\n */\n protected handleAccountsChanged = (accounts: unknown): void => {\n this.emit(\"accountsChanged\", accounts);\n };\n\n /**\n * 处理链变更事件\n */\n protected handleChainChanged = (chainId: unknown): void => {\n this.emit(\"chainChanged\", chainId);\n };\n\n /**\n * 处理断开连接事件\n */\n protected handleDisconnect = (): void => {\n this.emit(\"disconnect\", null);\n this.cleanup();\n };\n\n /**\n * 向所有监听器触发事件\n */\n protected emit(event: string, data: unknown): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`${event} 监听器错误:`, error);\n }\n });\n }\n }\n\n /**\n * 检查错误是否为未知链错误\n */\n protected isUnrecognizedChainError(error: unknown): boolean {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.UNRECOGNIZED_CHAIN;\n }\n return false;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n ethereum?: EthereumProvider;\n }\n}\n\n/**\n * MetaMask 钱包实现\n */\nexport class MetaMaskWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"metamask\",\n name: \"MetaMask\",\n downloadUrl: \"https://metamask.io/download/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.ethereum?.isMetaMask);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n\n // MetaMask 可能会与其他钱包共享 window.ethereum\n // 尝试获取 MetaMask 专属的提供者\n if (window.ethereum?.isMetaMask) {\n return window.ethereum;\n }\n\n return null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n okxwallet?: EthereumProvider;\n }\n}\n\n/**\n * OKX 钱包实现\n */\nexport class OKXWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"okx\",\n name: \"OKX Wallet\",\n downloadUrl: \"https://www.okx.com/web3\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.okxwallet);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.okxwallet || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n phantom?: {\n ethereum?: EthereumProvider;\n };\n }\n}\n\n/**\n * Phantom 钱包实现\n * Phantom 支持 Solana 和 Ethereum\n * 我们使用 ethereum 属性以兼容 EVM\n */\nexport class PhantomWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"phantom\",\n name: \"Phantom\",\n downloadUrl: \"https://phantom.app/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.phantom?.ethereum);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.phantom?.ethereum || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n coinbaseWalletExtension?: EthereumProvider;\n }\n}\n\n/**\n * Coinbase 钱包实现\n */\nexport class CoinbaseWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"coinbase\",\n name: \"Coinbase Wallet\",\n downloadUrl: \"https://www.coinbase.com/wallet\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.coinbaseWalletExtension);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.coinbaseWalletExtension || null;\n }\n}\n","export { BaseWallet } from \"./BaseWallet\";\nexport { MetaMaskWallet } from \"./MetaMaskWallet\";\nexport { OKXWallet } from \"./OKXWallet\";\nexport { PhantomWallet } from \"./PhantomWallet\";\nexport { CoinbaseWallet } from \"./CoinbaseWallet\";\n\nimport { MetaMaskWallet } from \"./MetaMaskWallet\";\nimport { OKXWallet } from \"./OKXWallet\";\nimport { PhantomWallet } from \"./PhantomWallet\";\nimport { CoinbaseWallet } from \"./CoinbaseWallet\";\nimport { BaseWallet } from \"./BaseWallet\";\n\n/**\n * 所有可用钱包的注册表\n */\nexport const walletRegistry: BaseWallet[] = [\n new MetaMaskWallet(),\n new OKXWallet(),\n new PhantomWallet(),\n new CoinbaseWallet(),\n];\n\n/**\n * 根据 ID 获取钱包\n */\nexport function getWalletById(id: string): BaseWallet | undefined {\n return walletRegistry.find((wallet) => wallet.getInfo().id === id);\n}\n","import { Chain } from \"../types\";\n\n/**\n * 以太坊主网\n */\nexport const mainnet: Chain = {\n chainId: \"0x1\",\n chainName: \"Ethereum Mainnet\",\n nativeCurrency: {\n name: \"Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://eth.llamarpc.com\"],\n blockExplorerUrls: [\"https://etherscan.io\"],\n};\n\n/**\n * Sepolia 测试网\n */\nexport const sepolia: Chain = {\n chainId: \"0xaa36a7\",\n chainName: \"Sepolia\",\n nativeCurrency: {\n name: \"Sepolia Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://rpc.sepolia.org\"],\n blockExplorerUrls: [\"https://sepolia.etherscan.io\"],\n};\n\n/**\n * 默认链列表\n */\nexport const defaultChains: Chain[] = [mainnet, sepolia];\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(\n chainId: string,\n chains: Chain[],\n): Chain | undefined {\n return chains.find(\n (chain) => chain.chainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * 将 chainId 格式化为十六进制字符串\n */\nexport function formatChainId(chainId: number | string): string {\n if (typeof chainId === \"string\") {\n if (chainId.startsWith(\"0x\")) {\n return chainId;\n }\n return `0x${parseInt(chainId, 10).toString(16)}`;\n }\n return `0x${chainId.toString(16)}`;\n}\n\n/**\n * 将 chainId 解析为数字\n */\nexport function parseChainId(chainId: string): number {\n if (chainId.startsWith(\"0x\")) {\n return parseInt(chainId, 16);\n }\n return parseInt(chainId, 10);\n}\n","import React, { useState, useEffect, useCallback, useMemo } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletProviderConfig, WalletState, Chain, WalletInfo } from \"../types\";\nimport { walletRegistry, getWalletById, BaseWallet } from \"../wallets\";\nimport { ErrorCode, createWalletError } from \"../utils/errors\";\nimport { defaultChains, getChainById } from \"../utils/chains\";\n\ninterface WalletProviderProps {\n children: React.ReactNode;\n config: WalletProviderConfig;\n}\n\nconst STORAGE_KEY = \"wjb_wallet_connect\";\n\n/**\n * 钱包提供者组件\n * 管理钱包连接状态并向子组件提供钱包上下文\n */\nexport function WalletProvider({ children, config }: WalletProviderProps) {\n const { chains = defaultChains, autoConnect = true } = config;\n\n const [state, setState] = useState<WalletState>({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n const [currentWallet, setCurrentWallet] = useState<BaseWallet | null>(null);\n\n /**\n * 获取可用(已安装)的钱包\n */\n const availableWallets: WalletInfo[] = useMemo(() => {\n return walletRegistry\n .filter((wallet) => wallet.isInstalled())\n .map((wallet) => wallet.getInfo());\n }, []);\n\n /**\n * 更新余额\n */\n const updateBalance = useCallback(\n async (wallet: BaseWallet, account: string) => {\n try {\n const balance = await wallet.getBalance(account);\n setState((prev) => ({ ...prev, balance }));\n } catch (error) {\n console.error(\"更新余额失败:\", error);\n }\n },\n [],\n );\n\n /**\n * 连接到指定钱包\n */\n const connect = useCallback(\n async (walletId: string) => {\n try {\n // 检查是否已连接\n if (state.isConnected && state.wallet?.id === walletId) {\n throw createWalletError(\"钱包已连接\", ErrorCode.ALREADY_CONNECTED);\n }\n\n // 如果有当前连接的钱包,先断开\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n // 获取钱包实例\n const wallet = getWalletById(walletId);\n if (!wallet) {\n throw createWalletError(\n `未找到钱包 ${walletId}`,\n ErrorCode.PROVIDER_NOT_FOUND,\n );\n }\n\n // 连接钱包\n const accounts = await wallet.connect();\n const chainId = await wallet.getChainId();\n const balance = await wallet.getBalance(accounts[0]);\n\n const walletInfo = wallet.getInfo();\n\n // 设置事件监听器\n wallet.on(\"accountsChanged\", async (accounts) => {\n const accountList = accounts as string[];\n if (accountList.length === 0) {\n // 用户断开连接\n disconnect();\n } else {\n const newAccount = accountList[0];\n const newBalance = await wallet.getBalance(newAccount);\n setState((prev) => ({\n ...prev,\n account: newAccount,\n balance: newBalance,\n }));\n }\n });\n\n wallet.on(\"chainChanged\", async (chainId) => {\n // 链改变后重新获取余额\n const currentAccount = (await wallet.getAccounts())[0];\n let newBalance = \"0x0\";\n if (currentAccount) {\n newBalance = await wallet.getBalance(currentAccount);\n }\n\n setState((prev) => ({\n ...prev,\n chainId: chainId as string,\n balance: newBalance,\n }));\n });\n\n wallet.on(\"disconnect\", () => {\n disconnect();\n });\n\n setCurrentWallet(wallet);\n setState({\n isConnected: true,\n account: accounts[0],\n chainId,\n balance,\n wallet: walletInfo,\n });\n\n // 保存到 localStorage 以便自动连接\n if (typeof window !== \"undefined\") {\n localStorage.setItem(\n STORAGE_KEY,\n JSON.stringify({ walletId, account: accounts[0] }),\n );\n }\n } catch (error) {\n console.error(\"连接钱包失败:\", error);\n throw error;\n }\n },\n [state.isConnected, state.wallet, currentWallet],\n );\n\n /**\n * 断开钱包连接\n */\n const disconnect = useCallback(async () => {\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n setCurrentWallet(null);\n setState({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n // 清除 localStorage\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, [currentWallet]);\n\n /**\n * 切换链\n */\n const switchChain = useCallback(\n async (chainId: string) => {\n if (!currentWallet) {\n throw createWalletError(\"未连接钱包\", ErrorCode.DISCONNECTED);\n }\n\n const chain = getChainById(chainId, chains);\n if (!chain) {\n throw createWalletError(\n `不支持链 ${chainId}`,\n ErrorCode.UNRECOGNIZED_CHAIN,\n );\n }\n\n await currentWallet.switchChain(chain);\n\n // chainChanged 事件将更新状态\n },\n [currentWallet, chains],\n );\n\n /**\n * 组件挂载时自动连接\n */\n useEffect(() => {\n if (!autoConnect) return;\n\n const attemptAutoConnect = async () => {\n if (typeof window === \"undefined\") return;\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return;\n\n try {\n const { walletId } = JSON.parse(stored);\n const wallet = getWalletById(walletId);\n\n if (!wallet) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 尝试等待钱包注入(解决页面刷新时注入延迟问题)\n let retryCount = 0;\n while (!wallet.isInstalled() && retryCount < 10) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n retryCount++;\n }\n\n if (!wallet.isInstalled()) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 如果已安装钱包插件则自动连接\n await connect(walletId);\n } catch (error) {\n console.error(\"自动连接失败:\", error);\n localStorage.removeItem(STORAGE_KEY);\n }\n };\n\n attemptAutoConnect();\n }, [autoConnect]);\n\n const value = useMemo(\n () => ({\n state,\n connect,\n disconnect,\n switchChain,\n availableWallets,\n supportedChains: chains,\n }),\n [state, connect, disconnect, switchChain, availableWallets, chains],\n );\n\n return (\n <WalletContext.Provider value={value}>{children}</WalletContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 访问钱包上下文的 Hook\n */\nexport function useWallet(): WalletContextValue {\n const context = useContext(WalletContext);\n\n if (!context) {\n throw new Error(\"useWallet 必须在 WalletProvider 中使用\");\n }\n\n return context;\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { walletRegistry } from \"../wallets\";\n\ninterface WalletModalProps {\n onClose: () => void;\n}\n\nexport function WalletModal({ onClose }: WalletModalProps) {\n const { connect, availableWallets } = useWallet();\n const [connecting, setConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleConnect = async (walletId: string) => {\n setConnecting(true);\n setError(null);\n try {\n await connect(walletId);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"连接失败\");\n } finally {\n setConnecting(false);\n }\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n // Predefine icons/colors for known wallets or use generic\n const getWalletIcon = (id: string) => {\n // Allow flexible icon rendering. For now, simple colored squares or letters.\n // In a real app, these would be proper SVGs or helper components.\n if (id === \"metamask\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-orange-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-orange-500\">\n 🦊\n </div>\n );\n if (id === \"okx\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-black wjb-flex wjb-items-center wjb-justify-center wjb-text-white\">\n X\n </div>\n );\n if (id === \"phantom\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-purple-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-purple-500\">\n P\n </div>\n );\n if (id === \"coinbase\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-blue-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-blue-500\">\n C\n </div>\n );\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-gray-200\"></div>\n );\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-wallet-modal-content\">\n {/* Left Side: Wallet List */}\n <div className=\"wjb-modal-left\">\n <div className=\"wjb-modal-header\">\n <h2 className=\"wjb-modal-title\">连接钱包</h2>\n {/* Mobile close button could go here, but omitted for clean desktop design or added if needed */}\n </div>\n\n <div className=\"wjb-wallet-list\">\n {/* Installed Wallets */}\n {availableWallets.map((wallet) => (\n <button\n key={wallet.id}\n onClick={() => handleConnect(wallet.id)}\n disabled={connecting}\n className=\"wjb-wallet-option\"\n >\n {getWalletIcon(wallet.id)}\n <span className=\"wjb-flex-1\">{wallet.name}</span>\n {connecting && (\n <span className=\"wjb-text-xs wjb-text-blue-500 wjb-animate-pulse\">\n 连接中...\n </span>\n )}\n </button>\n ))}\n\n {/* Uninstalled Wallets */}\n {walletRegistry\n .filter((w) => !w.isInstalled())\n .map((wallet) => {\n const info = wallet.getInfo();\n return (\n <a\n key={info.id}\n href={info.downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"wjb-wallet-option wjb-opacity-60 wjb-hover:opacity-100\"\n >\n {getWalletIcon(info.id)}\n <span className=\"wjb-flex-1\">{info.name}</span>\n <span className=\"wjb-text-xs wjb-font-bold wjb-text-blue-500 wjb-bg-blue-50 wjb-px-2 wjb-py-1 wjb-rounded\">\n 安装\n </span>\n </a>\n );\n })}\n </div>\n\n {error && (\n <div className=\"wjb-mt-4 wjb-p-3 wjb-bg-red-50 wjb-text-red-500 wjb-text-sm wjb-rounded-xl\">\n {error}\n </div>\n )}\n </div>\n\n {/* Right Side: Education / Info */}\n <div className=\"wjb-modal-right hidden md:flex\">\n {/* Icon Grid Placeholder */}\n <div className=\"wjb-grid wjb-grid-cols-2 wjb-gap-4 wjb-mb-6 wjb-opacity-80\">\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-blue-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-6\"></div>\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-purple-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-12\"></div>\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-orange-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-6\"></div>\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-green-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-12\"></div>\n </div>\n\n <h3 className=\"wjb-text-lg wjb-font-bold wjb-text-gray-900 wjb-dark:text-white wjb-mb-2\">\n 什么是钱包?\n </h3>\n <ul className=\"wjb-text-sm wjb-text-gray-500 wjb-dark:text-gray-400 wjb-space-y-3 wjb-text-left wjb-max-w-xs\">\n <li className=\"wjb-flex wjb-items-start wjb-gap-2\">\n <span className=\"wjb-mt-1\">🏠</span>\n <span>\n 您的数字资产之家\n <br />\n 发送、接收和存储资产。\n </span>\n </li>\n <li className=\"wjb-flex wjb-items-start wjb-gap-2\">\n <span className=\"wjb-mt-1\">🔐</span>\n <span>\n 一种新的登录方式\n <br />\n 无需创建账户和密码。\n </span>\n </li>\n </ul>\n\n <button className=\"wjb-mt-6 wjb-px-4 wjb-py-2 wjb-bg-gray-200 wjb-dark:bg-gray-700 wjb-rounded-lg wjb-text-sm wjb-font-bold wjb-text-gray-700 wjb-dark:text-white wjb-hover:bg-gray-300 wjb-transition-colors\">\n 了解更多\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useRef, useEffect } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\n\ninterface ChainSwitcherProps {\n onClose: () => void;\n}\n\nexport function ChainSwitcher({ onClose }: ChainSwitcherProps) {\n const { supportedChains, switchChain, state } = useWallet();\n // We can use a backdrop for mobile, or click outside for desktop dropdown\n const handleSwitch = async (chainId: string) => {\n if (state.chainId !== chainId) {\n await switchChain(chainId);\n }\n onClose();\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-chain-switcher-content\">\n <div className=\"wjb-p-4 wjb-border-b wjb-border-gray-100 wjb-dark:border-gray-800 wjb-flex wjb-justify-between wjb-items-center\">\n <h3 className=\"wjb-font-bold wjb-text-gray-900 wjb-dark:text-white\">\n 切换网络\n </h3>\n <button onClick={onClose} className=\"wjb-chain-modal-close\">\n ✕\n </button>\n </div>\n\n <div className=\"wjb-p-2 wjb-space-y-1\">\n {supportedChains.map((chain) => (\n <button\n key={chain.chainId}\n onClick={() => handleSwitch(chain.chainId)}\n className={`wjb-chain-option ${state.chainId === chain.chainId ? \"active\" : \"\"}`}\n >\n <div className=\"wjb-flex wjb-items-center\">\n {/* Chain Icons */}\n <div\n className={`wjb-chain-icon wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-xs ${\n chain.chainId === \"0x1\"\n ? \"wjb-bg-blue-500\"\n : \"wjb-bg-purple-500\"\n }`}\n >\n {chain.chainName[0]}\n </div>\n <span>{chain.chainName}</span>\n </div>\n\n {state.chainId === chain.chainId && (\n <span className=\"wjb-text-sm wjb-font-bold wjb-text-green-500\">\n 已连接\n </span>\n )}\n </button>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * Format balance from hex/wei to formatted string\n */\nexport function formatBalance(rawBalance: string | undefined): string {\n if (!rawBalance || rawBalance === \"0x0\") return \"0 ETH\";\n\n try {\n const hex = rawBalance.startsWith(\"0x\") ? rawBalance : `0x${rawBalance}`;\n const wei = BigInt(hex);\n // Rough conversion to ETH (18 decimals), keeping 4 decimal places\n const divisor = 1000000000000000000n;\n const integerPart = wei / divisor;\n const remainder = wei % divisor;\n\n // Convert remainder to decimal string padded with zeros\n const decimals = remainder.toString().padStart(18, \"0\").slice(0, 4);\n\n // Remove trailing zeros if any\n const formattedDecimals = decimals.replace(/0+$/, \"\");\n\n return formattedDecimals\n ? `${integerPart}.${formattedDecimals} ETH`\n : `${integerPart} ETH`;\n } catch (error) {\n console.error(\"Error formatting balance:\", error);\n return \"0 ETH\";\n }\n}\n\n/**\n * Format address to short form 0x...1234\n */\nexport function formatAddress(address: string | null | undefined): string {\n if (!address) return \"\";\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n","import React from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { formatAddress } from \"../utils/format\";\n\ninterface AccountModalProps {\n onClose: () => void;\n}\n\nexport function AccountModal({ onClose }: AccountModalProps) {\n const { state, disconnect } = useWallet();\n const { account, balance } = state;\n\n const handleCopy = async () => {\n if (account) {\n await navigator.clipboard.writeText(account);\n // Could add toast here\n }\n };\n\n const handleDisconnect = async () => {\n await disconnect();\n onClose();\n };\n\n // Close when clicking overlay\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-account-modal-content\">\n <button onClick={onClose} className=\"wjb-account-modal-close\">\n ✕\n </button>\n\n <div className=\"wjb-account-avatar-large\" />\n\n <div className=\"wjb-account-address-large\">\n {formatAddress(account)}\n </div>\n\n <div className=\"wjb-account-balance-large\">\n {state.balance || \"0 ETH\"}\n {/* Fallback not really needed if state init correct, but safe */}\n </div>\n\n <div className=\"wjb-account-actions\">\n <button onClick={handleCopy} className=\"wjb-action-button\">\n {/* Copy Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n 复制地址\n </button>\n\n <button\n onClick={handleDisconnect}\n className=\"wjb-action-button wjb-text-red-500 wjb-hover:text-red-600\"\n >\n {/* Disconnect Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" />\n </svg>\n 断开连接\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { WalletModal } from \"./WalletModal\";\nimport { ChainSwitcher } from \"./ChainSwitcher\";\nimport { AccountModal } from \"./AccountModal\"; // Import new component\nimport { formatAddress, formatBalance } from \"../utils/format\";\n\nexport function ConnectButton() {\n const { state } = useWallet();\n const [showWalletModal, setShowWalletModal] = useState(false);\n const [showChainSwitcher, setShowChainSwitcher] = useState(false);\n const [showAccountModal, setShowAccountModal] = useState(false);\n\n if (!state.isConnected) {\n return (\n <>\n <button\n onClick={() => setShowWalletModal(true)}\n className=\"wjb-connect-button wjb-connect-button-primary\"\n >\n 连接钱包\n </button>\n {showWalletModal && (\n <WalletModal onClose={() => setShowWalletModal(false)} />\n )}\n </>\n );\n }\n\n return (\n <>\n <div className=\"wjb-wallet-connected\">\n <div className=\"wjb-wallet-info-group\">\n {/* Chain Switcher Trigger */}\n <button\n onClick={() => setShowChainSwitcher(true)}\n className=\"wjb-chain-button\"\n >\n {/* Simple Chain Icon Placeholder or check ChainID */}\n <div\n className={`wjb-w-5 wjb-h-5 wjb-rounded-full ${\n state.chainId === \"0x1\"\n ? \"wjb-bg-blue-500\"\n : state.chainId === \"0xaa36a7\"\n ? \"wjb-bg-purple-500\"\n : \"wjb-bg-gray-500\"\n } wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-[10px]`}\n >\n {state.chainId === \"0x1\"\n ? \"E\"\n : state.chainId === \"0xaa36a7\"\n ? \"S\"\n : \"?\"}\n </div>\n <span>\n {state.chainId === \"0x1\" && \"Ethereum\"}\n {state.chainId === \"0xaa36a7\" && \"Sepolia\"}\n {state.chainId &&\n state.chainId !== \"0x1\" &&\n state.chainId !== \"0xaa36a7\" &&\n \"Unknown\"}\n </span>\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"wjb-text-gray-400\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n\n {/* Balance Display */}\n <div className=\"wjb-balance\">\n {state.balance ? formatBalance(state.balance) : \"0 ETH\"}\n </div>\n\n {/* Account Button */}\n <button\n onClick={() => setShowAccountModal(true)}\n className=\"wjb-account-button\"\n >\n <span>{state.account && formatAddress(state.account)}</span>\n <div className=\"wjb-account-avatar\" />\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"wjb-text-gray-400 wjb-ml-1\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n {showChainSwitcher && (\n <ChainSwitcher onClose={() => setShowChainSwitcher(false)} />\n )}\n\n {showAccountModal && (\n <AccountModal onClose={() => setShowAccountModal(false)} />\n )}\n </>\n );\n}\n"],"names":["WalletContext","createContext","WalletError","Error","constructor","message","code","data","super","Object","defineProperty","this","name","ErrorCode","USER_REJECTED","UNAUTHORIZED","UNSUPPORTED_METHOD","DISCONNECTED","CHAIN_DISCONNECTED","UNRECOGNIZED_CHAIN","INVALID_PARAMS","INTERNAL_ERROR","PROVIDER_NOT_FOUND","WALLET_NOT_INSTALLED","ALREADY_CONNECTED","createWalletError","parseProviderError","error","err","BaseWallet","value","Map","accounts","emit","chainId","cleanup","connect","isInstalled","getInfo","provider","getProvider","setupEventListeners","request","method","length","disconnect","getAccounts","console","getBalance","address","params","getChainId","switchChain","chain","isUnrecognizedChainError","chainName","nativeCurrency","rpcUrls","blockExplorerUrls","iconUrls","addError","on","event","listener","eventListeners","has","set","Set","get","add","off","listeners","delete","args","handleAccountsChanged","handleChainChanged","handleDisconnect","removeListener","clear","forEach","MetaMaskWallet","id","downloadUrl","window","Boolean","ethereum","isMetaMask","OKXWallet","okxwallet","PhantomWallet","phantom","CoinbaseWallet","coinbaseWalletExtension","walletRegistry","getWalletById","find","wallet","mainnet","symbol","decimals","sepolia","defaultChains","STORAGE_KEY","useWallet","context","useContext","WalletModal","onClose","availableWallets","connecting","setConnecting","useState","setError","getWalletIcon","_jsx","className","children","onClick","e","target","currentTarget","_jsxs","map","async","walletId","handleConnect","disabled","filter","w","info","href","rel","ChainSwitcher","supportedChains","state","handleSwitch","formatBalance","rawBalance","hex","startsWith","wei","BigInt","divisor","integerPart","formattedDecimals","toString","padStart","slice","replace","formatAddress","AccountModal","account","balance","navigator","clipboard","writeText","width","height","viewBox","fill","stroke","strokeWidth","x","y","rx","ry","d","points","x1","y1","x2","y2","showWalletModal","setShowWalletModal","showChainSwitcher","setShowChainSwitcher","showAccountModal","setShowAccountModal","isConnected","_Fragment","strokeLinecap","strokeLinejoin","config","chains","autoConnect","setState","currentWallet","setCurrentWallet","useMemo","useCallback","prev","walletInfo","accountList","newAccount","newBalance","currentAccount","localStorage","setItem","JSON","stringify","removeItem","toLowerCase","getChainById","useEffect","stored","getItem","parse","retryCount","Promise","resolve","setTimeout","attemptAutoConnect","Provider"],"mappings":"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"}
@@ -1 +1 @@
1
- .wjb-connect-button{border-radius:.75rem;font-weight:700;padding:.625rem 1rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-connect-button:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-offset-width:2px;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);outline:2px solid transparent;outline-offset:2px}.wjb-connect-button{align-items:center;cursor:pointer;display:flex;gap:.5rem;justify-content:center}.wjb-connect-button-primary{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.wjb-connect-button-primary:hover{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.wjb-connect-button-primary{--tw-text-opacity:1;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);background:linear-gradient(90deg,#3b82f6,#2563eb);color:rgb(255 255 255/var(--tw-text-opacity,1))}.wjb-connect-button-primary,.wjb-connect-button-primary:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.wjb-connect-button-primary:hover{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-scale-x:1.02;--tw-scale-y:1.02}.wjb-connect-button-primary:active,.wjb-connect-button-primary:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.wjb-connect-button-primary:active{--tw-scale-x:0.98;--tw-scale-y:0.98}.wjb-connect-button-primary:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.wjb-wallet-connected{align-items:center;display:flex;gap:.75rem}.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-color:rgb(229 231 235/var(--tw-border-opacity,1));border-radius:.75rem;border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);display:flex;padding:.25rem}@media (prefers-color-scheme:dark){.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1));border-color:rgb(55 65 81/var(--tw-border-opacity,1))}}.wjb-chain-button{align-items:center;border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;padding:.375rem .75rem}.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-chain-button{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-chain-button{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}}.wjb-balance{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));display:none;font-size:.875rem;font-weight:500;line-height:1.25rem;padding-left:.75rem;padding-right:.75rem}@media (min-width:640px){.wjb-balance{display:block}}@media (prefers-color-scheme:dark){.wjb-balance{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}}.wjb-account-button{--tw-bg-opacity:1;align-items:center;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;margin-left:.25rem;padding:.375rem .75rem}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity,1))}}.wjb-account-button{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-avatar{--tw-shadow:inset 0 2px 4px 0 rgba(0,0,0,.05);--tw-shadow-colored:inset 0 2px 4px 0 var(--tw-shadow-color);background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:1.5rem;width:1.5rem}.wjb-modal-overlay{--tw-backdrop-blur:blur(2px);align-items:center;animation:fade-in .2s ease-out;backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);background-color:rgba(0,0,0,.4);display:flex;inset:0;justify-content:center;padding:1rem;position:fixed;z-index:50}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.wjb-modal-overlay{animation:fadeIn .2s ease-in-out}.wjb-wallet-modal-content{--tw-bg-opacity:1;--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (prefers-color-scheme:dark){.wjb-wallet-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-wallet-modal-content{display:flex;flex-direction:column;max-width:48rem;overflow:hidden;width:100%}@media (min-width:768px){.wjb-wallet-modal-content{flex-direction:row}}.wjb-wallet-modal-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-modal-left{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(243 244 246/var(--tw-border-opacity,1));padding:1.5rem;width:100%}@media (min-width:768px){.wjb-modal-left{border-bottom-width:0;border-right-width:1px;width:20rem}}@media (prefers-color-scheme:dark){.wjb-modal-left{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}}.wjb-modal-right{--tw-bg-opacity:1;align-items:center;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));display:flex;flex:1 1 0%;flex-direction:column;justify-content:center;padding:1.5rem;text-align:center}@media (prefers-color-scheme:dark){.wjb-modal-right{background-color:rgba(31,41,55,.5)}}.wjb-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:1rem}.wjb-modal-title{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.125rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-modal-title{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-wallet-list>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.wjb-wallet-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;gap:.75rem;padding:.75rem 1rem;width:100%}.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-wallet-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:700;text-align:left;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-wallet-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-switcher-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:.5rem;width:20rem}@media (prefers-color-scheme:dark){.wjb-chain-switcher-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-chain-switcher-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-chain-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;justify-content:space-between;padding:.75rem 1rem;width:100%}.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-chain-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-chain-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-option{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-chain-option.active{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1));color:rgb(59 130 246/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option.active{background-color:rgba(30,58,138,.1)}}.wjb-chain-icon{border-radius:9999px;height:1.5rem;margin-right:.75rem;width:1.5rem}.wjb-account-modal-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:2rem;text-align:center;width:20rem}@media (prefers-color-scheme:dark){.wjb-account-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-account-modal-content{align-items:center;animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out;display:flex;flex-direction:column;gap:1rem;position:relative}.wjb-account-modal-close{--tw-text-opacity:1;border-radius:9999px;color:rgb(156 163 175/var(--tw-text-opacity,1));cursor:pointer;padding:.5rem;position:absolute;right:1rem;top:1rem}.wjb-account-modal-close:hover{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));color:rgb(75 85 99/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-modal-close:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-account-avatar-large{background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;height:5rem;margin-bottom:.5rem;width:5rem}.wjb-account-address-large{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.25rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-account-address-large{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-account-actions{display:flex;gap:.75rem;margin-top:1rem;width:100%}.wjb-action-button{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;flex:1 1 0%;flex-direction:column;gap:.5rem;padding:.75rem}.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-action-button{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1));font-size:.75rem;font-weight:500;line-height:1rem}@media (prefers-color-scheme:dark){.wjb-action-button{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-action-button{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes scale-up{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.mb-2{margin-bottom:.5rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-12{height:3rem}.h-5{height:1.25rem}.h-8{height:2rem}.w-12{width:3rem}.w-5{width:1.25rem}.w-8{width:2rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.-rotate-12{--tw-rotate:-12deg}.-rotate-12,.-rotate-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-6{--tw-rotate:-6deg}.rotate-12{--tw-rotate:12deg}.rotate-12,.rotate-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-6{--tw-rotate:6deg}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-4{gap:1rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border-b{border-bottom-width:1px}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-orange-100{--tw-bg-opacity:1;background-color:rgb(255 237 213/var(--tw-bg-opacity,1))}.bg-orange-500{--tw-bg-opacity:1;background-color:rgb(249 115 22/var(--tw-bg-opacity,1))}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(243 232 255/var(--tw-bg-opacity,1))}.bg-purple-500{--tw-bg-opacity:1;background-color:rgb(168 85 247/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.text-left{text-align:left}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-purple-500{--tw-text-opacity:1;color:rgb(168 85 247/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.opacity-60{opacity:.6}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity,1))}.hover\:text-red-600:hover{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.hover\:opacity-100:hover{opacity:1}@media (min-width:768px){.md\:flex{display:flex}}@media (prefers-color-scheme:dark){.dark\:border-gray-800{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}.dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}
1
+ .wjb-connect-button{border-radius:.75rem;font-weight:700;padding:.625rem 1rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-connect-button:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-offset-width:2px;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);outline:2px solid transparent;outline-offset:2px}.wjb-connect-button{align-items:center;cursor:pointer;display:flex;gap:.5rem;justify-content:center}.wjb-connect-button-primary{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.wjb-connect-button-primary:hover{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.wjb-connect-button-primary{--tw-text-opacity:1;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);background:linear-gradient(90deg,#3b82f6,#2563eb);color:rgb(255 255 255/var(--tw-text-opacity,1))}.wjb-connect-button-primary,.wjb-connect-button-primary:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.wjb-connect-button-primary:hover{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-scale-x:1.02;--tw-scale-y:1.02}.wjb-connect-button-primary:active,.wjb-connect-button-primary:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.wjb-connect-button-primary:active{--tw-scale-x:0.98;--tw-scale-y:0.98}.wjb-connect-button-primary:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.wjb-wallet-connected{align-items:center;display:flex;gap:.75rem}.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-color:rgb(229 231 235/var(--tw-border-opacity,1));border-radius:.75rem;border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);display:flex;padding:.25rem}@media (prefers-color-scheme:dark){.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1));border-color:rgb(55 65 81/var(--tw-border-opacity,1))}}.wjb-chain-button{align-items:center;border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;padding:.375rem .75rem}.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-chain-button{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-chain-button{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}}.wjb-balance{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));display:none;font-size:.875rem;font-weight:500;line-height:1.25rem;padding-left:.75rem;padding-right:.75rem}@media (min-width:640px){.wjb-balance{display:block}}@media (prefers-color-scheme:dark){.wjb-balance{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}}.wjb-account-button{--tw-bg-opacity:1;align-items:center;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;margin-left:.25rem;padding:.375rem .75rem}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity,1))}}.wjb-account-button{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-avatar{--tw-shadow:inset 0 2px 4px 0 rgba(0,0,0,.05);--tw-shadow-colored:inset 0 2px 4px 0 var(--tw-shadow-color);background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:1.5rem;width:1.5rem}.wjb-modal-overlay{--tw-backdrop-blur:blur(2px);align-items:center;animation:fade-in .2s ease-out;backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);background-color:rgba(0,0,0,.4);display:flex;inset:0;justify-content:center;padding:1rem;position:fixed;z-index:50}.wjb-wallet-modal-content{--tw-bg-opacity:1;--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (prefers-color-scheme:dark){.wjb-wallet-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-wallet-modal-content{display:flex;flex-direction:column;max-width:48rem;overflow:hidden;width:100%}@media (min-width:768px){.wjb-wallet-modal-content{flex-direction:row}}.wjb-wallet-modal-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-modal-left{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(243 244 246/var(--tw-border-opacity,1));padding:1.5rem;width:100%}@media (min-width:768px){.wjb-modal-left{border-bottom-width:0;border-right-width:1px;width:20rem}}@media (prefers-color-scheme:dark){.wjb-modal-left{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}}.wjb-modal-right{--tw-bg-opacity:1;align-items:center;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));display:flex;flex:1 1 0%;flex-direction:column;justify-content:center;padding:1.5rem;text-align:center}@media (prefers-color-scheme:dark){.wjb-modal-right{background-color:rgba(31,41,55,.5)}}.wjb-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:1rem}.wjb-modal-title{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.125rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-modal-title{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-wallet-list>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.wjb-wallet-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;gap:.75rem;padding:.75rem 1rem;width:100%}.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-wallet-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:700;text-align:left;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-wallet-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-switcher-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:.5rem;width:20rem}@media (prefers-color-scheme:dark){.wjb-chain-switcher-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-chain-switcher-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-chain-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;justify-content:space-between;padding:.75rem 1rem;width:100%}.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-chain-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-chain-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-option{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-chain-option.active{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1));color:rgb(59 130 246/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option.active{background-color:rgba(30,58,138,.1)}}.wjb-chain-icon{border-radius:9999px;height:1.5rem;margin-right:.75rem;width:1.5rem}.wjb-chain-modal-close{--tw-text-opacity:1;border-radius:9999px;color:rgb(156 163 175/var(--tw-text-opacity,1));cursor:pointer;padding:.5rem}.wjb-chain-modal-close:hover{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));color:rgb(75 85 99/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-modal-close:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-account-modal-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:2rem;text-align:center;width:20rem}@media (prefers-color-scheme:dark){.wjb-account-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-account-modal-content{align-items:center;animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out;display:flex;flex-direction:column;gap:1rem;position:relative}.wjb-account-modal-close{--tw-text-opacity:1;border-radius:9999px;color:rgb(156 163 175/var(--tw-text-opacity,1));cursor:pointer;padding:.5rem;position:absolute;right:1rem;top:1rem}.wjb-account-modal-close:hover{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));color:rgb(75 85 99/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-modal-close:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-account-avatar-large{background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;height:5rem;margin-bottom:.5rem;width:5rem}.wjb-account-address-large{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.25rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-account-address-large{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-account-actions{display:flex;gap:.75rem;margin-top:1rem;width:100%}.wjb-action-button{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;flex:1 1 0%;flex-direction:column;gap:.5rem;padding:.75rem}.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-action-button{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1));font-size:.75rem;font-weight:500;line-height:1rem}@media (prefers-color-scheme:dark){.wjb-action-button{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-action-button{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes scale-up{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}
@@ -1 +1 @@
1
- {"version":3,"file":"ChainSwitcher.d.ts","sourceRoot":"","sources":["../../../src/components/ChainSwitcher.tsx"],"names":[],"mappings":"AAGA,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CAoD5D"}
1
+ {"version":3,"file":"ChainSwitcher.d.ts","sourceRoot":"","sources":["../../../src/components/ChainSwitcher.tsx"],"names":[],"mappings":"AAGA,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CA0D5D"}
@@ -1 +1 @@
1
- {"version":3,"file":"WalletModal.d.ts","sourceRoot":"","sources":["../../../src/components/WalletModal.tsx"],"names":[],"mappings":"AAIA,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAuJxD"}
1
+ {"version":3,"file":"WalletModal.d.ts","sourceRoot":"","sources":["../../../src/components/WalletModal.tsx"],"names":[],"mappings":"AAIA,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAyJxD"}
package/dist/esm/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import{createContext as a,useState as r,useMemo as i,useCallback as c,useEffect as l,useContext as o}from"react";const s=a(null);class d extends Error{constructor(e,t,n){super(e),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name="WalletError",this.code=t,this.data=n}}const h={USER_REJECTED:4001,UNAUTHORIZED:4100,UNSUPPORTED_METHOD:4200,DISCONNECTED:4900,CHAIN_DISCONNECTED:4901,UNRECOGNIZED_CHAIN:4902,INVALID_PARAMS:-32602,INTERNAL_ERROR:-32603,PROVIDER_NOT_FOUND:-32e3,WALLET_NOT_INSTALLED:-32001,ALREADY_CONNECTED:-32002};function u(e,t,n){return new d(e,t,n)}function w(e){if(e instanceof d)return e;if("object"==typeof e&&null!==e){const t=e;return u(t.message||"未知错误",t.code||h.INTERNAL_ERROR,t.data)}return u("string"==typeof e?e:"发生未知错误",h.INTERNAL_ERROR)}class m{constructor(){Object.defineProperty(this,"provider",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"eventListeners",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"handleAccountsChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("accountsChanged",e)}}),Object.defineProperty(this,"handleChainChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("chainChanged",e)}}),Object.defineProperty(this,"handleDisconnect",{enumerable:!0,configurable:!0,writable:!0,value:()=>{this.emit("disconnect",null),this.cleanup()}})}async connect(){if(!this.isInstalled())throw u(`${this.getInfo().name} 未安装`,h.WALLET_NOT_INSTALLED);const e=this.getProvider();if(!e)throw u("未找到提供者",h.PROVIDER_NOT_FOUND);this.provider=e,this.setupEventListeners();try{const e=await this.request({method:"eth_requestAccounts"});if(!e||0===e.length)throw u("未返回账户",h.UNAUTHORIZED);return e}catch(e){throw this.cleanup(),w(e)}}async disconnect(){this.cleanup()}async getAccounts(){if(!this.provider)return[];try{return await this.request({method:"eth_accounts"})||[]}catch(e){return console.error("获取账户失败:",e),[]}}async getBalance(e){if(!this.provider)return"0x0";try{return await this.request({method:"eth_getBalance",params:[e,"latest"]})}catch(e){return console.error("获取余额失败:",e),"0x0"}}async getChainId(){if(!this.provider)throw u("提供者未连接",h.DISCONNECTED);try{return await this.request({method:"eth_chainId"})}catch(e){throw w(e)}}async switchChain(e){if(!this.provider)throw u("提供者未连接",h.DISCONNECTED);try{await this.request({method:"wallet_switchEthereumChain",params:[{chainId:e.chainId}]})}catch(t){if(!this.isUnrecognizedChainError(t))throw w(t);try{await this.request({method:"wallet_addEthereumChain",params:[{chainId:e.chainId,chainName:e.chainName,nativeCurrency:e.nativeCurrency,rpcUrls:e.rpcUrls,blockExplorerUrls:e.blockExplorerUrls,iconUrls:e.iconUrls}]})}catch(e){throw w(e)}}}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){const n=this.eventListeners.get(e);n&&n.delete(t)}async request(e){if(!this.provider)throw u("提供者未连接",h.DISCONNECTED);try{return await this.provider.request(e)}catch(e){throw w(e)}}setupEventListeners(){this.provider&&(this.provider.on("accountsChanged",this.handleAccountsChanged),this.provider.on("chainChanged",this.handleChainChanged),this.provider.on("disconnect",this.handleDisconnect))}cleanup(){this.provider&&(this.provider.removeListener("accountsChanged",this.handleAccountsChanged),this.provider.removeListener("chainChanged",this.handleChainChanged),this.provider.removeListener("disconnect",this.handleDisconnect)),this.provider=null,this.eventListeners.clear()}emit(e,t){const n=this.eventListeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`${e} 监听器错误:`,t)}})}isUnrecognizedChainError(e){return"object"==typeof e&&null!==e&&"code"in e&&e.code===h.UNRECOGNIZED_CHAIN}}class b extends m{getInfo(){return{id:"metamask",name:"MetaMask",downloadUrl:"https://metamask.io/download/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.ethereum?.isMetaMask)}getProvider(){return"undefined"==typeof window?null:window.ethereum?.isMetaMask?window.ethereum:null}}class p extends m{getInfo(){return{id:"okx",name:"OKX Wallet",downloadUrl:"https://www.okx.com/web3"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.okxwallet)}getProvider(){return"undefined"==typeof window?null:window.okxwallet||null}}class g extends m{getInfo(){return{id:"phantom",name:"Phantom",downloadUrl:"https://phantom.app/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.phantom?.ethereum)}getProvider(){return"undefined"==typeof window?null:window.phantom?.ethereum||null}}class f extends m{getInfo(){return{id:"coinbase",name:"Coinbase Wallet",downloadUrl:"https://www.coinbase.com/wallet"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.coinbaseWalletExtension)}getProvider(){return"undefined"==typeof window?null:window.coinbaseWalletExtension||null}}const N=[new b,new p,new g,new f];function v(e){return N.find(t=>t.getInfo().id===e)}const x={chainId:"0x1",chainName:"Ethereum Mainnet",nativeCurrency:{name:"Ether",symbol:"ETH",decimals:18},rpcUrls:["https://eth.llamarpc.com"],blockExplorerUrls:["https://etherscan.io"]},y={chainId:"0xaa36a7",chainName:"Sepolia",nativeCurrency:{name:"Sepolia Ether",symbol:"ETH",decimals:18},rpcUrls:["https://rpc.sepolia.org"],blockExplorerUrls:["https://sepolia.etherscan.io"]},C=[x,y];const I="wjb_wallet_connect";function E({children:t,config:n}){const{chains:a=C,autoConnect:o=!0}=n,[d,w]=r({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),[m,b]=r(null),p=i(()=>N.filter(e=>e.isInstalled()).map(e=>e.getInfo()),[]);c(async(e,t)=>{try{const n=await e.getBalance(t);w(e=>({...e,balance:n}))}catch(e){console.error("更新余额失败:",e)}},[]);const g=c(async e=>{try{if(d.isConnected&&d.wallet?.id===e)throw u("钱包已连接",h.ALREADY_CONNECTED);m&&await m.disconnect();const t=v(e);if(!t)throw u(`未找到钱包 ${e}`,h.PROVIDER_NOT_FOUND);const n=await t.connect(),a=await t.getChainId(),r=await t.getBalance(n[0]),i=t.getInfo();t.on("accountsChanged",async e=>{const n=e;if(0===n.length)f();else{const e=n[0],a=await t.getBalance(e);w(t=>({...t,account:e,balance:a}))}}),t.on("chainChanged",async e=>{const n=(await t.getAccounts())[0];let a="0x0";n&&(a=await t.getBalance(n)),w(t=>({...t,chainId:e,balance:a}))}),t.on("disconnect",()=>{f()}),b(t),w({isConnected:!0,account:n[0],chainId:a,balance:r,wallet:i}),"undefined"!=typeof window&&localStorage.setItem(I,JSON.stringify({walletId:e,account:n[0]}))}catch(e){throw console.error("连接钱包失败:",e),e}},[d.isConnected,d.wallet,m]),f=c(async()=>{m&&await m.disconnect(),b(null),w({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),"undefined"!=typeof window&&localStorage.removeItem(I)},[m]),x=c(async e=>{if(!m)throw u("未连接钱包",h.DISCONNECTED);const t=function(e,t){return t.find(t=>t.chainId.toLowerCase()===e.toLowerCase())}(e,a);if(!t)throw u(`不支持链 ${e}`,h.UNRECOGNIZED_CHAIN);await m.switchChain(t)},[m,a]);l(()=>{if(!o)return;(async()=>{if("undefined"==typeof window)return;const e=localStorage.getItem(I);if(e)try{const{walletId:t}=JSON.parse(e),n=v(t);if(!n)return void localStorage.removeItem(I);let a=0;for(;!n.isInstalled()&&a<10;)await new Promise(e=>setTimeout(e,100)),a++;if(!n.isInstalled())return void localStorage.removeItem(I);await g(t)}catch(e){console.error("自动连接失败:",e),localStorage.removeItem(I)}})()},[o]);const y=i(()=>({state:d,connect:g,disconnect:f,switchChain:x,availableWallets:p,supportedChains:a}),[d,g,f,x,p,a]);return e(s.Provider,{value:y,children:t})}function j(){const e=o(s);if(!e)throw new Error("useWallet 必须在 WalletProvider 中使用");return e}function k({onClose:n}){const{connect:a,availableWallets:i}=j(),[c,l]=r(!1),[o,s]=r(null),d=t=>e("div","metamask"===t?{className:"w-8 h-8 rounded-lg bg-orange-100 flex items-center justify-center text-orange-500",children:"🦊"}:"okx"===t?{className:"w-8 h-8 rounded-lg bg-black flex items-center justify-center text-white",children:"X"}:"phantom"===t?{className:"w-8 h-8 rounded-lg bg-purple-100 flex items-center justify-center text-purple-500",children:"P"}:"coinbase"===t?{className:"w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center text-blue-500",children:"C"}:{className:"w-8 h-8 rounded-lg bg-gray-200"});return e("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:t("div",{className:"wjb-wallet-modal-content",children:[t("div",{className:"wjb-modal-left",children:[e("div",{className:"wjb-modal-header",children:e("h2",{className:"wjb-modal-title",children:"连接钱包"})}),t("div",{className:"wjb-wallet-list",children:[i.map(r=>t("button",{onClick:()=>(async e=>{l(!0),s(null);try{await a(e),n()}catch(e){s(e instanceof Error?e.message:"连接失败")}finally{l(!1)}})(r.id),disabled:c,className:"wjb-wallet-option",children:[d(r.id),e("span",{className:"flex-1",children:r.name}),c&&e("span",{className:"text-xs text-blue-500 animate-pulse",children:"连接中..."})]},r.id)),N.filter(e=>!e.isInstalled()).map(n=>{const a=n.getInfo();return t("a",{href:a.downloadUrl,target:"_blank",rel:"noopener noreferrer",className:"wjb-wallet-option opacity-60 hover:opacity-100",children:[d(a.id),e("span",{className:"flex-1",children:a.name}),e("span",{className:"text-xs font-bold text-blue-500 bg-blue-50 px-2 py-1 rounded",children:"安装"})]},a.id)})]}),o&&e("div",{className:"mt-4 p-3 bg-red-50 text-red-500 text-sm rounded-xl",children:o})]}),t("div",{className:"wjb-modal-right hidden md:flex",children:[t("div",{className:"grid grid-cols-2 gap-4 mb-6 opacity-80",children:[e("div",{className:"w-12 h-12 bg-blue-500 rounded-xl shadow-lg -rotate-6"}),e("div",{className:"w-12 h-12 bg-purple-500 rounded-xl shadow-lg rotate-12"}),e("div",{className:"w-12 h-12 bg-orange-500 rounded-xl shadow-lg rotate-6"}),e("div",{className:"w-12 h-12 bg-green-500 rounded-xl shadow-lg -rotate-12"})]}),e("h3",{className:"text-lg font-bold text-gray-900 dark:text-white mb-2",children:"什么是钱包?"}),t("ul",{className:"text-sm text-gray-500 dark:text-gray-400 space-y-3 text-left max-w-xs",children:[t("li",{className:"flex items-start gap-2",children:[e("span",{className:"mt-1",children:"🏠"}),t("span",{children:["您的数字资产之家",e("br",{}),"发送、接收和存储资产。"]})]}),t("li",{className:"flex items-start gap-2",children:[e("span",{className:"mt-1",children:"🔐"}),t("span",{children:["一种新的登录方式",e("br",{}),"无需创建账户和密码。"]})]})]}),e("button",{className:"mt-6 px-4 py-2 bg-gray-200 dark:bg-gray-700 rounded-lg text-sm font-bold text-gray-700 dark:text-white hover:bg-gray-300 transition-colors",children:"了解更多"})]})]})})}function O({onClose:n}){const{supportedChains:a,switchChain:r,state:i}=j();return e("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:t("div",{className:"wjb-chain-switcher-content",children:[t("div",{className:"p-4 border-b border-gray-100 dark:border-gray-800 flex justify-between items-center",children:[e("h3",{className:"font-bold text-gray-900 dark:text-white",children:"切换网络"}),e("button",{onClick:n,className:"wjb-account-modal-close",children:"✕"})]}),e("div",{className:"p-2 space-y-1",children:a.map(a=>t("button",{onClick:()=>(async e=>{i.chainId!==e&&await r(e),n()})(a.chainId),className:"wjb-chain-option "+(i.chainId===a.chainId?"active":""),children:[t("div",{className:"flex items-center",children:[e("div",{className:"wjb-chain-icon flex items-center justify-center text-white text-xs "+("0x1"===a.chainId?"bg-blue-500":"bg-purple-500"),children:a.chainName[0]}),e("span",{children:a.chainName})]}),i.chainId===a.chainId&&e("span",{className:"text-sm font-bold text-green-500",children:"已连接"})]},a.chainId))})]})})}function T(e){if(!e||"0x0"===e)return"0 ETH";try{const t=e.startsWith("0x")?e:`0x${e}`,n=BigInt(t),a=1000000000000000000n,r=n/a,i=(n%a).toString().padStart(18,"0").slice(0,4).replace(/0+$/,"");return i?`${r}.${i} ETH`:`${r} ETH`}catch(e){return console.error("Error formatting balance:",e),"0 ETH"}}function D(e){return e?`${e.slice(0,6)}...${e.slice(-4)}`:""}function L({onClose:n}){const{state:a,disconnect:r}=j(),{account:i,balance:c}=a;return e("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:t("div",{className:"wjb-account-modal-content",children:[e("button",{onClick:n,className:"wjb-account-modal-close",children:"✕"}),e("div",{className:"wjb-account-avatar-large"}),e("div",{className:"wjb-account-address-large",children:D(i)}),e("div",{className:"wjb-account-balance-large",children:a.balance||"0 ETH"}),t("div",{className:"wjb-account-actions",children:[t("button",{onClick:async()=>{i&&await navigator.clipboard.writeText(i)},className:"wjb-action-button",children:[t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),e("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]}),"复制地址"]}),t("button",{onClick:async()=>{await r(),n()},className:"wjb-action-button text-red-500 hover:text-red-600",children:[t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e("path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"}),e("polyline",{points:"16 17 21 12 16 7"}),e("line",{x1:"21",y1:"12",x2:"9",y2:"12"})]}),"断开连接"]})]})]})})}function U(){const{state:a}=j(),[i,c]=r(!1),[l,o]=r(!1),[s,d]=r(!1);return a.isConnected?t(n,{children:[e("div",{className:"wjb-wallet-connected",children:t("div",{className:"wjb-wallet-info-group",children:[t("button",{onClick:()=>o(!0),className:"wjb-chain-button",children:[e("div",{className:`w-5 h-5 rounded-full ${"0x1"===a.chainId?"bg-blue-500":"0xaa36a7"===a.chainId?"bg-purple-500":"bg-gray-500"} flex items-center justify-center text-white text-[10px]`,children:"0x1"===a.chainId?"E":"0xaa36a7"===a.chainId?"S":"?"}),t("span",{children:["0x1"===a.chainId&&"Ethereum","0xaa36a7"===a.chainId&&"Sepolia",a.chainId&&"0x1"!==a.chainId&&"0xaa36a7"!==a.chainId&&"Unknown"]}),e("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"text-gray-400",children:e("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),e("div",{className:"wjb-balance",children:a.balance?T(a.balance):"0 ETH"}),t("button",{onClick:()=>d(!0),className:"wjb-account-button",children:[e("span",{children:a.account&&D(a.account)}),e("div",{className:"wjb-account-avatar"}),e("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"text-gray-400 ml-1",children:e("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})]})}),l&&e(O,{onClose:()=>o(!1)}),s&&e(L,{onClose:()=>d(!1)})]}):t(n,{children:[e("button",{onClick:()=>c(!0),className:"wjb-connect-button wjb-connect-button-primary",children:"连接钱包"}),i&&e(k,{onClose:()=>c(!1)})]})}export{m as BaseWallet,f as CoinbaseWallet,U as ConnectButton,h as ErrorCode,b as MetaMaskWallet,p as OKXWallet,g as PhantomWallet,E as WalletProvider,C as defaultChains,x as mainnet,y as sepolia,j as useWallet};
1
+ import{jsx as e,jsxs as t,Fragment as n}from"react/jsx-runtime";import{createContext as a,useState as r,useMemo as i,useCallback as c,useEffect as l,useContext as o}from"react";const s=a(null);class d extends Error{constructor(e,t,n){super(e),Object.defineProperty(this,"code",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,"data",{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.name="WalletError",this.code=t,this.data=n}}const w={USER_REJECTED:4001,UNAUTHORIZED:4100,UNSUPPORTED_METHOD:4200,DISCONNECTED:4900,CHAIN_DISCONNECTED:4901,UNRECOGNIZED_CHAIN:4902,INVALID_PARAMS:-32602,INTERNAL_ERROR:-32603,PROVIDER_NOT_FOUND:-32e3,WALLET_NOT_INSTALLED:-32001,ALREADY_CONNECTED:-32002};function h(e,t,n){return new d(e,t,n)}function b(e){if(e instanceof d)return e;if("object"==typeof e&&null!==e){const t=e;return h(t.message||"未知错误",t.code||w.INTERNAL_ERROR,t.data)}return h("string"==typeof e?e:"发生未知错误",w.INTERNAL_ERROR)}class u{constructor(){Object.defineProperty(this,"provider",{enumerable:!0,configurable:!0,writable:!0,value:null}),Object.defineProperty(this,"eventListeners",{enumerable:!0,configurable:!0,writable:!0,value:new Map}),Object.defineProperty(this,"handleAccountsChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("accountsChanged",e)}}),Object.defineProperty(this,"handleChainChanged",{enumerable:!0,configurable:!0,writable:!0,value:e=>{this.emit("chainChanged",e)}}),Object.defineProperty(this,"handleDisconnect",{enumerable:!0,configurable:!0,writable:!0,value:()=>{this.emit("disconnect",null),this.cleanup()}})}async connect(){if(!this.isInstalled())throw h(`${this.getInfo().name} 未安装`,w.WALLET_NOT_INSTALLED);const e=this.getProvider();if(!e)throw h("未找到提供者",w.PROVIDER_NOT_FOUND);this.provider=e,this.setupEventListeners();try{const e=await this.request({method:"eth_requestAccounts"});if(!e||0===e.length)throw h("未返回账户",w.UNAUTHORIZED);return e}catch(e){throw this.cleanup(),b(e)}}async disconnect(){this.cleanup()}async getAccounts(){if(!this.provider)return[];try{return await this.request({method:"eth_accounts"})||[]}catch(e){return console.error("获取账户失败:",e),[]}}async getBalance(e){if(!this.provider)return"0x0";try{return await this.request({method:"eth_getBalance",params:[e,"latest"]})}catch(e){return console.error("获取余额失败:",e),"0x0"}}async getChainId(){if(!this.provider)throw h("提供者未连接",w.DISCONNECTED);try{return await this.request({method:"eth_chainId"})}catch(e){throw b(e)}}async switchChain(e){if(!this.provider)throw h("提供者未连接",w.DISCONNECTED);try{await this.request({method:"wallet_switchEthereumChain",params:[{chainId:e.chainId}]})}catch(t){if(!this.isUnrecognizedChainError(t))throw b(t);try{await this.request({method:"wallet_addEthereumChain",params:[{chainId:e.chainId,chainName:e.chainName,nativeCurrency:e.nativeCurrency,rpcUrls:e.rpcUrls,blockExplorerUrls:e.blockExplorerUrls,iconUrls:e.iconUrls}]})}catch(e){throw b(e)}}}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){const n=this.eventListeners.get(e);n&&n.delete(t)}async request(e){if(!this.provider)throw h("提供者未连接",w.DISCONNECTED);try{return await this.provider.request(e)}catch(e){throw b(e)}}setupEventListeners(){this.provider&&(this.provider.on("accountsChanged",this.handleAccountsChanged),this.provider.on("chainChanged",this.handleChainChanged),this.provider.on("disconnect",this.handleDisconnect))}cleanup(){this.provider&&(this.provider.removeListener("accountsChanged",this.handleAccountsChanged),this.provider.removeListener("chainChanged",this.handleChainChanged),this.provider.removeListener("disconnect",this.handleDisconnect)),this.provider=null,this.eventListeners.clear()}emit(e,t){const n=this.eventListeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`${e} 监听器错误:`,t)}})}isUnrecognizedChainError(e){return"object"==typeof e&&null!==e&&"code"in e&&e.code===w.UNRECOGNIZED_CHAIN}}class j extends u{getInfo(){return{id:"metamask",name:"MetaMask",downloadUrl:"https://metamask.io/download/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.ethereum?.isMetaMask)}getProvider(){return"undefined"==typeof window?null:window.ethereum?.isMetaMask?window.ethereum:null}}class m extends u{getInfo(){return{id:"okx",name:"OKX Wallet",downloadUrl:"https://www.okx.com/web3"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.okxwallet)}getProvider(){return"undefined"==typeof window?null:window.okxwallet||null}}class p extends u{getInfo(){return{id:"phantom",name:"Phantom",downloadUrl:"https://phantom.app/"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.phantom?.ethereum)}getProvider(){return"undefined"==typeof window?null:window.phantom?.ethereum||null}}class g extends u{getInfo(){return{id:"coinbase",name:"Coinbase Wallet",downloadUrl:"https://www.coinbase.com/wallet"}}isInstalled(){return"undefined"!=typeof window&&Boolean(window.coinbaseWalletExtension)}getProvider(){return"undefined"==typeof window?null:window.coinbaseWalletExtension||null}}const f=[new j,new m,new p,new g];function N(e){return f.find(t=>t.getInfo().id===e)}const v={chainId:"0x1",chainName:"Ethereum Mainnet",nativeCurrency:{name:"Ether",symbol:"ETH",decimals:18},rpcUrls:["https://eth.llamarpc.com"],blockExplorerUrls:["https://etherscan.io"]},x={chainId:"0xaa36a7",chainName:"Sepolia",nativeCurrency:{name:"Sepolia Ether",symbol:"ETH",decimals:18},rpcUrls:["https://rpc.sepolia.org"],blockExplorerUrls:["https://sepolia.etherscan.io"]},y=[v,x];const C="wjb_wallet_connect";function I({children:t,config:n}){const{chains:a=y,autoConnect:o=!0}=n,[d,b]=r({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),[u,j]=r(null),m=i(()=>f.filter(e=>e.isInstalled()).map(e=>e.getInfo()),[]);c(async(e,t)=>{try{const n=await e.getBalance(t);b(e=>({...e,balance:n}))}catch(e){console.error("更新余额失败:",e)}},[]);const p=c(async e=>{try{if(d.isConnected&&d.wallet?.id===e)throw h("钱包已连接",w.ALREADY_CONNECTED);u&&await u.disconnect();const t=N(e);if(!t)throw h(`未找到钱包 ${e}`,w.PROVIDER_NOT_FOUND);const n=await t.connect(),a=await t.getChainId(),r=await t.getBalance(n[0]),i=t.getInfo();t.on("accountsChanged",async e=>{const n=e;if(0===n.length)g();else{const e=n[0],a=await t.getBalance(e);b(t=>({...t,account:e,balance:a}))}}),t.on("chainChanged",async e=>{const n=(await t.getAccounts())[0];let a="0x0";n&&(a=await t.getBalance(n)),b(t=>({...t,chainId:e,balance:a}))}),t.on("disconnect",()=>{g()}),j(t),b({isConnected:!0,account:n[0],chainId:a,balance:r,wallet:i}),"undefined"!=typeof window&&localStorage.setItem(C,JSON.stringify({walletId:e,account:n[0]}))}catch(e){throw console.error("连接钱包失败:",e),e}},[d.isConnected,d.wallet,u]),g=c(async()=>{u&&await u.disconnect(),j(null),b({isConnected:!1,account:null,chainId:null,balance:null,wallet:null}),"undefined"!=typeof window&&localStorage.removeItem(C)},[u]),v=c(async e=>{if(!u)throw h("未连接钱包",w.DISCONNECTED);const t=function(e,t){return t.find(t=>t.chainId.toLowerCase()===e.toLowerCase())}(e,a);if(!t)throw h(`不支持链 ${e}`,w.UNRECOGNIZED_CHAIN);await u.switchChain(t)},[u,a]);l(()=>{if(!o)return;(async()=>{if("undefined"==typeof window)return;const e=localStorage.getItem(C);if(e)try{const{walletId:t}=JSON.parse(e),n=N(t);if(!n)return void localStorage.removeItem(C);let a=0;for(;!n.isInstalled()&&a<10;)await new Promise(e=>setTimeout(e,100)),a++;if(!n.isInstalled())return void localStorage.removeItem(C);await p(t)}catch(e){console.error("自动连接失败:",e),localStorage.removeItem(C)}})()},[o]);const x=i(()=>({state:d,connect:p,disconnect:g,switchChain:v,availableWallets:m,supportedChains:a}),[d,p,g,v,m,a]);return e(s.Provider,{value:x,children:t})}function E(){const e=o(s);if(!e)throw new Error("useWallet 必须在 WalletProvider 中使用");return e}function k({onClose:n}){const{connect:a,availableWallets:i}=E(),[c,l]=r(!1),[o,s]=r(null),d=t=>e("div","metamask"===t?{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-orange-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-orange-500",children:"🦊"}:"okx"===t?{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-black wjb-flex wjb-items-center wjb-justify-center wjb-text-white",children:"X"}:"phantom"===t?{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-purple-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-purple-500",children:"P"}:"coinbase"===t?{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-blue-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-blue-500",children:"C"}:{className:"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-gray-200"});return e("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:t("div",{className:"wjb-wallet-modal-content",children:[t("div",{className:"wjb-modal-left",children:[e("div",{className:"wjb-modal-header",children:e("h2",{className:"wjb-modal-title",children:"连接钱包"})}),t("div",{className:"wjb-wallet-list",children:[i.map(r=>t("button",{onClick:()=>(async e=>{l(!0),s(null);try{await a(e),n()}catch(e){s(e instanceof Error?e.message:"连接失败")}finally{l(!1)}})(r.id),disabled:c,className:"wjb-wallet-option",children:[d(r.id),e("span",{className:"wjb-flex-1",children:r.name}),c&&e("span",{className:"wjb-text-xs wjb-text-blue-500 wjb-animate-pulse",children:"连接中..."})]},r.id)),f.filter(e=>!e.isInstalled()).map(n=>{const a=n.getInfo();return t("a",{href:a.downloadUrl,target:"_blank",rel:"noopener noreferrer",className:"wjb-wallet-option wjb-opacity-60 wjb-hover:opacity-100",children:[d(a.id),e("span",{className:"wjb-flex-1",children:a.name}),e("span",{className:"wjb-text-xs wjb-font-bold wjb-text-blue-500 wjb-bg-blue-50 wjb-px-2 wjb-py-1 wjb-rounded",children:"安装"})]},a.id)})]}),o&&e("div",{className:"wjb-mt-4 wjb-p-3 wjb-bg-red-50 wjb-text-red-500 wjb-text-sm wjb-rounded-xl",children:o})]}),t("div",{className:"wjb-modal-right hidden md:flex",children:[t("div",{className:"wjb-grid wjb-grid-cols-2 wjb-gap-4 wjb-mb-6 wjb-opacity-80",children:[e("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-blue-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-6"}),e("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-purple-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-12"}),e("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-orange-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-6"}),e("div",{className:"wjb-w-12 wjb-h-12 wjb-bg-green-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-12"})]}),e("h3",{className:"wjb-text-lg wjb-font-bold wjb-text-gray-900 wjb-dark:text-white wjb-mb-2",children:"什么是钱包?"}),t("ul",{className:"wjb-text-sm wjb-text-gray-500 wjb-dark:text-gray-400 wjb-space-y-3 wjb-text-left wjb-max-w-xs",children:[t("li",{className:"wjb-flex wjb-items-start wjb-gap-2",children:[e("span",{className:"wjb-mt-1",children:"🏠"}),t("span",{children:["您的数字资产之家",e("br",{}),"发送、接收和存储资产。"]})]}),t("li",{className:"wjb-flex wjb-items-start wjb-gap-2",children:[e("span",{className:"wjb-mt-1",children:"🔐"}),t("span",{children:["一种新的登录方式",e("br",{}),"无需创建账户和密码。"]})]})]}),e("button",{className:"wjb-mt-6 wjb-px-4 wjb-py-2 wjb-bg-gray-200 wjb-dark:bg-gray-700 wjb-rounded-lg wjb-text-sm wjb-font-bold wjb-text-gray-700 wjb-dark:text-white wjb-hover:bg-gray-300 wjb-transition-colors",children:"了解更多"})]})]})})}function O({onClose:n}){const{supportedChains:a,switchChain:r,state:i}=E();return e("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:t("div",{className:"wjb-chain-switcher-content",children:[t("div",{className:"wjb-p-4 wjb-border-b wjb-border-gray-100 wjb-dark:border-gray-800 wjb-flex wjb-justify-between wjb-items-center",children:[e("h3",{className:"wjb-font-bold wjb-text-gray-900 wjb-dark:text-white",children:"切换网络"}),e("button",{onClick:n,className:"wjb-chain-modal-close",children:"✕"})]}),e("div",{className:"wjb-p-2 wjb-space-y-1",children:a.map(a=>t("button",{onClick:()=>(async e=>{i.chainId!==e&&await r(e),n()})(a.chainId),className:"wjb-chain-option "+(i.chainId===a.chainId?"active":""),children:[t("div",{className:"wjb-flex wjb-items-center",children:[e("div",{className:"wjb-chain-icon wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-xs "+("0x1"===a.chainId?"wjb-bg-blue-500":"wjb-bg-purple-500"),children:a.chainName[0]}),e("span",{children:a.chainName})]}),i.chainId===a.chainId&&e("span",{className:"wjb-text-sm wjb-font-bold wjb-text-green-500",children:"已连接"})]},a.chainId))})]})})}function T(e){if(!e||"0x0"===e)return"0 ETH";try{const t=e.startsWith("0x")?e:`0x${e}`,n=BigInt(t),a=1000000000000000000n,r=n/a,i=(n%a).toString().padStart(18,"0").slice(0,4).replace(/0+$/,"");return i?`${r}.${i} ETH`:`${r} ETH`}catch(e){return console.error("Error formatting balance:",e),"0 ETH"}}function D(e){return e?`${e.slice(0,6)}...${e.slice(-4)}`:""}function L({onClose:n}){const{state:a,disconnect:r}=E(),{account:i,balance:c}=a;return e("div",{className:"wjb-modal-overlay",onClick:e=>{e.target===e.currentTarget&&n()},children:t("div",{className:"wjb-account-modal-content",children:[e("button",{onClick:n,className:"wjb-account-modal-close",children:"✕"}),e("div",{className:"wjb-account-avatar-large"}),e("div",{className:"wjb-account-address-large",children:D(i)}),e("div",{className:"wjb-account-balance-large",children:a.balance||"0 ETH"}),t("div",{className:"wjb-account-actions",children:[t("button",{onClick:async()=>{i&&await navigator.clipboard.writeText(i)},className:"wjb-action-button",children:[t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e("rect",{x:"9",y:"9",width:"13",height:"13",rx:"2",ry:"2"}),e("path",{d:"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"})]}),"复制地址"]}),t("button",{onClick:async()=>{await r(),n()},className:"wjb-action-button wjb-text-red-500 wjb-hover:text-red-600",children:[t("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:[e("path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"}),e("polyline",{points:"16 17 21 12 16 7"}),e("line",{x1:"21",y1:"12",x2:"9",y2:"12"})]}),"断开连接"]})]})]})})}function U(){const{state:a}=E(),[i,c]=r(!1),[l,o]=r(!1),[s,d]=r(!1);return a.isConnected?t(n,{children:[e("div",{className:"wjb-wallet-connected",children:t("div",{className:"wjb-wallet-info-group",children:[t("button",{onClick:()=>o(!0),className:"wjb-chain-button",children:[e("div",{className:`wjb-w-5 wjb-h-5 wjb-rounded-full ${"0x1"===a.chainId?"wjb-bg-blue-500":"0xaa36a7"===a.chainId?"wjb-bg-purple-500":"wjb-bg-gray-500"} wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-[10px]`,children:"0x1"===a.chainId?"E":"0xaa36a7"===a.chainId?"S":"?"}),t("span",{children:["0x1"===a.chainId&&"Ethereum","0xaa36a7"===a.chainId&&"Sepolia",a.chainId&&"0x1"!==a.chainId&&"0xaa36a7"!==a.chainId&&"Unknown"]}),e("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"wjb-text-gray-400",children:e("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]}),e("div",{className:"wjb-balance",children:a.balance?T(a.balance):"0 ETH"}),t("button",{onClick:()=>d(!0),className:"wjb-account-button",children:[e("span",{children:a.account&&D(a.account)}),e("div",{className:"wjb-account-avatar"}),e("svg",{width:"12",height:"12",viewBox:"0 0 12 12",fill:"none",className:"wjb-text-gray-400 wjb-ml-1",children:e("path",{d:"M2.5 4.5L6 8L9.5 4.5",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})]})]})}),l&&e(O,{onClose:()=>o(!1)}),s&&e(L,{onClose:()=>d(!1)})]}):t(n,{children:[e("button",{onClick:()=>c(!0),className:"wjb-connect-button wjb-connect-button-primary",children:"连接钱包"}),i&&e(k,{onClose:()=>c(!1)})]})}export{u as BaseWallet,g as CoinbaseWallet,U as ConnectButton,w as ErrorCode,j as MetaMaskWallet,m as OKXWallet,p as PhantomWallet,I as WalletProvider,y as defaultChains,v as mainnet,x as sepolia,E as useWallet};
2
2
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/context/WalletContext.tsx","../../src/types/wallet.ts","../../src/utils/errors.ts","../../src/wallets/BaseWallet.ts","../../src/wallets/MetaMaskWallet.ts","../../src/wallets/OKXWallet.ts","../../src/wallets/PhantomWallet.ts","../../src/wallets/CoinbaseWallet.ts","../../src/wallets/index.ts","../../src/utils/chains.ts","../../src/components/WalletProvider.tsx","../../src/hooks/useWallet.ts","../../src/components/WalletModal.tsx","../../src/components/ChainSwitcher.tsx","../../src/utils/format.ts","../../src/components/AccountModal.tsx","../../src/components/ConnectButton.tsx"],"sourcesContent":["import { createContext } from \"react\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 钱包上下文\n */\nexport const WalletContext = createContext<WalletContextValue | null>(null);\n","/**\n * 基于 EIP-1193 的以太坊提供者接口\n */\nexport interface EthereumProvider {\n request(args: RequestArguments): Promise<unknown>;\n on(event: string, listener: (...args: unknown[]) => void): void;\n removeListener(event: string, listener: (...args: unknown[]) => void): void;\n isMetaMask?: boolean;\n isOkxWallet?: boolean;\n isCoinbaseWallet?: boolean;\n isPhantom?: boolean;\n}\n\n/**\n * JSON-RPC 调用请求参数\n */\nexport interface RequestArguments {\n method: string;\n params?: unknown[] | Record<string, unknown>;\n}\n\n/**\n * 链配置\n */\nexport interface Chain {\n chainId: string; // 十六进制字符串,例如 \"0x1\"\n chainName: string;\n nativeCurrency: {\n name: string;\n symbol: string;\n decimals: number;\n };\n rpcUrls: string[];\n blockExplorerUrls?: string[];\n iconUrls?: string[];\n}\n\n/**\n * 钱包信息\n */\nexport interface WalletInfo {\n id: string;\n name: string;\n icon?: string;\n downloadUrl?: string;\n}\n\n/**\n * 钱包连接状态\n */\nexport interface WalletState {\n isConnected: boolean;\n account: string | null;\n chainId: string | null;\n balance: string | null;\n wallet: WalletInfo | null;\n}\n\n/**\n * 钱包事件类型\n */\nexport type WalletEventType =\n | \"accountsChanged\"\n | \"chainChanged\"\n | \"connect\"\n | \"disconnect\";\n\n/**\n * 事件监听器类型\n */\nexport type WalletEventListener = (data: unknown) => void;\n\n/**\n * 钱包错误类型\n */\nexport class WalletError extends Error {\n code: number;\n data?: unknown;\n\n constructor(message: string, code: number, data?: unknown) {\n super(message);\n this.name = \"WalletError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/**\n * 钱包提供者上下文值\n */\nexport interface WalletContextValue {\n state: WalletState;\n connect: (walletId: string) => Promise<void>;\n disconnect: () => Promise<void>;\n switchChain: (chainId: string) => Promise<void>;\n availableWallets: WalletInfo[];\n supportedChains: Chain[];\n}\n\n/**\n * 钱包提供者配置\n */\nexport interface WalletProviderConfig {\n chains: Chain[];\n autoConnect?: boolean;\n appName?: string;\n}\n","import { WalletError } from \"../types\";\n\n/**\n * 基于 EIP-1193 的错误代码\n */\nexport const ErrorCode = {\n USER_REJECTED: 4001,\n UNAUTHORIZED: 4100,\n UNSUPPORTED_METHOD: 4200,\n DISCONNECTED: 4900,\n CHAIN_DISCONNECTED: 4901,\n UNRECOGNIZED_CHAIN: 4902,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n PROVIDER_NOT_FOUND: -32000,\n WALLET_NOT_INSTALLED: -32001,\n ALREADY_CONNECTED: -32002,\n} as const;\n\n/**\n * 创建钱包错误\n */\nexport function createWalletError(\n message: string,\n code: number,\n data?: unknown,\n): WalletError {\n return new WalletError(message, code, data);\n}\n\n/**\n * 检查错误是否为用户拒绝\n */\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof WalletError) {\n return error.code === ErrorCode.USER_REJECTED;\n }\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.USER_REJECTED;\n }\n return false;\n}\n\n/**\n * 解析提供者错误\n */\nexport function parseProviderError(error: unknown): WalletError {\n if (error instanceof WalletError) {\n return error;\n }\n\n if (typeof error === \"object\" && error !== null) {\n const err = error as {\n code?: number;\n message?: string;\n data?: unknown;\n };\n\n return createWalletError(\n err.message || \"未知错误\",\n err.code || ErrorCode.INTERNAL_ERROR,\n err.data,\n );\n }\n\n if (typeof error === \"string\") {\n return createWalletError(error, ErrorCode.INTERNAL_ERROR);\n }\n\n return createWalletError(\"发生未知错误\", ErrorCode.INTERNAL_ERROR);\n}\n","import {\n EthereumProvider,\n RequestArguments,\n Chain,\n WalletInfo,\n WalletEventListener,\n} from \"../types\";\nimport {\n ErrorCode,\n createWalletError,\n parseProviderError,\n} from \"../utils/errors\";\n\n/**\n * 钱包基类(抽象类)\n * 所有钱包实现都应继承此类\n */\nexport abstract class BaseWallet {\n protected provider: EthereumProvider | null = null;\n protected eventListeners: Map<string, Set<WalletEventListener>> = new Map();\n\n /**\n * 获取钱包信息\n */\n abstract getInfo(): WalletInfo;\n\n /**\n * 检查钱包是否安装\n */\n abstract isInstalled(): boolean;\n\n /**\n * 获取提供者实例\n */\n abstract getProvider(): EthereumProvider | null;\n\n /**\n * 连接钱包\n */\n async connect(): Promise<string[]> {\n if (!this.isInstalled()) {\n throw createWalletError(\n `${this.getInfo().name} 未安装`,\n ErrorCode.WALLET_NOT_INSTALLED,\n );\n }\n\n const provider = this.getProvider();\n if (!provider) {\n throw createWalletError(\"未找到提供者\", ErrorCode.PROVIDER_NOT_FOUND);\n }\n\n this.provider = provider;\n this.setupEventListeners();\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_requestAccounts\",\n });\n\n if (!accounts || accounts.length === 0) {\n throw createWalletError(\"未返回账户\", ErrorCode.UNAUTHORIZED);\n }\n\n return accounts;\n } catch (error) {\n this.cleanup();\n throw parseProviderError(error);\n }\n }\n\n /**\n * 断开钱包连接\n */\n async disconnect(): Promise<void> {\n this.cleanup();\n }\n\n /**\n * 获取当前账户\n */\n async getAccounts(): Promise<string[]> {\n if (!this.provider) {\n return [];\n }\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_accounts\",\n });\n return accounts || [];\n } catch (error) {\n console.error(\"获取账户失败:\", error);\n return [];\n }\n }\n\n /**\n * 获取当前账户余额\n */\n async getBalance(address: string): Promise<string> {\n if (!this.provider) {\n return \"0x0\";\n }\n\n try {\n const balance = await this.request<string>({\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n });\n return balance;\n } catch (error) {\n console.error(\"获取余额失败:\", error);\n return \"0x0\";\n }\n }\n\n /**\n * 获取当前链 ID\n */\n async getChainId(): Promise<string> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const chainId = await this.request<string>({\n method: \"eth_chainId\",\n });\n return chainId;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 切换到指定链\n */\n async switchChain(chain: Chain): Promise<void> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n // 尝试切换链\n await this.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: chain.chainId }],\n });\n } catch (error) {\n // 如果未添加该链,则尝试添加\n if (this.isUnrecognizedChainError(error)) {\n try {\n await this.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: chain.chainId,\n chainName: chain.chainName,\n nativeCurrency: chain.nativeCurrency,\n rpcUrls: chain.rpcUrls,\n blockExplorerUrls: chain.blockExplorerUrls,\n iconUrls: chain.iconUrls,\n },\n ],\n });\n } catch (addError) {\n throw parseProviderError(addError);\n }\n } else {\n throw parseProviderError(error);\n }\n }\n }\n\n /**\n * 添加事件监听器\n */\n on(event: string, listener: WalletEventListener): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(listener);\n }\n\n /**\n * 移除事件监听器\n */\n off(event: string, listener: WalletEventListener): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 发起 JSON-RPC 请求\n */\n protected async request<T = unknown>(args: RequestArguments): Promise<T> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const result = await this.provider.request(args);\n return result as T;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 设置提供者事件监听\n */\n protected setupEventListeners(): void {\n if (!this.provider) return;\n\n this.provider.on(\"accountsChanged\", this.handleAccountsChanged);\n this.provider.on(\"chainChanged\", this.handleChainChanged);\n this.provider.on(\"disconnect\", this.handleDisconnect);\n }\n\n /**\n * 清理资源和监听器\n */\n protected cleanup(): void {\n if (this.provider) {\n this.provider.removeListener(\n \"accountsChanged\",\n this.handleAccountsChanged,\n );\n this.provider.removeListener(\"chainChanged\", this.handleChainChanged);\n this.provider.removeListener(\"disconnect\", this.handleDisconnect);\n }\n this.provider = null;\n this.eventListeners.clear();\n }\n\n /**\n * 处理账户变更事件\n */\n protected handleAccountsChanged = (accounts: unknown): void => {\n this.emit(\"accountsChanged\", accounts);\n };\n\n /**\n * 处理链变更事件\n */\n protected handleChainChanged = (chainId: unknown): void => {\n this.emit(\"chainChanged\", chainId);\n };\n\n /**\n * 处理断开连接事件\n */\n protected handleDisconnect = (): void => {\n this.emit(\"disconnect\", null);\n this.cleanup();\n };\n\n /**\n * 向所有监听器触发事件\n */\n protected emit(event: string, data: unknown): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`${event} 监听器错误:`, error);\n }\n });\n }\n }\n\n /**\n * 检查错误是否为未知链错误\n */\n protected isUnrecognizedChainError(error: unknown): boolean {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.UNRECOGNIZED_CHAIN;\n }\n return false;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n ethereum?: EthereumProvider;\n }\n}\n\n/**\n * MetaMask 钱包实现\n */\nexport class MetaMaskWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"metamask\",\n name: \"MetaMask\",\n downloadUrl: \"https://metamask.io/download/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.ethereum?.isMetaMask);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n\n // MetaMask 可能会与其他钱包共享 window.ethereum\n // 尝试获取 MetaMask 专属的提供者\n if (window.ethereum?.isMetaMask) {\n return window.ethereum;\n }\n\n return null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n okxwallet?: EthereumProvider;\n }\n}\n\n/**\n * OKX 钱包实现\n */\nexport class OKXWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"okx\",\n name: \"OKX Wallet\",\n downloadUrl: \"https://www.okx.com/web3\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.okxwallet);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.okxwallet || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n phantom?: {\n ethereum?: EthereumProvider;\n };\n }\n}\n\n/**\n * Phantom 钱包实现\n * Phantom 支持 Solana 和 Ethereum\n * 我们使用 ethereum 属性以兼容 EVM\n */\nexport class PhantomWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"phantom\",\n name: \"Phantom\",\n downloadUrl: \"https://phantom.app/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.phantom?.ethereum);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.phantom?.ethereum || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n coinbaseWalletExtension?: EthereumProvider;\n }\n}\n\n/**\n * Coinbase 钱包实现\n */\nexport class CoinbaseWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"coinbase\",\n name: \"Coinbase Wallet\",\n downloadUrl: \"https://www.coinbase.com/wallet\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.coinbaseWalletExtension);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.coinbaseWalletExtension || null;\n }\n}\n","export { BaseWallet } from \"./BaseWallet\";\nexport { MetaMaskWallet } from \"./MetaMaskWallet\";\nexport { OKXWallet } from \"./OKXWallet\";\nexport { PhantomWallet } from \"./PhantomWallet\";\nexport { CoinbaseWallet } from \"./CoinbaseWallet\";\n\nimport { MetaMaskWallet } from \"./MetaMaskWallet\";\nimport { OKXWallet } from \"./OKXWallet\";\nimport { PhantomWallet } from \"./PhantomWallet\";\nimport { CoinbaseWallet } from \"./CoinbaseWallet\";\nimport { BaseWallet } from \"./BaseWallet\";\n\n/**\n * 所有可用钱包的注册表\n */\nexport const walletRegistry: BaseWallet[] = [\n new MetaMaskWallet(),\n new OKXWallet(),\n new PhantomWallet(),\n new CoinbaseWallet(),\n];\n\n/**\n * 根据 ID 获取钱包\n */\nexport function getWalletById(id: string): BaseWallet | undefined {\n return walletRegistry.find((wallet) => wallet.getInfo().id === id);\n}\n","import { Chain } from \"../types\";\n\n/**\n * 以太坊主网\n */\nexport const mainnet: Chain = {\n chainId: \"0x1\",\n chainName: \"Ethereum Mainnet\",\n nativeCurrency: {\n name: \"Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://eth.llamarpc.com\"],\n blockExplorerUrls: [\"https://etherscan.io\"],\n};\n\n/**\n * Sepolia 测试网\n */\nexport const sepolia: Chain = {\n chainId: \"0xaa36a7\",\n chainName: \"Sepolia\",\n nativeCurrency: {\n name: \"Sepolia Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://rpc.sepolia.org\"],\n blockExplorerUrls: [\"https://sepolia.etherscan.io\"],\n};\n\n/**\n * 默认链列表\n */\nexport const defaultChains: Chain[] = [mainnet, sepolia];\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(\n chainId: string,\n chains: Chain[],\n): Chain | undefined {\n return chains.find(\n (chain) => chain.chainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * 将 chainId 格式化为十六进制字符串\n */\nexport function formatChainId(chainId: number | string): string {\n if (typeof chainId === \"string\") {\n if (chainId.startsWith(\"0x\")) {\n return chainId;\n }\n return `0x${parseInt(chainId, 10).toString(16)}`;\n }\n return `0x${chainId.toString(16)}`;\n}\n\n/**\n * 将 chainId 解析为数字\n */\nexport function parseChainId(chainId: string): number {\n if (chainId.startsWith(\"0x\")) {\n return parseInt(chainId, 16);\n }\n return parseInt(chainId, 10);\n}\n","import React, { useState, useEffect, useCallback, useMemo } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletProviderConfig, WalletState, Chain, WalletInfo } from \"../types\";\nimport { walletRegistry, getWalletById, BaseWallet } from \"../wallets\";\nimport { ErrorCode, createWalletError } from \"../utils/errors\";\nimport { defaultChains, getChainById } from \"../utils/chains\";\n\ninterface WalletProviderProps {\n children: React.ReactNode;\n config: WalletProviderConfig;\n}\n\nconst STORAGE_KEY = \"wjb_wallet_connect\";\n\n/**\n * 钱包提供者组件\n * 管理钱包连接状态并向子组件提供钱包上下文\n */\nexport function WalletProvider({ children, config }: WalletProviderProps) {\n const { chains = defaultChains, autoConnect = true } = config;\n\n const [state, setState] = useState<WalletState>({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n const [currentWallet, setCurrentWallet] = useState<BaseWallet | null>(null);\n\n /**\n * 获取可用(已安装)的钱包\n */\n const availableWallets: WalletInfo[] = useMemo(() => {\n return walletRegistry\n .filter((wallet) => wallet.isInstalled())\n .map((wallet) => wallet.getInfo());\n }, []);\n\n /**\n * 更新余额\n */\n const updateBalance = useCallback(\n async (wallet: BaseWallet, account: string) => {\n try {\n const balance = await wallet.getBalance(account);\n setState((prev) => ({ ...prev, balance }));\n } catch (error) {\n console.error(\"更新余额失败:\", error);\n }\n },\n [],\n );\n\n /**\n * 连接到指定钱包\n */\n const connect = useCallback(\n async (walletId: string) => {\n try {\n // 检查是否已连接\n if (state.isConnected && state.wallet?.id === walletId) {\n throw createWalletError(\"钱包已连接\", ErrorCode.ALREADY_CONNECTED);\n }\n\n // 如果有当前连接的钱包,先断开\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n // 获取钱包实例\n const wallet = getWalletById(walletId);\n if (!wallet) {\n throw createWalletError(\n `未找到钱包 ${walletId}`,\n ErrorCode.PROVIDER_NOT_FOUND,\n );\n }\n\n // 连接钱包\n const accounts = await wallet.connect();\n const chainId = await wallet.getChainId();\n const balance = await wallet.getBalance(accounts[0]);\n\n const walletInfo = wallet.getInfo();\n\n // 设置事件监听器\n wallet.on(\"accountsChanged\", async (accounts) => {\n const accountList = accounts as string[];\n if (accountList.length === 0) {\n // 用户断开连接\n disconnect();\n } else {\n const newAccount = accountList[0];\n const newBalance = await wallet.getBalance(newAccount);\n setState((prev) => ({\n ...prev,\n account: newAccount,\n balance: newBalance,\n }));\n }\n });\n\n wallet.on(\"chainChanged\", async (chainId) => {\n // 链改变后重新获取余额\n const currentAccount = (await wallet.getAccounts())[0];\n let newBalance = \"0x0\";\n if (currentAccount) {\n newBalance = await wallet.getBalance(currentAccount);\n }\n\n setState((prev) => ({\n ...prev,\n chainId: chainId as string,\n balance: newBalance,\n }));\n });\n\n wallet.on(\"disconnect\", () => {\n disconnect();\n });\n\n setCurrentWallet(wallet);\n setState({\n isConnected: true,\n account: accounts[0],\n chainId,\n balance,\n wallet: walletInfo,\n });\n\n // 保存到 localStorage 以便自动连接\n if (typeof window !== \"undefined\") {\n localStorage.setItem(\n STORAGE_KEY,\n JSON.stringify({ walletId, account: accounts[0] }),\n );\n }\n } catch (error) {\n console.error(\"连接钱包失败:\", error);\n throw error;\n }\n },\n [state.isConnected, state.wallet, currentWallet],\n );\n\n /**\n * 断开钱包连接\n */\n const disconnect = useCallback(async () => {\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n setCurrentWallet(null);\n setState({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n // 清除 localStorage\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, [currentWallet]);\n\n /**\n * 切换链\n */\n const switchChain = useCallback(\n async (chainId: string) => {\n if (!currentWallet) {\n throw createWalletError(\"未连接钱包\", ErrorCode.DISCONNECTED);\n }\n\n const chain = getChainById(chainId, chains);\n if (!chain) {\n throw createWalletError(\n `不支持链 ${chainId}`,\n ErrorCode.UNRECOGNIZED_CHAIN,\n );\n }\n\n await currentWallet.switchChain(chain);\n\n // chainChanged 事件将更新状态\n },\n [currentWallet, chains],\n );\n\n /**\n * 组件挂载时自动连接\n */\n useEffect(() => {\n if (!autoConnect) return;\n\n const attemptAutoConnect = async () => {\n if (typeof window === \"undefined\") return;\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return;\n\n try {\n const { walletId } = JSON.parse(stored);\n const wallet = getWalletById(walletId);\n\n if (!wallet) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 尝试等待钱包注入(解决页面刷新时注入延迟问题)\n let retryCount = 0;\n while (!wallet.isInstalled() && retryCount < 10) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n retryCount++;\n }\n\n if (!wallet.isInstalled()) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 如果已安装钱包插件则自动连接\n await connect(walletId);\n } catch (error) {\n console.error(\"自动连接失败:\", error);\n localStorage.removeItem(STORAGE_KEY);\n }\n };\n\n attemptAutoConnect();\n }, [autoConnect]);\n\n const value = useMemo(\n () => ({\n state,\n connect,\n disconnect,\n switchChain,\n availableWallets,\n supportedChains: chains,\n }),\n [state, connect, disconnect, switchChain, availableWallets, chains],\n );\n\n return (\n <WalletContext.Provider value={value}>{children}</WalletContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 访问钱包上下文的 Hook\n */\nexport function useWallet(): WalletContextValue {\n const context = useContext(WalletContext);\n\n if (!context) {\n throw new Error(\"useWallet 必须在 WalletProvider 中使用\");\n }\n\n return context;\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { walletRegistry } from \"../wallets\";\n\ninterface WalletModalProps {\n onClose: () => void;\n}\n\nexport function WalletModal({ onClose }: WalletModalProps) {\n const { connect, availableWallets } = useWallet();\n const [connecting, setConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleConnect = async (walletId: string) => {\n setConnecting(true);\n setError(null);\n try {\n await connect(walletId);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"连接失败\");\n } finally {\n setConnecting(false);\n }\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n // Predefine icons/colors for known wallets or use generic\n const getWalletIcon = (id: string) => {\n // Allow flexible icon rendering. For now, simple colored squares or letters.\n // In a real app, these would be proper SVGs or helper components.\n if (id === \"metamask\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-orange-100 flex items-center justify-center text-orange-500\">\n 🦊\n </div>\n );\n if (id === \"okx\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-black flex items-center justify-center text-white\">\n X\n </div>\n );\n if (id === \"phantom\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-purple-100 flex items-center justify-center text-purple-500\">\n P\n </div>\n );\n if (id === \"coinbase\")\n return (\n <div className=\"w-8 h-8 rounded-lg bg-blue-100 flex items-center justify-center text-blue-500\">\n C\n </div>\n );\n return <div className=\"w-8 h-8 rounded-lg bg-gray-200\"></div>;\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-wallet-modal-content\">\n {/* Left Side: Wallet List */}\n <div className=\"wjb-modal-left\">\n <div className=\"wjb-modal-header\">\n <h2 className=\"wjb-modal-title\">连接钱包</h2>\n {/* Mobile close button could go here, but omitted for clean desktop design or added if needed */}\n </div>\n\n <div className=\"wjb-wallet-list\">\n {/* Installed Wallets */}\n {availableWallets.map((wallet) => (\n <button\n key={wallet.id}\n onClick={() => handleConnect(wallet.id)}\n disabled={connecting}\n className=\"wjb-wallet-option\"\n >\n {getWalletIcon(wallet.id)}\n <span className=\"flex-1\">{wallet.name}</span>\n {connecting && (\n <span className=\"text-xs text-blue-500 animate-pulse\">\n 连接中...\n </span>\n )}\n </button>\n ))}\n\n {/* Uninstalled Wallets */}\n {walletRegistry\n .filter((w) => !w.isInstalled())\n .map((wallet) => {\n const info = wallet.getInfo();\n return (\n <a\n key={info.id}\n href={info.downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"wjb-wallet-option opacity-60 hover:opacity-100\"\n >\n {getWalletIcon(info.id)}\n <span className=\"flex-1\">{info.name}</span>\n <span className=\"text-xs font-bold text-blue-500 bg-blue-50 px-2 py-1 rounded\">\n 安装\n </span>\n </a>\n );\n })}\n </div>\n\n {error && (\n <div className=\"mt-4 p-3 bg-red-50 text-red-500 text-sm rounded-xl\">\n {error}\n </div>\n )}\n </div>\n\n {/* Right Side: Education / Info */}\n <div className=\"wjb-modal-right hidden md:flex\">\n {/* Icon Grid Placeholder */}\n <div className=\"grid grid-cols-2 gap-4 mb-6 opacity-80\">\n <div className=\"w-12 h-12 bg-blue-500 rounded-xl shadow-lg -rotate-6\"></div>\n <div className=\"w-12 h-12 bg-purple-500 rounded-xl shadow-lg rotate-12\"></div>\n <div className=\"w-12 h-12 bg-orange-500 rounded-xl shadow-lg rotate-6\"></div>\n <div className=\"w-12 h-12 bg-green-500 rounded-xl shadow-lg -rotate-12\"></div>\n </div>\n\n <h3 className=\"text-lg font-bold text-gray-900 dark:text-white mb-2\">\n 什么是钱包?\n </h3>\n <ul className=\"text-sm text-gray-500 dark:text-gray-400 space-y-3 text-left max-w-xs\">\n <li className=\"flex items-start gap-2\">\n <span className=\"mt-1\">🏠</span>\n <span>\n 您的数字资产之家\n <br />\n 发送、接收和存储资产。\n </span>\n </li>\n <li className=\"flex items-start gap-2\">\n <span className=\"mt-1\">🔐</span>\n <span>\n 一种新的登录方式\n <br />\n 无需创建账户和密码。\n </span>\n </li>\n </ul>\n\n <button className=\"mt-6 px-4 py-2 bg-gray-200 dark:bg-gray-700 rounded-lg text-sm font-bold text-gray-700 dark:text-white hover:bg-gray-300 transition-colors\">\n 了解更多\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useRef, useEffect } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\n\ninterface ChainSwitcherProps {\n onClose: () => void;\n}\n\nexport function ChainSwitcher({ onClose }: ChainSwitcherProps) {\n const { supportedChains, switchChain, state } = useWallet();\n // We can use a backdrop for mobile, or click outside for desktop dropdown\n const handleSwitch = async (chainId: string) => {\n if (state.chainId !== chainId) {\n await switchChain(chainId);\n }\n onClose();\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-chain-switcher-content\">\n <div className=\"p-4 border-b border-gray-100 dark:border-gray-800 flex justify-between items-center\">\n <h3 className=\"font-bold text-gray-900 dark:text-white\">切换网络</h3>\n <button onClick={onClose} className=\"wjb-account-modal-close\">\n ✕\n </button>\n </div>\n\n <div className=\"p-2 space-y-1\">\n {supportedChains.map((chain) => (\n <button\n key={chain.chainId}\n onClick={() => handleSwitch(chain.chainId)}\n className={`wjb-chain-option ${state.chainId === chain.chainId ? \"active\" : \"\"}`}\n >\n <div className=\"flex items-center\">\n {/* Chain Icons */}\n <div\n className={`wjb-chain-icon flex items-center justify-center text-white text-xs ${\n chain.chainId === \"0x1\" ? \"bg-blue-500\" : \"bg-purple-500\"\n }`}\n >\n {chain.chainName[0]}\n </div>\n <span>{chain.chainName}</span>\n </div>\n\n {state.chainId === chain.chainId && (\n <span className=\"text-sm font-bold text-green-500\">已连接</span>\n )}\n </button>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * Format balance from hex/wei to formatted string\n */\nexport function formatBalance(rawBalance: string | undefined): string {\n if (!rawBalance || rawBalance === \"0x0\") return \"0 ETH\";\n\n try {\n const hex = rawBalance.startsWith(\"0x\") ? rawBalance : `0x${rawBalance}`;\n const wei = BigInt(hex);\n // Rough conversion to ETH (18 decimals), keeping 4 decimal places\n const divisor = 1000000000000000000n;\n const integerPart = wei / divisor;\n const remainder = wei % divisor;\n\n // Convert remainder to decimal string padded with zeros\n const decimals = remainder.toString().padStart(18, \"0\").slice(0, 4);\n\n // Remove trailing zeros if any\n const formattedDecimals = decimals.replace(/0+$/, \"\");\n\n return formattedDecimals\n ? `${integerPart}.${formattedDecimals} ETH`\n : `${integerPart} ETH`;\n } catch (error) {\n console.error(\"Error formatting balance:\", error);\n return \"0 ETH\";\n }\n}\n\n/**\n * Format address to short form 0x...1234\n */\nexport function formatAddress(address: string | null | undefined): string {\n if (!address) return \"\";\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n","import React from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { formatAddress } from \"../utils/format\";\n\ninterface AccountModalProps {\n onClose: () => void;\n}\n\nexport function AccountModal({ onClose }: AccountModalProps) {\n const { state, disconnect } = useWallet();\n const { account, balance } = state;\n\n const handleCopy = async () => {\n if (account) {\n await navigator.clipboard.writeText(account);\n // Could add toast here\n }\n };\n\n const handleDisconnect = async () => {\n await disconnect();\n onClose();\n };\n\n // Close when clicking overlay\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-account-modal-content\">\n <button onClick={onClose} className=\"wjb-account-modal-close\">\n ✕\n </button>\n\n <div className=\"wjb-account-avatar-large\" />\n\n <div className=\"wjb-account-address-large\">\n {formatAddress(account)}\n </div>\n\n <div className=\"wjb-account-balance-large\">\n {state.balance || \"0 ETH\"}\n {/* Fallback not really needed if state init correct, but safe */}\n </div>\n\n <div className=\"wjb-account-actions\">\n <button onClick={handleCopy} className=\"wjb-action-button\">\n {/* Copy Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n 复制地址\n </button>\n\n <button\n onClick={handleDisconnect}\n className=\"wjb-action-button text-red-500 hover:text-red-600\"\n >\n {/* Disconnect Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" />\n </svg>\n 断开连接\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { WalletModal } from \"./WalletModal\";\nimport { ChainSwitcher } from \"./ChainSwitcher\";\nimport { AccountModal } from \"./AccountModal\"; // Import new component\nimport { formatAddress, formatBalance } from \"../utils/format\";\n\nexport function ConnectButton() {\n const { state } = useWallet();\n const [showWalletModal, setShowWalletModal] = useState(false);\n const [showChainSwitcher, setShowChainSwitcher] = useState(false);\n const [showAccountModal, setShowAccountModal] = useState(false);\n\n if (!state.isConnected) {\n return (\n <>\n <button\n onClick={() => setShowWalletModal(true)}\n className=\"wjb-connect-button wjb-connect-button-primary\"\n >\n 连接钱包\n </button>\n {showWalletModal && (\n <WalletModal onClose={() => setShowWalletModal(false)} />\n )}\n </>\n );\n }\n\n return (\n <>\n <div className=\"wjb-wallet-connected\">\n <div className=\"wjb-wallet-info-group\">\n {/* Chain Switcher Trigger */}\n <button\n onClick={() => setShowChainSwitcher(true)}\n className=\"wjb-chain-button\"\n >\n {/* Simple Chain Icon Placeholder or check ChainID */}\n <div\n className={`w-5 h-5 rounded-full ${\n state.chainId === \"0x1\"\n ? \"bg-blue-500\"\n : state.chainId === \"0xaa36a7\"\n ? \"bg-purple-500\"\n : \"bg-gray-500\"\n } flex items-center justify-center text-white text-[10px]`}\n >\n {state.chainId === \"0x1\"\n ? \"E\"\n : state.chainId === \"0xaa36a7\"\n ? \"S\"\n : \"?\"}\n </div>\n <span>\n {state.chainId === \"0x1\" && \"Ethereum\"}\n {state.chainId === \"0xaa36a7\" && \"Sepolia\"}\n {state.chainId &&\n state.chainId !== \"0x1\" &&\n state.chainId !== \"0xaa36a7\" &&\n \"Unknown\"}\n </span>\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"text-gray-400\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n\n {/* Balance Display */}\n <div className=\"wjb-balance\">\n {state.balance ? formatBalance(state.balance) : \"0 ETH\"}\n </div>\n\n {/* Account Button */}\n <button\n onClick={() => setShowAccountModal(true)}\n className=\"wjb-account-button\"\n >\n <span>{state.account && formatAddress(state.account)}</span>\n <div className=\"wjb-account-avatar\" />\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"text-gray-400 ml-1\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n {showChainSwitcher && (\n <ChainSwitcher onClose={() => setShowChainSwitcher(false)} />\n )}\n\n {showAccountModal && (\n <AccountModal onClose={() => setShowAccountModal(false)} />\n )}\n </>\n );\n}\n"],"names":["WalletContext","createContext","WalletError","Error","constructor","message","code","data","super","Object","defineProperty","this","name","ErrorCode","USER_REJECTED","UNAUTHORIZED","UNSUPPORTED_METHOD","DISCONNECTED","CHAIN_DISCONNECTED","UNRECOGNIZED_CHAIN","INVALID_PARAMS","INTERNAL_ERROR","PROVIDER_NOT_FOUND","WALLET_NOT_INSTALLED","ALREADY_CONNECTED","createWalletError","parseProviderError","error","err","BaseWallet","value","Map","accounts","emit","chainId","cleanup","connect","isInstalled","getInfo","provider","getProvider","setupEventListeners","request","method","length","disconnect","getAccounts","console","getBalance","address","params","getChainId","switchChain","chain","isUnrecognizedChainError","chainName","nativeCurrency","rpcUrls","blockExplorerUrls","iconUrls","addError","on","event","listener","eventListeners","has","set","Set","get","add","off","listeners","delete","args","handleAccountsChanged","handleChainChanged","handleDisconnect","removeListener","clear","forEach","MetaMaskWallet","id","downloadUrl","window","Boolean","ethereum","isMetaMask","OKXWallet","okxwallet","PhantomWallet","phantom","CoinbaseWallet","coinbaseWalletExtension","walletRegistry","getWalletById","find","wallet","mainnet","symbol","decimals","sepolia","defaultChains","STORAGE_KEY","WalletProvider","children","config","chains","autoConnect","state","setState","useState","isConnected","account","balance","currentWallet","setCurrentWallet","availableWallets","useMemo","filter","map","useCallback","async","prev","walletId","walletInfo","accountList","newAccount","newBalance","currentAccount","localStorage","setItem","JSON","stringify","removeItem","toLowerCase","getChainById","useEffect","stored","getItem","parse","retryCount","Promise","resolve","setTimeout","attemptAutoConnect","supportedChains","_jsx","Provider","useWallet","context","useContext","WalletModal","onClose","connecting","setConnecting","setError","getWalletIcon","className","onClick","e","target","currentTarget","_jsxs","handleConnect","disabled","w","info","href","rel","ChainSwitcher","handleSwitch","formatBalance","rawBalance","hex","startsWith","wei","BigInt","divisor","integerPart","formattedDecimals","toString","padStart","slice","replace","formatAddress","AccountModal","navigator","clipboard","writeText","width","height","viewBox","fill","stroke","strokeWidth","x","y","rx","ry","d","points","x1","y1","x2","y2","ConnectButton","showWalletModal","setShowWalletModal","showChainSwitcher","setShowChainSwitcher","showAccountModal","setShowAccountModal","_Fragment","strokeLinecap","strokeLinejoin"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/context/WalletContext.tsx","../../src/types/wallet.ts","../../src/utils/errors.ts","../../src/wallets/BaseWallet.ts","../../src/wallets/MetaMaskWallet.ts","../../src/wallets/OKXWallet.ts","../../src/wallets/PhantomWallet.ts","../../src/wallets/CoinbaseWallet.ts","../../src/wallets/index.ts","../../src/utils/chains.ts","../../src/components/WalletProvider.tsx","../../src/hooks/useWallet.ts","../../src/components/WalletModal.tsx","../../src/components/ChainSwitcher.tsx","../../src/utils/format.ts","../../src/components/AccountModal.tsx","../../src/components/ConnectButton.tsx"],"sourcesContent":["import { createContext } from \"react\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 钱包上下文\n */\nexport const WalletContext = createContext<WalletContextValue | null>(null);\n","/**\n * 基于 EIP-1193 的以太坊提供者接口\n */\nexport interface EthereumProvider {\n request(args: RequestArguments): Promise<unknown>;\n on(event: string, listener: (...args: unknown[]) => void): void;\n removeListener(event: string, listener: (...args: unknown[]) => void): void;\n isMetaMask?: boolean;\n isOkxWallet?: boolean;\n isCoinbaseWallet?: boolean;\n isPhantom?: boolean;\n}\n\n/**\n * JSON-RPC 调用请求参数\n */\nexport interface RequestArguments {\n method: string;\n params?: unknown[] | Record<string, unknown>;\n}\n\n/**\n * 链配置\n */\nexport interface Chain {\n chainId: string; // 十六进制字符串,例如 \"0x1\"\n chainName: string;\n nativeCurrency: {\n name: string;\n symbol: string;\n decimals: number;\n };\n rpcUrls: string[];\n blockExplorerUrls?: string[];\n iconUrls?: string[];\n}\n\n/**\n * 钱包信息\n */\nexport interface WalletInfo {\n id: string;\n name: string;\n icon?: string;\n downloadUrl?: string;\n}\n\n/**\n * 钱包连接状态\n */\nexport interface WalletState {\n isConnected: boolean;\n account: string | null;\n chainId: string | null;\n balance: string | null;\n wallet: WalletInfo | null;\n}\n\n/**\n * 钱包事件类型\n */\nexport type WalletEventType =\n | \"accountsChanged\"\n | \"chainChanged\"\n | \"connect\"\n | \"disconnect\";\n\n/**\n * 事件监听器类型\n */\nexport type WalletEventListener = (data: unknown) => void;\n\n/**\n * 钱包错误类型\n */\nexport class WalletError extends Error {\n code: number;\n data?: unknown;\n\n constructor(message: string, code: number, data?: unknown) {\n super(message);\n this.name = \"WalletError\";\n this.code = code;\n this.data = data;\n }\n}\n\n/**\n * 钱包提供者上下文值\n */\nexport interface WalletContextValue {\n state: WalletState;\n connect: (walletId: string) => Promise<void>;\n disconnect: () => Promise<void>;\n switchChain: (chainId: string) => Promise<void>;\n availableWallets: WalletInfo[];\n supportedChains: Chain[];\n}\n\n/**\n * 钱包提供者配置\n */\nexport interface WalletProviderConfig {\n chains: Chain[];\n autoConnect?: boolean;\n appName?: string;\n}\n","import { WalletError } from \"../types\";\n\n/**\n * 基于 EIP-1193 的错误代码\n */\nexport const ErrorCode = {\n USER_REJECTED: 4001,\n UNAUTHORIZED: 4100,\n UNSUPPORTED_METHOD: 4200,\n DISCONNECTED: 4900,\n CHAIN_DISCONNECTED: 4901,\n UNRECOGNIZED_CHAIN: 4902,\n INVALID_PARAMS: -32602,\n INTERNAL_ERROR: -32603,\n PROVIDER_NOT_FOUND: -32000,\n WALLET_NOT_INSTALLED: -32001,\n ALREADY_CONNECTED: -32002,\n} as const;\n\n/**\n * 创建钱包错误\n */\nexport function createWalletError(\n message: string,\n code: number,\n data?: unknown,\n): WalletError {\n return new WalletError(message, code, data);\n}\n\n/**\n * 检查错误是否为用户拒绝\n */\nexport function isUserRejectedError(error: unknown): boolean {\n if (error instanceof WalletError) {\n return error.code === ErrorCode.USER_REJECTED;\n }\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.USER_REJECTED;\n }\n return false;\n}\n\n/**\n * 解析提供者错误\n */\nexport function parseProviderError(error: unknown): WalletError {\n if (error instanceof WalletError) {\n return error;\n }\n\n if (typeof error === \"object\" && error !== null) {\n const err = error as {\n code?: number;\n message?: string;\n data?: unknown;\n };\n\n return createWalletError(\n err.message || \"未知错误\",\n err.code || ErrorCode.INTERNAL_ERROR,\n err.data,\n );\n }\n\n if (typeof error === \"string\") {\n return createWalletError(error, ErrorCode.INTERNAL_ERROR);\n }\n\n return createWalletError(\"发生未知错误\", ErrorCode.INTERNAL_ERROR);\n}\n","import {\n EthereumProvider,\n RequestArguments,\n Chain,\n WalletInfo,\n WalletEventListener,\n} from \"../types\";\nimport {\n ErrorCode,\n createWalletError,\n parseProviderError,\n} from \"../utils/errors\";\n\n/**\n * 钱包基类(抽象类)\n * 所有钱包实现都应继承此类\n */\nexport abstract class BaseWallet {\n protected provider: EthereumProvider | null = null;\n protected eventListeners: Map<string, Set<WalletEventListener>> = new Map();\n\n /**\n * 获取钱包信息\n */\n abstract getInfo(): WalletInfo;\n\n /**\n * 检查钱包是否安装\n */\n abstract isInstalled(): boolean;\n\n /**\n * 获取提供者实例\n */\n abstract getProvider(): EthereumProvider | null;\n\n /**\n * 连接钱包\n */\n async connect(): Promise<string[]> {\n if (!this.isInstalled()) {\n throw createWalletError(\n `${this.getInfo().name} 未安装`,\n ErrorCode.WALLET_NOT_INSTALLED,\n );\n }\n\n const provider = this.getProvider();\n if (!provider) {\n throw createWalletError(\"未找到提供者\", ErrorCode.PROVIDER_NOT_FOUND);\n }\n\n this.provider = provider;\n this.setupEventListeners();\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_requestAccounts\",\n });\n\n if (!accounts || accounts.length === 0) {\n throw createWalletError(\"未返回账户\", ErrorCode.UNAUTHORIZED);\n }\n\n return accounts;\n } catch (error) {\n this.cleanup();\n throw parseProviderError(error);\n }\n }\n\n /**\n * 断开钱包连接\n */\n async disconnect(): Promise<void> {\n this.cleanup();\n }\n\n /**\n * 获取当前账户\n */\n async getAccounts(): Promise<string[]> {\n if (!this.provider) {\n return [];\n }\n\n try {\n const accounts = await this.request<string[]>({\n method: \"eth_accounts\",\n });\n return accounts || [];\n } catch (error) {\n console.error(\"获取账户失败:\", error);\n return [];\n }\n }\n\n /**\n * 获取当前账户余额\n */\n async getBalance(address: string): Promise<string> {\n if (!this.provider) {\n return \"0x0\";\n }\n\n try {\n const balance = await this.request<string>({\n method: \"eth_getBalance\",\n params: [address, \"latest\"],\n });\n return balance;\n } catch (error) {\n console.error(\"获取余额失败:\", error);\n return \"0x0\";\n }\n }\n\n /**\n * 获取当前链 ID\n */\n async getChainId(): Promise<string> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const chainId = await this.request<string>({\n method: \"eth_chainId\",\n });\n return chainId;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 切换到指定链\n */\n async switchChain(chain: Chain): Promise<void> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n // 尝试切换链\n await this.request({\n method: \"wallet_switchEthereumChain\",\n params: [{ chainId: chain.chainId }],\n });\n } catch (error) {\n // 如果未添加该链,则尝试添加\n if (this.isUnrecognizedChainError(error)) {\n try {\n await this.request({\n method: \"wallet_addEthereumChain\",\n params: [\n {\n chainId: chain.chainId,\n chainName: chain.chainName,\n nativeCurrency: chain.nativeCurrency,\n rpcUrls: chain.rpcUrls,\n blockExplorerUrls: chain.blockExplorerUrls,\n iconUrls: chain.iconUrls,\n },\n ],\n });\n } catch (addError) {\n throw parseProviderError(addError);\n }\n } else {\n throw parseProviderError(error);\n }\n }\n }\n\n /**\n * 添加事件监听器\n */\n on(event: string, listener: WalletEventListener): void {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(listener);\n }\n\n /**\n * 移除事件监听器\n */\n off(event: string, listener: WalletEventListener): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.delete(listener);\n }\n }\n\n /**\n * 发起 JSON-RPC 请求\n */\n protected async request<T = unknown>(args: RequestArguments): Promise<T> {\n if (!this.provider) {\n throw createWalletError(\"提供者未连接\", ErrorCode.DISCONNECTED);\n }\n\n try {\n const result = await this.provider.request(args);\n return result as T;\n } catch (error) {\n throw parseProviderError(error);\n }\n }\n\n /**\n * 设置提供者事件监听\n */\n protected setupEventListeners(): void {\n if (!this.provider) return;\n\n this.provider.on(\"accountsChanged\", this.handleAccountsChanged);\n this.provider.on(\"chainChanged\", this.handleChainChanged);\n this.provider.on(\"disconnect\", this.handleDisconnect);\n }\n\n /**\n * 清理资源和监听器\n */\n protected cleanup(): void {\n if (this.provider) {\n this.provider.removeListener(\n \"accountsChanged\",\n this.handleAccountsChanged,\n );\n this.provider.removeListener(\"chainChanged\", this.handleChainChanged);\n this.provider.removeListener(\"disconnect\", this.handleDisconnect);\n }\n this.provider = null;\n this.eventListeners.clear();\n }\n\n /**\n * 处理账户变更事件\n */\n protected handleAccountsChanged = (accounts: unknown): void => {\n this.emit(\"accountsChanged\", accounts);\n };\n\n /**\n * 处理链变更事件\n */\n protected handleChainChanged = (chainId: unknown): void => {\n this.emit(\"chainChanged\", chainId);\n };\n\n /**\n * 处理断开连接事件\n */\n protected handleDisconnect = (): void => {\n this.emit(\"disconnect\", null);\n this.cleanup();\n };\n\n /**\n * 向所有监听器触发事件\n */\n protected emit(event: string, data: unknown): void {\n const listeners = this.eventListeners.get(event);\n if (listeners) {\n listeners.forEach((listener) => {\n try {\n listener(data);\n } catch (error) {\n console.error(`${event} 监听器错误:`, error);\n }\n });\n }\n }\n\n /**\n * 检查错误是否为未知链错误\n */\n protected isUnrecognizedChainError(error: unknown): boolean {\n if (typeof error === \"object\" && error !== null && \"code\" in error) {\n return (error as { code: number }).code === ErrorCode.UNRECOGNIZED_CHAIN;\n }\n return false;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n ethereum?: EthereumProvider;\n }\n}\n\n/**\n * MetaMask 钱包实现\n */\nexport class MetaMaskWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"metamask\",\n name: \"MetaMask\",\n downloadUrl: \"https://metamask.io/download/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.ethereum?.isMetaMask);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n\n // MetaMask 可能会与其他钱包共享 window.ethereum\n // 尝试获取 MetaMask 专属的提供者\n if (window.ethereum?.isMetaMask) {\n return window.ethereum;\n }\n\n return null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n okxwallet?: EthereumProvider;\n }\n}\n\n/**\n * OKX 钱包实现\n */\nexport class OKXWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"okx\",\n name: \"OKX Wallet\",\n downloadUrl: \"https://www.okx.com/web3\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.okxwallet);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.okxwallet || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n phantom?: {\n ethereum?: EthereumProvider;\n };\n }\n}\n\n/**\n * Phantom 钱包实现\n * Phantom 支持 Solana 和 Ethereum\n * 我们使用 ethereum 属性以兼容 EVM\n */\nexport class PhantomWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"phantom\",\n name: \"Phantom\",\n downloadUrl: \"https://phantom.app/\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.phantom?.ethereum);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.phantom?.ethereum || null;\n }\n}\n","import { BaseWallet } from \"./BaseWallet\";\nimport { EthereumProvider, WalletInfo } from \"../types\";\n\ndeclare global {\n interface Window {\n coinbaseWalletExtension?: EthereumProvider;\n }\n}\n\n/**\n * Coinbase 钱包实现\n */\nexport class CoinbaseWallet extends BaseWallet {\n getInfo(): WalletInfo {\n return {\n id: \"coinbase\",\n name: \"Coinbase Wallet\",\n downloadUrl: \"https://www.coinbase.com/wallet\",\n };\n }\n\n isInstalled(): boolean {\n if (typeof window === \"undefined\") return false;\n return Boolean(window.coinbaseWalletExtension);\n }\n\n getProvider(): EthereumProvider | null {\n if (typeof window === \"undefined\") return null;\n return window.coinbaseWalletExtension || null;\n }\n}\n","export { BaseWallet } from \"./BaseWallet\";\nexport { MetaMaskWallet } from \"./MetaMaskWallet\";\nexport { OKXWallet } from \"./OKXWallet\";\nexport { PhantomWallet } from \"./PhantomWallet\";\nexport { CoinbaseWallet } from \"./CoinbaseWallet\";\n\nimport { MetaMaskWallet } from \"./MetaMaskWallet\";\nimport { OKXWallet } from \"./OKXWallet\";\nimport { PhantomWallet } from \"./PhantomWallet\";\nimport { CoinbaseWallet } from \"./CoinbaseWallet\";\nimport { BaseWallet } from \"./BaseWallet\";\n\n/**\n * 所有可用钱包的注册表\n */\nexport const walletRegistry: BaseWallet[] = [\n new MetaMaskWallet(),\n new OKXWallet(),\n new PhantomWallet(),\n new CoinbaseWallet(),\n];\n\n/**\n * 根据 ID 获取钱包\n */\nexport function getWalletById(id: string): BaseWallet | undefined {\n return walletRegistry.find((wallet) => wallet.getInfo().id === id);\n}\n","import { Chain } from \"../types\";\n\n/**\n * 以太坊主网\n */\nexport const mainnet: Chain = {\n chainId: \"0x1\",\n chainName: \"Ethereum Mainnet\",\n nativeCurrency: {\n name: \"Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://eth.llamarpc.com\"],\n blockExplorerUrls: [\"https://etherscan.io\"],\n};\n\n/**\n * Sepolia 测试网\n */\nexport const sepolia: Chain = {\n chainId: \"0xaa36a7\",\n chainName: \"Sepolia\",\n nativeCurrency: {\n name: \"Sepolia Ether\",\n symbol: \"ETH\",\n decimals: 18,\n },\n rpcUrls: [\"https://rpc.sepolia.org\"],\n blockExplorerUrls: [\"https://sepolia.etherscan.io\"],\n};\n\n/**\n * 默认链列表\n */\nexport const defaultChains: Chain[] = [mainnet, sepolia];\n\n/**\n * 根据 chainId 获取链配置\n */\nexport function getChainById(\n chainId: string,\n chains: Chain[],\n): Chain | undefined {\n return chains.find(\n (chain) => chain.chainId.toLowerCase() === chainId.toLowerCase(),\n );\n}\n\n/**\n * 将 chainId 格式化为十六进制字符串\n */\nexport function formatChainId(chainId: number | string): string {\n if (typeof chainId === \"string\") {\n if (chainId.startsWith(\"0x\")) {\n return chainId;\n }\n return `0x${parseInt(chainId, 10).toString(16)}`;\n }\n return `0x${chainId.toString(16)}`;\n}\n\n/**\n * 将 chainId 解析为数字\n */\nexport function parseChainId(chainId: string): number {\n if (chainId.startsWith(\"0x\")) {\n return parseInt(chainId, 16);\n }\n return parseInt(chainId, 10);\n}\n","import React, { useState, useEffect, useCallback, useMemo } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletProviderConfig, WalletState, Chain, WalletInfo } from \"../types\";\nimport { walletRegistry, getWalletById, BaseWallet } from \"../wallets\";\nimport { ErrorCode, createWalletError } from \"../utils/errors\";\nimport { defaultChains, getChainById } from \"../utils/chains\";\n\ninterface WalletProviderProps {\n children: React.ReactNode;\n config: WalletProviderConfig;\n}\n\nconst STORAGE_KEY = \"wjb_wallet_connect\";\n\n/**\n * 钱包提供者组件\n * 管理钱包连接状态并向子组件提供钱包上下文\n */\nexport function WalletProvider({ children, config }: WalletProviderProps) {\n const { chains = defaultChains, autoConnect = true } = config;\n\n const [state, setState] = useState<WalletState>({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n const [currentWallet, setCurrentWallet] = useState<BaseWallet | null>(null);\n\n /**\n * 获取可用(已安装)的钱包\n */\n const availableWallets: WalletInfo[] = useMemo(() => {\n return walletRegistry\n .filter((wallet) => wallet.isInstalled())\n .map((wallet) => wallet.getInfo());\n }, []);\n\n /**\n * 更新余额\n */\n const updateBalance = useCallback(\n async (wallet: BaseWallet, account: string) => {\n try {\n const balance = await wallet.getBalance(account);\n setState((prev) => ({ ...prev, balance }));\n } catch (error) {\n console.error(\"更新余额失败:\", error);\n }\n },\n [],\n );\n\n /**\n * 连接到指定钱包\n */\n const connect = useCallback(\n async (walletId: string) => {\n try {\n // 检查是否已连接\n if (state.isConnected && state.wallet?.id === walletId) {\n throw createWalletError(\"钱包已连接\", ErrorCode.ALREADY_CONNECTED);\n }\n\n // 如果有当前连接的钱包,先断开\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n // 获取钱包实例\n const wallet = getWalletById(walletId);\n if (!wallet) {\n throw createWalletError(\n `未找到钱包 ${walletId}`,\n ErrorCode.PROVIDER_NOT_FOUND,\n );\n }\n\n // 连接钱包\n const accounts = await wallet.connect();\n const chainId = await wallet.getChainId();\n const balance = await wallet.getBalance(accounts[0]);\n\n const walletInfo = wallet.getInfo();\n\n // 设置事件监听器\n wallet.on(\"accountsChanged\", async (accounts) => {\n const accountList = accounts as string[];\n if (accountList.length === 0) {\n // 用户断开连接\n disconnect();\n } else {\n const newAccount = accountList[0];\n const newBalance = await wallet.getBalance(newAccount);\n setState((prev) => ({\n ...prev,\n account: newAccount,\n balance: newBalance,\n }));\n }\n });\n\n wallet.on(\"chainChanged\", async (chainId) => {\n // 链改变后重新获取余额\n const currentAccount = (await wallet.getAccounts())[0];\n let newBalance = \"0x0\";\n if (currentAccount) {\n newBalance = await wallet.getBalance(currentAccount);\n }\n\n setState((prev) => ({\n ...prev,\n chainId: chainId as string,\n balance: newBalance,\n }));\n });\n\n wallet.on(\"disconnect\", () => {\n disconnect();\n });\n\n setCurrentWallet(wallet);\n setState({\n isConnected: true,\n account: accounts[0],\n chainId,\n balance,\n wallet: walletInfo,\n });\n\n // 保存到 localStorage 以便自动连接\n if (typeof window !== \"undefined\") {\n localStorage.setItem(\n STORAGE_KEY,\n JSON.stringify({ walletId, account: accounts[0] }),\n );\n }\n } catch (error) {\n console.error(\"连接钱包失败:\", error);\n throw error;\n }\n },\n [state.isConnected, state.wallet, currentWallet],\n );\n\n /**\n * 断开钱包连接\n */\n const disconnect = useCallback(async () => {\n if (currentWallet) {\n await currentWallet.disconnect();\n }\n\n setCurrentWallet(null);\n setState({\n isConnected: false,\n account: null,\n chainId: null,\n balance: null,\n wallet: null,\n });\n\n // 清除 localStorage\n if (typeof window !== \"undefined\") {\n localStorage.removeItem(STORAGE_KEY);\n }\n }, [currentWallet]);\n\n /**\n * 切换链\n */\n const switchChain = useCallback(\n async (chainId: string) => {\n if (!currentWallet) {\n throw createWalletError(\"未连接钱包\", ErrorCode.DISCONNECTED);\n }\n\n const chain = getChainById(chainId, chains);\n if (!chain) {\n throw createWalletError(\n `不支持链 ${chainId}`,\n ErrorCode.UNRECOGNIZED_CHAIN,\n );\n }\n\n await currentWallet.switchChain(chain);\n\n // chainChanged 事件将更新状态\n },\n [currentWallet, chains],\n );\n\n /**\n * 组件挂载时自动连接\n */\n useEffect(() => {\n if (!autoConnect) return;\n\n const attemptAutoConnect = async () => {\n if (typeof window === \"undefined\") return;\n\n const stored = localStorage.getItem(STORAGE_KEY);\n if (!stored) return;\n\n try {\n const { walletId } = JSON.parse(stored);\n const wallet = getWalletById(walletId);\n\n if (!wallet) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 尝试等待钱包注入(解决页面刷新时注入延迟问题)\n let retryCount = 0;\n while (!wallet.isInstalled() && retryCount < 10) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n retryCount++;\n }\n\n if (!wallet.isInstalled()) {\n localStorage.removeItem(STORAGE_KEY);\n return;\n }\n\n // 如果已安装钱包插件则自动连接\n await connect(walletId);\n } catch (error) {\n console.error(\"自动连接失败:\", error);\n localStorage.removeItem(STORAGE_KEY);\n }\n };\n\n attemptAutoConnect();\n }, [autoConnect]);\n\n const value = useMemo(\n () => ({\n state,\n connect,\n disconnect,\n switchChain,\n availableWallets,\n supportedChains: chains,\n }),\n [state, connect, disconnect, switchChain, availableWallets, chains],\n );\n\n return (\n <WalletContext.Provider value={value}>{children}</WalletContext.Provider>\n );\n}\n","import { useContext } from \"react\";\nimport { WalletContext } from \"../context/WalletContext\";\nimport { WalletContextValue } from \"../types\";\n\n/**\n * 访问钱包上下文的 Hook\n */\nexport function useWallet(): WalletContextValue {\n const context = useContext(WalletContext);\n\n if (!context) {\n throw new Error(\"useWallet 必须在 WalletProvider 中使用\");\n }\n\n return context;\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { walletRegistry } from \"../wallets\";\n\ninterface WalletModalProps {\n onClose: () => void;\n}\n\nexport function WalletModal({ onClose }: WalletModalProps) {\n const { connect, availableWallets } = useWallet();\n const [connecting, setConnecting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleConnect = async (walletId: string) => {\n setConnecting(true);\n setError(null);\n try {\n await connect(walletId);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : \"连接失败\");\n } finally {\n setConnecting(false);\n }\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n // Predefine icons/colors for known wallets or use generic\n const getWalletIcon = (id: string) => {\n // Allow flexible icon rendering. For now, simple colored squares or letters.\n // In a real app, these would be proper SVGs or helper components.\n if (id === \"metamask\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-orange-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-orange-500\">\n 🦊\n </div>\n );\n if (id === \"okx\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-black wjb-flex wjb-items-center wjb-justify-center wjb-text-white\">\n X\n </div>\n );\n if (id === \"phantom\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-purple-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-purple-500\">\n P\n </div>\n );\n if (id === \"coinbase\")\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-blue-100 wjb-flex wjb-items-center wjb-justify-center wjb-text-blue-500\">\n C\n </div>\n );\n return (\n <div className=\"wjb-w-8 wjb-h-8 wjb-rounded-lg wjb-bg-gray-200\"></div>\n );\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-wallet-modal-content\">\n {/* Left Side: Wallet List */}\n <div className=\"wjb-modal-left\">\n <div className=\"wjb-modal-header\">\n <h2 className=\"wjb-modal-title\">连接钱包</h2>\n {/* Mobile close button could go here, but omitted for clean desktop design or added if needed */}\n </div>\n\n <div className=\"wjb-wallet-list\">\n {/* Installed Wallets */}\n {availableWallets.map((wallet) => (\n <button\n key={wallet.id}\n onClick={() => handleConnect(wallet.id)}\n disabled={connecting}\n className=\"wjb-wallet-option\"\n >\n {getWalletIcon(wallet.id)}\n <span className=\"wjb-flex-1\">{wallet.name}</span>\n {connecting && (\n <span className=\"wjb-text-xs wjb-text-blue-500 wjb-animate-pulse\">\n 连接中...\n </span>\n )}\n </button>\n ))}\n\n {/* Uninstalled Wallets */}\n {walletRegistry\n .filter((w) => !w.isInstalled())\n .map((wallet) => {\n const info = wallet.getInfo();\n return (\n <a\n key={info.id}\n href={info.downloadUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"wjb-wallet-option wjb-opacity-60 wjb-hover:opacity-100\"\n >\n {getWalletIcon(info.id)}\n <span className=\"wjb-flex-1\">{info.name}</span>\n <span className=\"wjb-text-xs wjb-font-bold wjb-text-blue-500 wjb-bg-blue-50 wjb-px-2 wjb-py-1 wjb-rounded\">\n 安装\n </span>\n </a>\n );\n })}\n </div>\n\n {error && (\n <div className=\"wjb-mt-4 wjb-p-3 wjb-bg-red-50 wjb-text-red-500 wjb-text-sm wjb-rounded-xl\">\n {error}\n </div>\n )}\n </div>\n\n {/* Right Side: Education / Info */}\n <div className=\"wjb-modal-right hidden md:flex\">\n {/* Icon Grid Placeholder */}\n <div className=\"wjb-grid wjb-grid-cols-2 wjb-gap-4 wjb-mb-6 wjb-opacity-80\">\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-blue-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-6\"></div>\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-purple-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-12\"></div>\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-orange-500 wjb-rounded-xl wjb-shadow-lg wjb-rotate-6\"></div>\n <div className=\"wjb-w-12 wjb-h-12 wjb-bg-green-500 wjb-rounded-xl wjb-shadow-lg wjb--rotate-12\"></div>\n </div>\n\n <h3 className=\"wjb-text-lg wjb-font-bold wjb-text-gray-900 wjb-dark:text-white wjb-mb-2\">\n 什么是钱包?\n </h3>\n <ul className=\"wjb-text-sm wjb-text-gray-500 wjb-dark:text-gray-400 wjb-space-y-3 wjb-text-left wjb-max-w-xs\">\n <li className=\"wjb-flex wjb-items-start wjb-gap-2\">\n <span className=\"wjb-mt-1\">🏠</span>\n <span>\n 您的数字资产之家\n <br />\n 发送、接收和存储资产。\n </span>\n </li>\n <li className=\"wjb-flex wjb-items-start wjb-gap-2\">\n <span className=\"wjb-mt-1\">🔐</span>\n <span>\n 一种新的登录方式\n <br />\n 无需创建账户和密码。\n </span>\n </li>\n </ul>\n\n <button className=\"wjb-mt-6 wjb-px-4 wjb-py-2 wjb-bg-gray-200 wjb-dark:bg-gray-700 wjb-rounded-lg wjb-text-sm wjb-font-bold wjb-text-gray-700 wjb-dark:text-white wjb-hover:bg-gray-300 wjb-transition-colors\">\n 了解更多\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useRef, useEffect } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\n\ninterface ChainSwitcherProps {\n onClose: () => void;\n}\n\nexport function ChainSwitcher({ onClose }: ChainSwitcherProps) {\n const { supportedChains, switchChain, state } = useWallet();\n // We can use a backdrop for mobile, or click outside for desktop dropdown\n const handleSwitch = async (chainId: string) => {\n if (state.chainId !== chainId) {\n await switchChain(chainId);\n }\n onClose();\n };\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) onClose();\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-chain-switcher-content\">\n <div className=\"wjb-p-4 wjb-border-b wjb-border-gray-100 wjb-dark:border-gray-800 wjb-flex wjb-justify-between wjb-items-center\">\n <h3 className=\"wjb-font-bold wjb-text-gray-900 wjb-dark:text-white\">\n 切换网络\n </h3>\n <button onClick={onClose} className=\"wjb-chain-modal-close\">\n ✕\n </button>\n </div>\n\n <div className=\"wjb-p-2 wjb-space-y-1\">\n {supportedChains.map((chain) => (\n <button\n key={chain.chainId}\n onClick={() => handleSwitch(chain.chainId)}\n className={`wjb-chain-option ${state.chainId === chain.chainId ? \"active\" : \"\"}`}\n >\n <div className=\"wjb-flex wjb-items-center\">\n {/* Chain Icons */}\n <div\n className={`wjb-chain-icon wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-xs ${\n chain.chainId === \"0x1\"\n ? \"wjb-bg-blue-500\"\n : \"wjb-bg-purple-500\"\n }`}\n >\n {chain.chainName[0]}\n </div>\n <span>{chain.chainName}</span>\n </div>\n\n {state.chainId === chain.chainId && (\n <span className=\"wjb-text-sm wjb-font-bold wjb-text-green-500\">\n 已连接\n </span>\n )}\n </button>\n ))}\n </div>\n </div>\n </div>\n );\n}\n","/**\n * Format balance from hex/wei to formatted string\n */\nexport function formatBalance(rawBalance: string | undefined): string {\n if (!rawBalance || rawBalance === \"0x0\") return \"0 ETH\";\n\n try {\n const hex = rawBalance.startsWith(\"0x\") ? rawBalance : `0x${rawBalance}`;\n const wei = BigInt(hex);\n // Rough conversion to ETH (18 decimals), keeping 4 decimal places\n const divisor = 1000000000000000000n;\n const integerPart = wei / divisor;\n const remainder = wei % divisor;\n\n // Convert remainder to decimal string padded with zeros\n const decimals = remainder.toString().padStart(18, \"0\").slice(0, 4);\n\n // Remove trailing zeros if any\n const formattedDecimals = decimals.replace(/0+$/, \"\");\n\n return formattedDecimals\n ? `${integerPart}.${formattedDecimals} ETH`\n : `${integerPart} ETH`;\n } catch (error) {\n console.error(\"Error formatting balance:\", error);\n return \"0 ETH\";\n }\n}\n\n/**\n * Format address to short form 0x...1234\n */\nexport function formatAddress(address: string | null | undefined): string {\n if (!address) return \"\";\n return `${address.slice(0, 6)}...${address.slice(-4)}`;\n}\n","import React from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { formatAddress } from \"../utils/format\";\n\ninterface AccountModalProps {\n onClose: () => void;\n}\n\nexport function AccountModal({ onClose }: AccountModalProps) {\n const { state, disconnect } = useWallet();\n const { account, balance } = state;\n\n const handleCopy = async () => {\n if (account) {\n await navigator.clipboard.writeText(account);\n // Could add toast here\n }\n };\n\n const handleDisconnect = async () => {\n await disconnect();\n onClose();\n };\n\n // Close when clicking overlay\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n return (\n <div className=\"wjb-modal-overlay\" onClick={handleBackdropClick}>\n <div className=\"wjb-account-modal-content\">\n <button onClick={onClose} className=\"wjb-account-modal-close\">\n ✕\n </button>\n\n <div className=\"wjb-account-avatar-large\" />\n\n <div className=\"wjb-account-address-large\">\n {formatAddress(account)}\n </div>\n\n <div className=\"wjb-account-balance-large\">\n {state.balance || \"0 ETH\"}\n {/* Fallback not really needed if state init correct, but safe */}\n </div>\n\n <div className=\"wjb-account-actions\">\n <button onClick={handleCopy} className=\"wjb-action-button\">\n {/* Copy Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\" />\n <path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\" />\n </svg>\n 复制地址\n </button>\n\n <button\n onClick={handleDisconnect}\n className=\"wjb-action-button wjb-text-red-500 wjb-hover:text-red-600\"\n >\n {/* Disconnect Icon */}\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\" />\n </svg>\n 断开连接\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from \"react\";\nimport { useWallet } from \"../hooks/useWallet\";\nimport { WalletModal } from \"./WalletModal\";\nimport { ChainSwitcher } from \"./ChainSwitcher\";\nimport { AccountModal } from \"./AccountModal\"; // Import new component\nimport { formatAddress, formatBalance } from \"../utils/format\";\n\nexport function ConnectButton() {\n const { state } = useWallet();\n const [showWalletModal, setShowWalletModal] = useState(false);\n const [showChainSwitcher, setShowChainSwitcher] = useState(false);\n const [showAccountModal, setShowAccountModal] = useState(false);\n\n if (!state.isConnected) {\n return (\n <>\n <button\n onClick={() => setShowWalletModal(true)}\n className=\"wjb-connect-button wjb-connect-button-primary\"\n >\n 连接钱包\n </button>\n {showWalletModal && (\n <WalletModal onClose={() => setShowWalletModal(false)} />\n )}\n </>\n );\n }\n\n return (\n <>\n <div className=\"wjb-wallet-connected\">\n <div className=\"wjb-wallet-info-group\">\n {/* Chain Switcher Trigger */}\n <button\n onClick={() => setShowChainSwitcher(true)}\n className=\"wjb-chain-button\"\n >\n {/* Simple Chain Icon Placeholder or check ChainID */}\n <div\n className={`wjb-w-5 wjb-h-5 wjb-rounded-full ${\n state.chainId === \"0x1\"\n ? \"wjb-bg-blue-500\"\n : state.chainId === \"0xaa36a7\"\n ? \"wjb-bg-purple-500\"\n : \"wjb-bg-gray-500\"\n } wjb-flex wjb-items-center wjb-justify-center wjb-text-white wjb-text-[10px]`}\n >\n {state.chainId === \"0x1\"\n ? \"E\"\n : state.chainId === \"0xaa36a7\"\n ? \"S\"\n : \"?\"}\n </div>\n <span>\n {state.chainId === \"0x1\" && \"Ethereum\"}\n {state.chainId === \"0xaa36a7\" && \"Sepolia\"}\n {state.chainId &&\n state.chainId !== \"0x1\" &&\n state.chainId !== \"0xaa36a7\" &&\n \"Unknown\"}\n </span>\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"wjb-text-gray-400\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n\n {/* Balance Display */}\n <div className=\"wjb-balance\">\n {state.balance ? formatBalance(state.balance) : \"0 ETH\"}\n </div>\n\n {/* Account Button */}\n <button\n onClick={() => setShowAccountModal(true)}\n className=\"wjb-account-button\"\n >\n <span>{state.account && formatAddress(state.account)}</span>\n <div className=\"wjb-account-avatar\" />\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n className=\"wjb-text-gray-400 wjb-ml-1\"\n >\n <path\n d=\"M2.5 4.5L6 8L9.5 4.5\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n {showChainSwitcher && (\n <ChainSwitcher onClose={() => setShowChainSwitcher(false)} />\n )}\n\n {showAccountModal && (\n <AccountModal onClose={() => setShowAccountModal(false)} />\n )}\n </>\n );\n}\n"],"names":["WalletContext","createContext","WalletError","Error","constructor","message","code","data","super","Object","defineProperty","this","name","ErrorCode","USER_REJECTED","UNAUTHORIZED","UNSUPPORTED_METHOD","DISCONNECTED","CHAIN_DISCONNECTED","UNRECOGNIZED_CHAIN","INVALID_PARAMS","INTERNAL_ERROR","PROVIDER_NOT_FOUND","WALLET_NOT_INSTALLED","ALREADY_CONNECTED","createWalletError","parseProviderError","error","err","BaseWallet","value","Map","accounts","emit","chainId","cleanup","connect","isInstalled","getInfo","provider","getProvider","setupEventListeners","request","method","length","disconnect","getAccounts","console","getBalance","address","params","getChainId","switchChain","chain","isUnrecognizedChainError","chainName","nativeCurrency","rpcUrls","blockExplorerUrls","iconUrls","addError","on","event","listener","eventListeners","has","set","Set","get","add","off","listeners","delete","args","handleAccountsChanged","handleChainChanged","handleDisconnect","removeListener","clear","forEach","MetaMaskWallet","id","downloadUrl","window","Boolean","ethereum","isMetaMask","OKXWallet","okxwallet","PhantomWallet","phantom","CoinbaseWallet","coinbaseWalletExtension","walletRegistry","getWalletById","find","wallet","mainnet","symbol","decimals","sepolia","defaultChains","STORAGE_KEY","WalletProvider","children","config","chains","autoConnect","state","setState","useState","isConnected","account","balance","currentWallet","setCurrentWallet","availableWallets","useMemo","filter","map","useCallback","async","prev","walletId","walletInfo","accountList","newAccount","newBalance","currentAccount","localStorage","setItem","JSON","stringify","removeItem","toLowerCase","getChainById","useEffect","stored","getItem","parse","retryCount","Promise","resolve","setTimeout","attemptAutoConnect","supportedChains","_jsx","Provider","useWallet","context","useContext","WalletModal","onClose","connecting","setConnecting","setError","getWalletIcon","className","onClick","e","target","currentTarget","_jsxs","handleConnect","disabled","w","info","href","rel","ChainSwitcher","handleSwitch","formatBalance","rawBalance","hex","startsWith","wei","BigInt","divisor","integerPart","formattedDecimals","toString","padStart","slice","replace","formatAddress","AccountModal","navigator","clipboard","writeText","width","height","viewBox","fill","stroke","strokeWidth","x","y","rx","ry","d","points","x1","y1","x2","y2","ConnectButton","showWalletModal","setShowWalletModal","showChainSwitcher","setShowChainSwitcher","showAccountModal","setShowAccountModal","_Fragment","strokeLinecap","strokeLinejoin"],"mappings":"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"}
@@ -1 +1 @@
1
- .wjb-connect-button{border-radius:.75rem;font-weight:700;padding:.625rem 1rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-connect-button:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-offset-width:2px;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);outline:2px solid transparent;outline-offset:2px}.wjb-connect-button{align-items:center;cursor:pointer;display:flex;gap:.5rem;justify-content:center}.wjb-connect-button-primary{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.wjb-connect-button-primary:hover{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.wjb-connect-button-primary{--tw-text-opacity:1;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);background:linear-gradient(90deg,#3b82f6,#2563eb);color:rgb(255 255 255/var(--tw-text-opacity,1))}.wjb-connect-button-primary,.wjb-connect-button-primary:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.wjb-connect-button-primary:hover{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-scale-x:1.02;--tw-scale-y:1.02}.wjb-connect-button-primary:active,.wjb-connect-button-primary:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.wjb-connect-button-primary:active{--tw-scale-x:0.98;--tw-scale-y:0.98}.wjb-connect-button-primary:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.wjb-wallet-connected{align-items:center;display:flex;gap:.75rem}.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-color:rgb(229 231 235/var(--tw-border-opacity,1));border-radius:.75rem;border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);display:flex;padding:.25rem}@media (prefers-color-scheme:dark){.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1));border-color:rgb(55 65 81/var(--tw-border-opacity,1))}}.wjb-chain-button{align-items:center;border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;padding:.375rem .75rem}.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-chain-button{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-chain-button{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}}.wjb-balance{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));display:none;font-size:.875rem;font-weight:500;line-height:1.25rem;padding-left:.75rem;padding-right:.75rem}@media (min-width:640px){.wjb-balance{display:block}}@media (prefers-color-scheme:dark){.wjb-balance{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}}.wjb-account-button{--tw-bg-opacity:1;align-items:center;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;margin-left:.25rem;padding:.375rem .75rem}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity,1))}}.wjb-account-button{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-avatar{--tw-shadow:inset 0 2px 4px 0 rgba(0,0,0,.05);--tw-shadow-colored:inset 0 2px 4px 0 var(--tw-shadow-color);background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:1.5rem;width:1.5rem}.wjb-modal-overlay{--tw-backdrop-blur:blur(2px);align-items:center;animation:fade-in .2s ease-out;backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);background-color:rgba(0,0,0,.4);display:flex;inset:0;justify-content:center;padding:1rem;position:fixed;z-index:50}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.wjb-modal-overlay{animation:fadeIn .2s ease-in-out}.wjb-wallet-modal-content{--tw-bg-opacity:1;--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (prefers-color-scheme:dark){.wjb-wallet-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-wallet-modal-content{display:flex;flex-direction:column;max-width:48rem;overflow:hidden;width:100%}@media (min-width:768px){.wjb-wallet-modal-content{flex-direction:row}}.wjb-wallet-modal-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-modal-left{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(243 244 246/var(--tw-border-opacity,1));padding:1.5rem;width:100%}@media (min-width:768px){.wjb-modal-left{border-bottom-width:0;border-right-width:1px;width:20rem}}@media (prefers-color-scheme:dark){.wjb-modal-left{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}}.wjb-modal-right{--tw-bg-opacity:1;align-items:center;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));display:flex;flex:1 1 0%;flex-direction:column;justify-content:center;padding:1.5rem;text-align:center}@media (prefers-color-scheme:dark){.wjb-modal-right{background-color:rgba(31,41,55,.5)}}.wjb-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:1rem}.wjb-modal-title{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.125rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-modal-title{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-wallet-list>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.wjb-wallet-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;gap:.75rem;padding:.75rem 1rem;width:100%}.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-wallet-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:700;text-align:left;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-wallet-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-switcher-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:.5rem;width:20rem}@media (prefers-color-scheme:dark){.wjb-chain-switcher-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-chain-switcher-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-chain-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;justify-content:space-between;padding:.75rem 1rem;width:100%}.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-chain-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-chain-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-option{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-chain-option.active{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1));color:rgb(59 130 246/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option.active{background-color:rgba(30,58,138,.1)}}.wjb-chain-icon{border-radius:9999px;height:1.5rem;margin-right:.75rem;width:1.5rem}.wjb-account-modal-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:2rem;text-align:center;width:20rem}@media (prefers-color-scheme:dark){.wjb-account-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-account-modal-content{align-items:center;animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out;display:flex;flex-direction:column;gap:1rem;position:relative}.wjb-account-modal-close{--tw-text-opacity:1;border-radius:9999px;color:rgb(156 163 175/var(--tw-text-opacity,1));cursor:pointer;padding:.5rem;position:absolute;right:1rem;top:1rem}.wjb-account-modal-close:hover{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));color:rgb(75 85 99/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-modal-close:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-account-avatar-large{background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;height:5rem;margin-bottom:.5rem;width:5rem}.wjb-account-address-large{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.25rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-account-address-large{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-account-actions{display:flex;gap:.75rem;margin-top:1rem;width:100%}.wjb-action-button{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;flex:1 1 0%;flex-direction:column;gap:.5rem;padding:.75rem}.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-action-button{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1));font-size:.75rem;font-weight:500;line-height:1rem}@media (prefers-color-scheme:dark){.wjb-action-button{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-action-button{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes scale-up{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}.mb-2{margin-bottom:.5rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-12{height:3rem}.h-5{height:1.25rem}.h-8{height:2rem}.w-12{width:3rem}.w-5{width:1.25rem}.w-8{width:2rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.-rotate-12{--tw-rotate:-12deg}.-rotate-12,.-rotate-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-6{--tw-rotate:-6deg}.rotate-12{--tw-rotate:12deg}.rotate-12,.rotate-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-6{--tw-rotate:6deg}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-4{gap:1rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.25rem*var(--tw-space-y-reverse));margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border-b{border-bottom-width:1px}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity,1))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(219 234 254/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity,1))}.bg-green-500{--tw-bg-opacity:1;background-color:rgb(34 197 94/var(--tw-bg-opacity,1))}.bg-orange-100{--tw-bg-opacity:1;background-color:rgb(255 237 213/var(--tw-bg-opacity,1))}.bg-orange-500{--tw-bg-opacity:1;background-color:rgb(249 115 22/var(--tw-bg-opacity,1))}.bg-purple-100{--tw-bg-opacity:1;background-color:rgb(243 232 255/var(--tw-bg-opacity,1))}.bg-purple-500{--tw-bg-opacity:1;background-color:rgb(168 85 247/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.text-left{text-align:left}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-green-500{--tw-text-opacity:1;color:rgb(34 197 94/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-purple-500{--tw-text-opacity:1;color:rgb(168 85 247/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.opacity-60{opacity:.6}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:bg-gray-300:hover{--tw-bg-opacity:1;background-color:rgb(209 213 219/var(--tw-bg-opacity,1))}.hover\:text-red-600:hover{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.hover\:opacity-100:hover{opacity:1}@media (min-width:768px){.md\:flex{display:flex}}@media (prefers-color-scheme:dark){.dark\:border-gray-800{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}.dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}.dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}
1
+ .wjb-connect-button{border-radius:.75rem;font-weight:700;padding:.625rem 1rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-connect-button:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);--tw-ring-offset-width:2px;box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);outline:2px solid transparent;outline-offset:2px}.wjb-connect-button{align-items:center;cursor:pointer;display:flex;gap:.5rem;justify-content:center}.wjb-connect-button-primary{--tw-bg-opacity:1;background-color:rgb(59 130 246/var(--tw-bg-opacity,1))}.wjb-connect-button-primary:hover{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.wjb-connect-button-primary{--tw-text-opacity:1;--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);background:linear-gradient(90deg,#3b82f6,#2563eb);color:rgb(255 255 255/var(--tw-text-opacity,1))}.wjb-connect-button-primary,.wjb-connect-button-primary:hover{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.wjb-connect-button-primary:hover{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color);--tw-scale-x:1.02;--tw-scale-y:1.02}.wjb-connect-button-primary:active,.wjb-connect-button-primary:hover{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.wjb-connect-button-primary:active{--tw-scale-x:0.98;--tw-scale-y:0.98}.wjb-connect-button-primary:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.wjb-wallet-connected{align-items:center;display:flex;gap:.75rem}.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);align-items:center;background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-color:rgb(229 231 235/var(--tw-border-opacity,1));border-radius:.75rem;border-width:1px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);display:flex;padding:.25rem}@media (prefers-color-scheme:dark){.wjb-wallet-info-group{--tw-border-opacity:1;--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1));border-color:rgb(55 65 81/var(--tw-border-opacity,1))}}.wjb-chain-button{align-items:center;border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;padding:.375rem .75rem}.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-button:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-chain-button{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-chain-button{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity,1))}}.wjb-balance{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));display:none;font-size:.875rem;font-weight:500;line-height:1.25rem;padding-left:.75rem;padding-right:.75rem}@media (min-width:640px){.wjb-balance{display:block}}@media (prefers-color-scheme:dark){.wjb-balance{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity,1))}}.wjb-account-button{--tw-bg-opacity:1;align-items:center;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));border-radius:.5rem;cursor:pointer;display:flex;gap:.5rem;margin-left:.25rem;padding:.375rem .75rem}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}}.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-button:hover{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity,1))}}.wjb-account-button{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:.875rem;font-weight:700;line-height:1.25rem;transition-duration:.2s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-account-button{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-avatar{--tw-shadow:inset 0 2px 4px 0 rgba(0,0,0,.05);--tw-shadow-colored:inset 0 2px 4px 0 var(--tw-shadow-color);background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);height:1.5rem;width:1.5rem}.wjb-modal-overlay{--tw-backdrop-blur:blur(2px);align-items:center;animation:fade-in .2s ease-out;backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);background-color:rgba(0,0,0,.4);display:flex;inset:0;justify-content:center;padding:1rem;position:fixed;z-index:50}.wjb-wallet-modal-content{--tw-bg-opacity:1;--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}@media (prefers-color-scheme:dark){.wjb-wallet-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-wallet-modal-content{display:flex;flex-direction:column;max-width:48rem;overflow:hidden;width:100%}@media (min-width:768px){.wjb-wallet-modal-content{flex-direction:row}}.wjb-wallet-modal-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-modal-left{--tw-border-opacity:1;border-bottom-width:1px;border-color:rgb(243 244 246/var(--tw-border-opacity,1));padding:1.5rem;width:100%}@media (min-width:768px){.wjb-modal-left{border-bottom-width:0;border-right-width:1px;width:20rem}}@media (prefers-color-scheme:dark){.wjb-modal-left{--tw-border-opacity:1;border-color:rgb(31 41 55/var(--tw-border-opacity,1))}}.wjb-modal-right{--tw-bg-opacity:1;align-items:center;background-color:rgb(249 250 251/var(--tw-bg-opacity,1));display:flex;flex:1 1 0%;flex-direction:column;justify-content:center;padding:1.5rem;text-align:center}@media (prefers-color-scheme:dark){.wjb-modal-right{background-color:rgba(31,41,55,.5)}}.wjb-modal-header{align-items:center;display:flex;justify-content:space-between;margin-bottom:1rem}.wjb-modal-title{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.125rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-modal-title{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-wallet-list>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.wjb-wallet-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;gap:.75rem;padding:.75rem 1rem;width:100%}.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-wallet-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-wallet-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:700;text-align:left;transition-duration:.2s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@media (prefers-color-scheme:dark){.wjb-wallet-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-switcher-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:.5rem;width:20rem}@media (prefers-color-scheme:dark){.wjb-chain-switcher-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-chain-switcher-content{animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out}.wjb-chain-option{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;justify-content:space-between;padding:.75rem 1rem;width:100%}.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-chain-option{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-chain-option{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-chain-option{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.wjb-chain-option.active{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1));color:rgb(59 130 246/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-option.active{background-color:rgba(30,58,138,.1)}}.wjb-chain-icon{border-radius:9999px;height:1.5rem;margin-right:.75rem;width:1.5rem}.wjb-chain-modal-close{--tw-text-opacity:1;border-radius:9999px;color:rgb(156 163 175/var(--tw-text-opacity,1));cursor:pointer;padding:.5rem}.wjb-chain-modal-close:hover{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));color:rgb(75 85 99/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-chain-modal-close:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-account-modal-content{--tw-bg-opacity:1;--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);background-color:rgb(255 255 255/var(--tw-bg-opacity,1));border-radius:1.5rem;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);padding:2rem;text-align:center;width:20rem}@media (prefers-color-scheme:dark){.wjb-account-modal-content{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity,1))}}.wjb-account-modal-content{align-items:center;animation:scale-up cubic-bezier(.16,1,.3,1) .2s ease-out;display:flex;flex-direction:column;gap:1rem;position:relative}.wjb-account-modal-close{--tw-text-opacity:1;border-radius:9999px;color:rgb(156 163 175/var(--tw-text-opacity,1));cursor:pointer;padding:.5rem;position:absolute;right:1rem;top:1rem}.wjb-account-modal-close:hover{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1));color:rgb(75 85 99/var(--tw-text-opacity,1))}@media (prefers-color-scheme:dark){.wjb-account-modal-close:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-account-avatar-large{background:linear-gradient(to bottom right,#60a5fa,#a855f7);border-radius:9999px;height:5rem;margin-bottom:.5rem;width:5rem}.wjb-account-address-large{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1));font-size:1.25rem;font-weight:700;line-height:1.75rem}@media (prefers-color-scheme:dark){.wjb-account-address-large{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}}.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity,1));font-weight:500}@media (prefers-color-scheme:dark){.wjb-account-balance-large{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-account-actions{display:flex;gap:.75rem;margin-top:1rem;width:100%}.wjb-action-button{align-items:center;border-radius:.75rem;cursor:pointer;display:flex;flex:1 1 0%;flex-direction:column;gap:.5rem;padding:.75rem}.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity,1))}@media (prefers-color-scheme:dark){.wjb-action-button:hover{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity,1))}}.wjb-action-button{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1));font-size:.75rem;font-weight:500;line-height:1rem}@media (prefers-color-scheme:dark){.wjb-action-button{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity,1))}}.wjb-action-button{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes scale-up{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}
@@ -1 +1 @@
1
- {"version":3,"file":"ChainSwitcher.d.ts","sourceRoot":"","sources":["../../../src/components/ChainSwitcher.tsx"],"names":[],"mappings":"AAGA,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CAoD5D"}
1
+ {"version":3,"file":"ChainSwitcher.d.ts","sourceRoot":"","sources":["../../../src/components/ChainSwitcher.tsx"],"names":[],"mappings":"AAGA,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CA0D5D"}
@@ -1 +1 @@
1
- {"version":3,"file":"WalletModal.d.ts","sourceRoot":"","sources":["../../../src/components/WalletModal.tsx"],"names":[],"mappings":"AAIA,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAuJxD"}
1
+ {"version":3,"file":"WalletModal.d.ts","sourceRoot":"","sources":["../../../src/components/WalletModal.tsx"],"names":[],"mappings":"AAIA,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAyJxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wangjinbao/wallet-connect",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "A React wallet connection library supporting MetaMask, OKX Wallet, Phantom, and Coinbase Wallet",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",