@monygroupcorp/micro-web3 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/micro-web3.cjs +2 -2
- package/dist/micro-web3.cjs.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/package.json +2 -2
- package/src/components/BondingCurve/BondingCurve.js +80 -116
- package/src/components/Display/BalanceDisplay.js +37 -61
- package/src/components/Display/PriceDisplay.js +43 -71
- package/src/components/FloatingWalletButton/FloatingWalletButton.js +106 -151
- package/src/components/Ipfs/IpfsImage.js +83 -107
- package/src/components/Modal/ApprovalModal.js +92 -149
- package/src/components/SettingsModal/SettingsModal.js +364 -341
- package/src/components/Swap/SwapButton.js +9 -45
- package/src/components/Swap/SwapInputs.js +46 -108
- package/src/components/Swap/SwapInterface.js +216 -597
- package/src/components/Swap/TransactionOptions.js +70 -179
- package/src/components/SyncProgressBar/SyncProgressBar.js +183 -215
- package/src/components/Util/MessagePopup.js +26 -24
- package/src/components/Wallet/WalletModal.js +45 -44
- package/src/components/WalletButton/WalletButton.js +193 -185
- package/src/services/WalletService.js +53 -20
|
@@ -1,213 +1,221 @@
|
|
|
1
|
+
import { Component, h, render } from '@monygroupcorp/microact';
|
|
1
2
|
import { FloatingWalletButton } from '../FloatingWalletButton/FloatingWalletButton.js';
|
|
2
3
|
import WalletModal from '../Wallet/WalletModal.js';
|
|
3
4
|
|
|
4
5
|
class WalletButtonModal extends WalletModal {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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);
|
|
6
|
+
handleWalletOptionClick(walletType) {
|
|
7
|
+
if (this.props.onWalletSelected) {
|
|
8
|
+
this.props.onWalletSelected(walletType);
|
|
17
9
|
}
|
|
18
10
|
this.hide();
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
}
|
|
11
|
+
}
|
|
23
12
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
});
|
|
13
|
+
render() {
|
|
14
|
+
if (!this.state.isVisible) {
|
|
15
|
+
return h('div', { className: 'wallet-modal-container', style: { display: 'none' } });
|
|
16
|
+
}
|
|
57
17
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
18
|
+
const walletOptions = Object.keys(this.props.providerMap);
|
|
19
|
+
|
|
20
|
+
return h('div', { className: 'wallet-modal-container' },
|
|
21
|
+
h('div', {
|
|
22
|
+
className: 'wallet-modal-overlay',
|
|
23
|
+
onClick: (e) => {
|
|
24
|
+
if (e.target === e.currentTarget) this.hide();
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
h('div', { className: 'wallet-modal' },
|
|
28
|
+
h('div', { className: 'wallet-modal-header' },
|
|
29
|
+
h('h3', null, 'Select Your Wallet'),
|
|
30
|
+
h('button', {
|
|
31
|
+
className: 'wallet-modal-close',
|
|
32
|
+
onClick: this.bind(this.hide)
|
|
33
|
+
}, '\u00D7')
|
|
34
|
+
),
|
|
35
|
+
h('div', { className: 'wallet-options' },
|
|
36
|
+
walletOptions.map(walletType =>
|
|
37
|
+
h('button', {
|
|
38
|
+
key: walletType,
|
|
39
|
+
className: 'wallet-option',
|
|
40
|
+
onClick: () => this.handleWalletOptionClick(walletType)
|
|
41
|
+
},
|
|
42
|
+
h('img', {
|
|
43
|
+
src: this.props.walletIcons[walletType],
|
|
44
|
+
alt: walletType
|
|
45
|
+
}),
|
|
46
|
+
h('span', null, walletType.charAt(0).toUpperCase() + walletType.slice(1))
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
62
55
|
|
|
63
|
-
|
|
56
|
+
export class WalletButton extends FloatingWalletButton {
|
|
57
|
+
constructor(props) {
|
|
58
|
+
super(props);
|
|
59
|
+
this.modalRoot = null;
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
showWalletModal() {
|
|
63
|
+
const providerMap =
|
|
64
|
+
this.walletService?.providerMap ||
|
|
65
|
+
{
|
|
66
|
+
rabby: () => (window.ethereum?.isRabby ? window.ethereum : null),
|
|
67
|
+
rainbow: () => (window.ethereum?.isRainbow ? window.ethereum : null),
|
|
68
|
+
phantom: () => window.phantom?.ethereum || null,
|
|
69
|
+
metamask: () => window.ethereum || null,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const walletIcons =
|
|
73
|
+
this.walletService?.walletIcons ||
|
|
74
|
+
{
|
|
75
|
+
rabby: '/public/wallets/rabby.webp',
|
|
76
|
+
rainbow: '/public/wallets/rainbow.webp',
|
|
77
|
+
phantom: '/public/wallets/phantom.webp',
|
|
78
|
+
metamask: '/public/wallets/MetaMask.webp',
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (!this.walletModal) {
|
|
82
|
+
if (!this.modalRoot) {
|
|
83
|
+
this.modalRoot = document.createElement('div');
|
|
84
|
+
document.body.appendChild(this.modalRoot);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
render(h(WalletButtonModal, {
|
|
88
|
+
providerMap,
|
|
89
|
+
walletIcons,
|
|
90
|
+
onWalletSelected: async (walletType) => {
|
|
91
|
+
await this.handleWalletSelection(walletType);
|
|
92
|
+
},
|
|
93
|
+
ref: instance => this.walletModal = instance
|
|
94
|
+
}), this.modalRoot);
|
|
95
|
+
}
|
|
68
96
|
|
|
69
|
-
|
|
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
|
-
`;
|
|
97
|
+
this.walletModal?.show();
|
|
84
98
|
}
|
|
85
99
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<span class="wallet-mark"></span>
|
|
93
|
-
<span class="wallet-text">Connect Wallet</span>
|
|
94
|
-
</button>
|
|
95
|
-
</div>
|
|
96
|
-
`;
|
|
100
|
+
willUnmount() {
|
|
101
|
+
if (this.modalRoot?.parentNode) {
|
|
102
|
+
this.modalRoot.parentNode.removeChild(this.modalRoot);
|
|
103
|
+
this.modalRoot = null;
|
|
104
|
+
}
|
|
105
|
+
super.willUnmount();
|
|
97
106
|
}
|
|
98
107
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
render() {
|
|
109
|
+
if (this.state.loading) {
|
|
110
|
+
return h('div', { className: 'floating-wallet-button loading' },
|
|
111
|
+
h('div', { className: 'wallet-spinner' })
|
|
112
|
+
);
|
|
113
|
+
}
|
|
104
114
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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);
|
|
115
|
+
const { walletConnected, address, balance, menuOpen } = this.state;
|
|
116
|
+
|
|
117
|
+
if (!walletConnected) {
|
|
118
|
+
return h('div', { className: 'floating-wallet-button disconnected', ref: el => this.element = el },
|
|
119
|
+
h('button', {
|
|
120
|
+
className: 'wallet-btn',
|
|
121
|
+
onClick: this.bind(this.handleWalletToggle)
|
|
122
|
+
},
|
|
123
|
+
h('span', { className: 'wallet-mark' }),
|
|
124
|
+
h('span', { className: 'wallet-text' }, 'Connect Wallet')
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const truncatedAddress = `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
130
|
+
const classNames = ['floating-wallet-button', 'connected'];
|
|
131
|
+
if (menuOpen) {
|
|
132
|
+
classNames.push('menu-open');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return h('div', { className: classNames.join(' '), ref: el => this.element = el },
|
|
136
|
+
h('button', {
|
|
137
|
+
className: 'wallet-btn',
|
|
138
|
+
title: `${this.escapeHtml(address)}\nBalance: ${balance} ETH`,
|
|
139
|
+
onClick: this.bind(this.handleWalletToggle)
|
|
140
|
+
},
|
|
141
|
+
h('span', { className: 'wallet-mark wallet-mark--connected' }),
|
|
142
|
+
h('span', { className: 'wallet-address' }, this.escapeHtml(truncatedAddress)),
|
|
143
|
+
h('span', {
|
|
144
|
+
className: 'wallet-disconnect',
|
|
145
|
+
title: 'Disconnect',
|
|
146
|
+
onClick: this.bind(this.handleInlineDisconnect)
|
|
147
|
+
}, '\u23CF\uFE0E')
|
|
148
|
+
),
|
|
149
|
+
this.renderWalletPanel(address, balance, menuOpen)
|
|
150
|
+
);
|
|
151
151
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
|
|
153
|
+
renderWalletPanel(address, balance, menuOpen) {
|
|
154
|
+
const truncatedAddress = `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
155
|
+
|
|
156
|
+
return h('div', {
|
|
157
|
+
className: 'wallet-info-panel',
|
|
158
|
+
'aria-hidden': menuOpen ? 'false' : 'true'
|
|
159
|
+
},
|
|
160
|
+
h('div', { className: 'wallet-info-row' },
|
|
161
|
+
h('span', { className: 'wallet-info-label' }, 'Address'),
|
|
162
|
+
h('span', { className: 'wallet-info-value' }, this.escapeHtml(truncatedAddress))
|
|
163
|
+
),
|
|
164
|
+
h('div', { className: 'wallet-info-row' },
|
|
165
|
+
h('span', { className: 'wallet-info-label' }, 'ETH Balance'),
|
|
166
|
+
h('span', { className: 'wallet-info-value' }, `${balance} ETH`)
|
|
167
|
+
)
|
|
168
|
+
);
|
|
158
169
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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;
|
|
170
|
+
|
|
171
|
+
didUpdate() {
|
|
172
|
+
if (this.state.menuOpen) {
|
|
173
|
+
this.attachOutsideClickListener();
|
|
174
|
+
} else {
|
|
175
|
+
this.detachOutsideClickListener();
|
|
176
|
+
}
|
|
183
177
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
178
|
+
|
|
179
|
+
attachOutsideClickListener() {
|
|
180
|
+
if (this.outsideClickHandler || this.outsideClickTimeout) return;
|
|
181
|
+
this.outsideClickHandler = (event) => {
|
|
182
|
+
if (!this.element) return;
|
|
183
|
+
const path = typeof event.composedPath === 'function' ? event.composedPath() : [];
|
|
184
|
+
const clickedInside =
|
|
185
|
+
(path.length && path.includes(this.element)) ||
|
|
186
|
+
(event.target && this.element.contains(event.target));
|
|
187
|
+
if (!clickedInside) {
|
|
188
|
+
this.setState({ menuOpen: false });
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
this.outsideClickTimeout = window.setTimeout(() => {
|
|
192
|
+
document.addEventListener('click', this.outsideClickHandler);
|
|
193
|
+
this.outsideClickTimeout = null;
|
|
194
|
+
}, 0);
|
|
187
195
|
}
|
|
188
|
-
}
|
|
189
196
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
197
|
+
detachOutsideClickListener() {
|
|
198
|
+
if (this.outsideClickTimeout) {
|
|
199
|
+
window.clearTimeout(this.outsideClickTimeout);
|
|
200
|
+
this.outsideClickTimeout = null;
|
|
201
|
+
}
|
|
202
|
+
if (this.outsideClickHandler) {
|
|
203
|
+
document.removeEventListener('click', this.outsideClickHandler);
|
|
204
|
+
this.outsideClickHandler = null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
193
207
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
208
|
+
handleWalletToggle(e) {
|
|
209
|
+
this.handleButtonClick(e);
|
|
210
|
+
}
|
|
197
211
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
212
|
+
handleInlineDisconnect(e) {
|
|
213
|
+
if (e) {
|
|
214
|
+
e.preventDefault();
|
|
215
|
+
e.stopPropagation();
|
|
216
|
+
}
|
|
217
|
+
this.handleDisconnect(e);
|
|
202
218
|
}
|
|
203
|
-
super.handleDisconnect(e);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
minifyHtml(markup) {
|
|
207
|
-
return typeof markup === 'string'
|
|
208
|
-
? markup.replace(/>\s+</g, '><').trim()
|
|
209
|
-
: markup;
|
|
210
|
-
}
|
|
211
219
|
}
|
|
212
220
|
|
|
213
221
|
export default WalletButton;
|
|
@@ -56,44 +56,77 @@ class WalletService {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
|
-
* Initialize the wallet service
|
|
59
|
+
* Initialize the wallet service.
|
|
60
|
+
* Automatically reconnects to previously authorized wallets by default.
|
|
60
61
|
* @param {Object} options - Initialization options
|
|
61
|
-
* @param {boolean} options.autoReconnect -
|
|
62
|
+
* @param {boolean} [options.autoReconnect=true] - Set to false to disable auto-reconnect
|
|
62
63
|
* @returns {Promise<boolean>} True if initialized successfully
|
|
63
64
|
*/
|
|
64
65
|
async initialize(options = {}) {
|
|
66
|
+
const { autoReconnect = true } = options;
|
|
67
|
+
|
|
65
68
|
try {
|
|
66
69
|
console.log('Initializing WalletService...');
|
|
67
70
|
|
|
68
71
|
// Check if window.ethereum exists
|
|
69
|
-
if (typeof window.ethereum
|
|
70
|
-
// Log that we found a wallet provider
|
|
71
|
-
console.log('Found Ethereum provider');
|
|
72
|
-
|
|
73
|
-
// Let other components know a wallet was detected
|
|
74
|
-
this.eventBus.emit('wallet:detected');
|
|
75
|
-
|
|
76
|
-
// Check if the provider is in MetaMask compatibility mode
|
|
77
|
-
this.isMetaMask = window.ethereum.isMetaMask;
|
|
78
|
-
|
|
79
|
-
// Set up event listeners for wallet changes
|
|
80
|
-
this.setupEventListeners();
|
|
81
|
-
} else {
|
|
72
|
+
if (typeof window.ethereum === 'undefined') {
|
|
82
73
|
console.log('No Ethereum provider found');
|
|
83
74
|
this.eventBus.emit('wallet:notdetected');
|
|
75
|
+
this.isInitialized = true;
|
|
76
|
+
return true;
|
|
84
77
|
}
|
|
85
78
|
|
|
86
|
-
|
|
87
|
-
this.
|
|
79
|
+
console.log('Found Ethereum provider');
|
|
80
|
+
this.eventBus.emit('wallet:detected');
|
|
81
|
+
this.isMetaMask = window.ethereum.isMetaMask;
|
|
82
|
+
|
|
83
|
+
// Check for previously authorized accounts (standard Web3 UX pattern)
|
|
84
|
+
if (autoReconnect) {
|
|
85
|
+
const accounts = await window.ethereum.request({ method: 'eth_accounts' });
|
|
86
|
+
|
|
87
|
+
if (accounts?.length > 0) {
|
|
88
|
+
console.log('[WalletService] Found authorized account:', accounts[0]);
|
|
89
|
+
|
|
90
|
+
// Detect wallet type and update internal state
|
|
91
|
+
const walletType = this._detectWalletType();
|
|
92
|
+
this.selectedWallet = walletType;
|
|
93
|
+
this.provider = window.ethereum;
|
|
94
|
+
this.connectedAddress = accounts[0];
|
|
95
|
+
this.connected = true;
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
// Create ethers provider and signer
|
|
98
|
+
this.ethersProvider = new ethers.providers.Web3Provider(window.ethereum, 'any');
|
|
99
|
+
this.signer = this.ethersProvider.getSigner();
|
|
100
|
+
|
|
101
|
+
// Set up event listeners
|
|
102
|
+
this.setupEventListeners();
|
|
103
|
+
|
|
104
|
+
// Store for future sessions
|
|
105
|
+
localStorage.setItem('ms2fun_lastWallet', walletType);
|
|
106
|
+
|
|
107
|
+
console.log('[WalletService] Auto-connected to:', accounts[0]);
|
|
108
|
+
|
|
109
|
+
// Emit connected event
|
|
110
|
+
this.eventBus.emit('wallet:connected', {
|
|
111
|
+
address: this.connectedAddress,
|
|
112
|
+
walletType: this.selectedWallet,
|
|
113
|
+
provider: this.provider,
|
|
114
|
+
ethersProvider: this.ethersProvider,
|
|
115
|
+
signer: this.signer
|
|
116
|
+
});
|
|
117
|
+
}
|
|
92
118
|
}
|
|
93
119
|
|
|
120
|
+
// Set up listeners even if not connected (for future connections)
|
|
121
|
+
if (!this.connected) {
|
|
122
|
+
this.setupEventListeners();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.isInitialized = true;
|
|
94
126
|
return true;
|
|
95
127
|
} catch (error) {
|
|
96
128
|
console.error('Error initializing WalletService:', error);
|
|
129
|
+
this.isInitialized = true; // Still mark as initialized
|
|
97
130
|
throw error;
|
|
98
131
|
}
|
|
99
132
|
}
|