@monygroupcorp/micro-web3 0.1.0 → 0.1.3
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/README.md +14 -0
- package/dist/micro-web3.cjs.js +2 -2
- package/dist/micro-web3.cjs.js.map +1 -1
- package/dist/micro-web3.esm.js +2 -2
- package/dist/micro-web3.esm.js.map +1 -1
- package/dist/micro-web3.umd.js +2 -2
- package/dist/micro-web3.umd.js.map +1 -1
- package/monygroupcorp-micro-web3-0.1.3.tgz +0 -0
- package/package.json +1 -1
- package/rollup.config.cjs +2 -2
- package/src/components/FloatingWalletButton/FloatingWalletButton.css +227 -0
- package/src/components/FloatingWalletButton/FloatingWalletButton.js +680 -0
- package/src/components/WalletButton/WalletButton.js +213 -0
- package/src/index.js +5 -3
- package/src/services/BlockchainService.js +6 -6
- package/src/services/WETHService.js +52 -0
- package/src/services/WalletService.js +2 -1
- package/src/components/Wallet/WalletSplash.js +0 -567
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { FloatingWalletButton } from '../FloatingWalletButton/FloatingWalletButton.js';
|
|
2
|
+
import WalletModal from '../Wallet/WalletModal.js';
|
|
3
|
+
|
|
4
|
+
class WalletButtonModal extends WalletModal {
|
|
5
|
+
events() {
|
|
6
|
+
const baseEvents = typeof super.events === 'function' ? super.events() : {};
|
|
7
|
+
return {
|
|
8
|
+
...baseEvents,
|
|
9
|
+
'click .wallet-option': async (e) => {
|
|
10
|
+
const button = e?.target?.closest?.('.wallet-option');
|
|
11
|
+
const walletType = button?.dataset?.wallet;
|
|
12
|
+
if (!walletType) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (this.onWalletSelected) {
|
|
16
|
+
await this.onWalletSelected(walletType);
|
|
17
|
+
}
|
|
18
|
+
this.hide();
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class WalletButton extends FloatingWalletButton {
|
|
25
|
+
constructor(props) {
|
|
26
|
+
super(props);
|
|
27
|
+
this.modalRoot = null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async showWalletModal() {
|
|
31
|
+
const providerMap =
|
|
32
|
+
this.walletService?.providerMap ||
|
|
33
|
+
{
|
|
34
|
+
rabby: () => (window.ethereum?.isRabby ? window.ethereum : null),
|
|
35
|
+
rainbow: () => (window.ethereum?.isRainbow ? window.ethereum : null),
|
|
36
|
+
phantom: () => window.phantom?.ethereum || null,
|
|
37
|
+
metamask: () => window.ethereum || null,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const walletIcons =
|
|
41
|
+
this.walletService?.walletIcons ||
|
|
42
|
+
{
|
|
43
|
+
rabby: '/public/wallets/rabby.webp',
|
|
44
|
+
rainbow: '/public/wallets/rainbow.webp',
|
|
45
|
+
phantom: '/public/wallets/phantom.webp',
|
|
46
|
+
metamask: '/public/wallets/MetaMask.webp',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
if (!this.walletModal) {
|
|
50
|
+
this.walletModal = new WalletButtonModal({
|
|
51
|
+
providerMap,
|
|
52
|
+
walletIcons,
|
|
53
|
+
onWalletSelected: async (walletType) => {
|
|
54
|
+
await this.handleWalletSelection(walletType);
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (!this.modalRoot) {
|
|
59
|
+
this.modalRoot = document.createElement('div');
|
|
60
|
+
document.body.appendChild(this.modalRoot);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.walletModal.mount(this.modalRoot);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.walletModal.show();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onUnmount() {
|
|
70
|
+
if (this.modalRoot?.parentNode) {
|
|
71
|
+
this.modalRoot.parentNode.removeChild(this.modalRoot);
|
|
72
|
+
this.modalRoot = null;
|
|
73
|
+
}
|
|
74
|
+
super.onUnmount();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
render() {
|
|
78
|
+
if (this.state.loading) {
|
|
79
|
+
return `
|
|
80
|
+
<div class="floating-wallet-button loading">
|
|
81
|
+
<div class="wallet-spinner"></div>
|
|
82
|
+
</div>
|
|
83
|
+
`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const { walletConnected, address, balance, menuOpen } = this.state;
|
|
87
|
+
|
|
88
|
+
if (!walletConnected) {
|
|
89
|
+
return `
|
|
90
|
+
<div class="floating-wallet-button disconnected" data-ref="wallet-button">
|
|
91
|
+
<button class="wallet-btn" data-ref="connect-btn">
|
|
92
|
+
<span class="wallet-mark"></span>
|
|
93
|
+
<span class="wallet-text">Connect Wallet</span>
|
|
94
|
+
</button>
|
|
95
|
+
</div>
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const truncatedAddress = `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
100
|
+
const classNames = ['floating-wallet-button', 'connected'];
|
|
101
|
+
if (menuOpen) {
|
|
102
|
+
classNames.push('menu-open');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const markup = `
|
|
106
|
+
<div class="${classNames.join(' ')}" data-ref="wallet-button">
|
|
107
|
+
<button class="wallet-btn" data-ref="wallet-btn" title="${this.escapeHtml(address)}\nBalance: ${balance} ETH">
|
|
108
|
+
<span class="wallet-mark wallet-mark--connected"></span>
|
|
109
|
+
<span class="wallet-address">${this.escapeHtml(truncatedAddress)}</span>
|
|
110
|
+
<span class="wallet-disconnect" data-ref="inline-disconnect" title="Disconnect">⏏︎</span>
|
|
111
|
+
</button>
|
|
112
|
+
${this.renderWalletPanel(address, balance, menuOpen)}
|
|
113
|
+
</div>
|
|
114
|
+
`;
|
|
115
|
+
|
|
116
|
+
return this.minifyHtml(markup);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
events() {
|
|
120
|
+
const baseEvents = super.events?.() || {};
|
|
121
|
+
return {
|
|
122
|
+
...baseEvents,
|
|
123
|
+
'click [data-ref="inline-disconnect"]': (e) => this.handleInlineDisconnect(e),
|
|
124
|
+
'click [data-ref="wallet-btn"]': (e) => this.handleWalletToggle(e),
|
|
125
|
+
'click [data-ref="connect-btn"]': (e) => this.handleWalletToggle(e),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
renderWalletPanel(address, balance, menuOpen) {
|
|
130
|
+
const truncatedAddress = `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
131
|
+
|
|
132
|
+
const markup = `
|
|
133
|
+
<div class="wallet-info-panel" data-ref="wallet-panel" aria-hidden="${menuOpen ? 'false' : 'true'}">
|
|
134
|
+
<div class="wallet-info-row">
|
|
135
|
+
<span class="wallet-info-label">Address</span>
|
|
136
|
+
<span class="wallet-info-value">${this.escapeHtml(truncatedAddress)}</span>
|
|
137
|
+
</div>
|
|
138
|
+
<div class="wallet-info-row">
|
|
139
|
+
<span class="wallet-info-label">ETH Balance</span>
|
|
140
|
+
<span class="wallet-info-value">${balance} ETH</span>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
`;
|
|
144
|
+
|
|
145
|
+
return this.minifyHtml(markup);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
onStateUpdate(oldState, newState) {
|
|
149
|
+
if (typeof super.onStateUpdate === 'function') {
|
|
150
|
+
super.onStateUpdate(oldState, newState);
|
|
151
|
+
}
|
|
152
|
+
if (!oldState || oldState.menuOpen !== newState.menuOpen) {
|
|
153
|
+
if (newState.menuOpen) {
|
|
154
|
+
this.attachOutsideClickListener();
|
|
155
|
+
} else {
|
|
156
|
+
this.detachOutsideClickListener();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
attachOutsideClickListener() {
|
|
162
|
+
if (this.outsideClickHandler || this.outsideClickTimeout) return;
|
|
163
|
+
this.outsideClickHandler = (event) => {
|
|
164
|
+
if (!this.element) return;
|
|
165
|
+
const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
166
|
+
const clickedInside =
|
|
167
|
+
(path.length && path.includes(this.element)) ||
|
|
168
|
+
(event.target && this.element.contains(event.target));
|
|
169
|
+
if (!clickedInside) {
|
|
170
|
+
this.setState({ menuOpen: false });
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
this.outsideClickTimeout = window.setTimeout(() => {
|
|
174
|
+
document.addEventListener('click', this.outsideClickHandler);
|
|
175
|
+
this.outsideClickTimeout = null;
|
|
176
|
+
}, 0);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
detachOutsideClickListener() {
|
|
180
|
+
if (this.outsideClickTimeout) {
|
|
181
|
+
window.clearTimeout(this.outsideClickTimeout);
|
|
182
|
+
this.outsideClickTimeout = null;
|
|
183
|
+
}
|
|
184
|
+
if (this.outsideClickHandler) {
|
|
185
|
+
document.removeEventListener('click', this.outsideClickHandler);
|
|
186
|
+
this.outsideClickHandler = null;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
setupDOMEventListeners() {
|
|
191
|
+
// Delegated events handle wiring in this component.
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
handleWalletToggle(e) {
|
|
195
|
+
this.handleButtonClick(e);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
handleInlineDisconnect(e) {
|
|
199
|
+
if (e) {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
e.stopPropagation();
|
|
202
|
+
}
|
|
203
|
+
super.handleDisconnect(e);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
minifyHtml(markup) {
|
|
207
|
+
return typeof markup === 'string'
|
|
208
|
+
? markup.replace(/>\s+</g, '><').trim()
|
|
209
|
+
: markup;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export default WalletButton;
|
package/src/index.js
CHANGED
|
@@ -6,7 +6,8 @@ import PriceService from './services/PriceService.js';
|
|
|
6
6
|
import * as IpfsService from './services/IpfsService.js';
|
|
7
7
|
|
|
8
8
|
// UI Components
|
|
9
|
-
import {
|
|
9
|
+
import { FloatingWalletButton } from './components/FloatingWalletButton/FloatingWalletButton.js';
|
|
10
|
+
import { WalletButton } from './components/WalletButton/WalletButton.js';
|
|
10
11
|
import { WalletModal } from './components/Wallet/WalletModal.js';
|
|
11
12
|
import { IpfsImage } from './components/Ipfs/IpfsImage.js';
|
|
12
13
|
import { SwapInterface } from './components/Swap/SwapInterface.js';
|
|
@@ -28,7 +29,8 @@ export {
|
|
|
28
29
|
IpfsService,
|
|
29
30
|
|
|
30
31
|
// UI Components
|
|
31
|
-
|
|
32
|
+
FloatingWalletButton,
|
|
33
|
+
WalletButton,
|
|
32
34
|
WalletModal,
|
|
33
35
|
IpfsImage,
|
|
34
36
|
SwapInterface,
|
|
@@ -40,4 +42,4 @@ export {
|
|
|
40
42
|
PriceDisplay,
|
|
41
43
|
BalanceDisplay,
|
|
42
44
|
MessagePopup
|
|
43
|
-
};
|
|
45
|
+
};
|
|
@@ -51,13 +51,13 @@ class BlockchainService {
|
|
|
51
51
|
await this.initializeProvider();
|
|
52
52
|
this.connectionState = 'connected';
|
|
53
53
|
this.setupNetworkListeners();
|
|
54
|
-
this.
|
|
54
|
+
this.eventBus.emit('blockchain:initialized');
|
|
55
55
|
this.isInitializing = false;
|
|
56
56
|
return true;
|
|
57
57
|
} catch (error) {
|
|
58
58
|
this.connectionState = 'error';
|
|
59
59
|
this.isInitializing = false;
|
|
60
|
-
this.
|
|
60
|
+
this.eventBus.emit('blockchain:error', error);
|
|
61
61
|
throw this.wrapError(error, 'Blockchain initialization failed');
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -91,7 +91,7 @@ class BlockchainService {
|
|
|
91
91
|
|
|
92
92
|
const network = await this.provider.getNetwork();
|
|
93
93
|
if (network.chainId !== targetNetwork) {
|
|
94
|
-
this.
|
|
94
|
+
this.eventBus.emit('network:switching', { from: network.chainId, to: targetNetwork, automatic: true });
|
|
95
95
|
try {
|
|
96
96
|
this.isInternalNetworkChange = true;
|
|
97
97
|
await window.ethereum.request({
|
|
@@ -100,10 +100,10 @@ class BlockchainService {
|
|
|
100
100
|
});
|
|
101
101
|
this.provider = new ethers.providers.Web3Provider(window.ethereum);
|
|
102
102
|
this.signer = this.provider.getSigner();
|
|
103
|
-
this.
|
|
103
|
+
this.eventBus.emit('network:switched', { from: network.chainId, to: targetNetwork, success: true });
|
|
104
104
|
} catch (switchError) {
|
|
105
105
|
this.isInternalNetworkChange = false;
|
|
106
|
-
this.
|
|
106
|
+
this.eventBus.emit('network:switched', { from: network.chainId, to: targetNetwork, success: false, error: switchError.message });
|
|
107
107
|
if (switchError.code === 4902) {
|
|
108
108
|
await window.ethereum.request({
|
|
109
109
|
method: 'wallet_addEthereumChain',
|
|
@@ -150,7 +150,7 @@ class BlockchainService {
|
|
|
150
150
|
} else {
|
|
151
151
|
console.warn('Liquidity pool address is zero, skipping V2 pool contract initialization.');
|
|
152
152
|
}
|
|
153
|
-
this.
|
|
153
|
+
this.eventBus.emit('contract:updated');
|
|
154
154
|
} catch (error) {
|
|
155
155
|
throw this.wrapError(error, 'Contract initialization failed');
|
|
156
156
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
|
|
3
|
+
const WETH_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
|
|
4
|
+
const WETH_ABI = [
|
|
5
|
+
'function deposit() payable',
|
|
6
|
+
'function withdraw(uint256 wad)',
|
|
7
|
+
'function balanceOf(address) view returns (uint256)',
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
class WETHService {
|
|
11
|
+
constructor(walletService) {
|
|
12
|
+
this.walletService = walletService;
|
|
13
|
+
this.contract = null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async _getContract() {
|
|
17
|
+
if (this.contract) return this.contract;
|
|
18
|
+
|
|
19
|
+
const provider = this.walletService.getProvider();
|
|
20
|
+
if (!provider) {
|
|
21
|
+
throw new Error('Wallet not connected');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const signer = provider.getSigner();
|
|
25
|
+
this.contract = new ethers.Contract(WETH_ADDRESS, WETH_ABI, signer);
|
|
26
|
+
return this.contract;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async deposit(amount) {
|
|
30
|
+
const contract = await this._getContract();
|
|
31
|
+
const tx = await contract.deposit({ value: ethers.utils.parseEther(amount) });
|
|
32
|
+
await tx.wait();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async withdraw(amount) {
|
|
36
|
+
const contract = await this._getContract();
|
|
37
|
+
const tx = await contract.withdraw(ethers.utils.parseEther(amount));
|
|
38
|
+
await tx.wait();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async getBalance() {
|
|
42
|
+
const contract = await this._getContract();
|
|
43
|
+
const address = this.walletService.getAddress();
|
|
44
|
+
if (!address) {
|
|
45
|
+
return '0';
|
|
46
|
+
}
|
|
47
|
+
const balance = await contract.balanceOf(address);
|
|
48
|
+
return ethers.utils.formatEther(balance);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default WETHService;
|