@monygroupcorp/micro-web3 1.2.4 → 1.3.1
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 +107 -152
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component } from '@monygroupcorp/microact';
|
|
1
|
+
import { Component, h, render } from '@monygroupcorp/microact';
|
|
2
2
|
import { TransactionOptions } from './TransactionOptions.js';
|
|
3
3
|
import { MessagePopup } from '../Util/MessagePopup.js';
|
|
4
4
|
import { PriceDisplay } from '../Display/PriceDisplay.js';
|
|
@@ -9,7 +9,7 @@ import SwapButton from './SwapButton.js';
|
|
|
9
9
|
export class SwapInterface extends Component {
|
|
10
10
|
constructor(props) {
|
|
11
11
|
super(props);
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
this.blockchainService = props.blockchainService;
|
|
14
14
|
this.eventBus = props.eventBus;
|
|
15
15
|
|
|
@@ -21,53 +21,29 @@ export class SwapInterface extends Component {
|
|
|
21
21
|
freeMint: props.freeMint || false,
|
|
22
22
|
freeSupply: props.freeSupply || 0,
|
|
23
23
|
calculatingAmount: false,
|
|
24
|
-
isPhase2: props.isPhase2 === null ? null : props.isPhase2,
|
|
24
|
+
isPhase2: props.isPhase2 === null ? null : props.isPhase2,
|
|
25
25
|
dataReady: props.dataReady || false,
|
|
26
26
|
balances: props.balances || { eth: '0', exec: '0' },
|
|
27
27
|
price: props.price || { current: 0 },
|
|
28
28
|
contractData: props.contractData || {},
|
|
29
29
|
};
|
|
30
|
-
|
|
31
|
-
// Store the address - could be a promise or a direct value
|
|
30
|
+
|
|
32
31
|
this._address = props.address || null;
|
|
33
|
-
|
|
34
|
-
// Initialize child components
|
|
35
|
-
this.transactionOptions = new TransactionOptions();
|
|
36
32
|
this.messagePopup = new MessagePopup('status-message');
|
|
37
|
-
this.
|
|
38
|
-
this.messagePopup.initialize();
|
|
39
|
-
|
|
40
|
-
this.swapInputs = null; // Initialized in initializeChildComponents
|
|
41
|
-
|
|
42
|
-
this.swapButton = new SwapButton({
|
|
43
|
-
direction: this.state.direction,
|
|
44
|
-
disabled: false,
|
|
45
|
-
onClick: this.handleSwap.bind(this)
|
|
46
|
-
});
|
|
47
|
-
|
|
33
|
+
this.messagePopup.initialize?.();
|
|
48
34
|
this.calculateTimer = null;
|
|
49
|
-
|
|
50
|
-
// Bind event handlers that are passed in props
|
|
51
35
|
this.onDirectionChange = props.onDirectionChange;
|
|
52
|
-
|
|
53
|
-
this.handleTransactionEvents = this.handleTransactionEvents.bind(this);
|
|
54
|
-
this.handleBalanceUpdate = this.handleBalanceUpdate.bind(this);
|
|
55
|
-
this.handleTransactionOptionsUpdate = this.handleTransactionOptionsUpdate.bind(this);
|
|
56
|
-
|
|
57
36
|
this.transactionOptionsState = {
|
|
58
37
|
message: '',
|
|
59
38
|
nftMintingEnabled: false
|
|
60
39
|
};
|
|
61
|
-
|
|
62
40
|
this.approveModal = null;
|
|
63
41
|
this.eventListeners = [];
|
|
64
42
|
this.instanceId = Math.random().toString(36).substring(2, 9);
|
|
65
|
-
console.log(
|
|
43
|
+
console.log(`[SwapInterface] Instance created: ${this.instanceId}`);
|
|
66
44
|
}
|
|
67
45
|
|
|
68
|
-
// Add new method to handle balance updates
|
|
69
46
|
handleBalanceUpdate(update) {
|
|
70
|
-
// Update state from the event detail or props
|
|
71
47
|
const newBalances = update.balances || this.props.balances;
|
|
72
48
|
const newFreeMint = update.freeMint !== undefined ? update.freeMint : this.props.freeMint;
|
|
73
49
|
const newFreeSupply = update.freeSupply !== undefined ? update.freeSupply : this.props.freeSupply;
|
|
@@ -77,83 +53,34 @@ export class SwapInterface extends Component {
|
|
|
77
53
|
freeMint: newFreeMint,
|
|
78
54
|
freeSupply: newFreeSupply
|
|
79
55
|
});
|
|
80
|
-
|
|
81
|
-
// Update swap inputs component with new balance info directly
|
|
82
|
-
if (this.swapInputs) {
|
|
83
|
-
this.swapInputs.updateProps({
|
|
84
|
-
freeMint: newFreeMint
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
updateElements() {
|
|
90
|
-
// Update child components with new props
|
|
91
|
-
// Use requestAnimationFrame to batch updates and prevent multiple renders
|
|
92
|
-
requestAnimationFrame(() => {
|
|
93
|
-
if (this.swapInputs) {
|
|
94
|
-
this.swapInputs.updateProps({
|
|
95
|
-
direction: this.state.direction,
|
|
96
|
-
ethAmount: this.state.ethAmount,
|
|
97
|
-
execAmount: this.state.execAmount,
|
|
98
|
-
calculatingAmount: this.state.calculatingAmount,
|
|
99
|
-
freeMint: this.state.freeMint,
|
|
100
|
-
isPhase2: this.state.isPhase2
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (this.swapButton) {
|
|
105
|
-
this.swapButton.updateProps({
|
|
106
|
-
direction: this.state.direction
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
56
|
}
|
|
111
57
|
|
|
112
58
|
async calculateSwapAmount(amount, inputType) {
|
|
113
|
-
// Handle empty or invalid input
|
|
114
59
|
if (!amount || isNaN(parseFloat(amount))) {
|
|
115
60
|
return '';
|
|
116
61
|
}
|
|
117
62
|
|
|
118
63
|
try {
|
|
119
64
|
if (this.isLiquidityDeployed()) {
|
|
120
|
-
// Phase 2: Use Uniswap-style calculations
|
|
121
65
|
const price = this.state.price.current;
|
|
122
|
-
console.log('calculateSwapAmount price', price);
|
|
123
|
-
|
|
124
66
|
if (inputType === 'eth') {
|
|
125
|
-
// Calculate EXEC amount based on ETH input
|
|
126
67
|
const ethAmount = parseFloat(amount);
|
|
127
|
-
// Apply a 5% reduction to account for 4% tax + slippage
|
|
128
68
|
const execAmount = (ethAmount / price * 1000000) * 0.95;
|
|
129
|
-
|
|
130
|
-
return execAmount.toFixed(0); // Use integer amounts for EXEC
|
|
69
|
+
return execAmount.toFixed(0);
|
|
131
70
|
} else {
|
|
132
|
-
// Calculate ETH amount based on EXEC input
|
|
133
71
|
const execAmount = parseFloat(amount);
|
|
134
|
-
// Add a 5.5% buffer for 4% tax + slippage + price impact
|
|
135
72
|
const ethAmount = (execAmount / 1000000) * price * 1.055;
|
|
136
|
-
console.log('calculateSwapAmount ethAmount', ethAmount);
|
|
137
73
|
return ethAmount.toFixed(6);
|
|
138
74
|
}
|
|
139
75
|
} else {
|
|
140
|
-
// Phase 1: Use bonding curve logic
|
|
141
76
|
if (inputType === 'eth') {
|
|
142
|
-
// Calculate how much EXEC user will receive for their ETH
|
|
143
77
|
const execAmount = await this.blockchainService.getExecForEth(amount);
|
|
144
|
-
|
|
145
|
-
// Check if user is eligible for free mint
|
|
146
78
|
const { freeSupply, freeMint } = this.state;
|
|
147
|
-
console.log('calculateSwapAmount freeMint', freeMint);
|
|
148
|
-
// If free supply is available and user hasn't claimed their free mint
|
|
149
79
|
const freeMintBonus = (freeSupply > 0 && !freeMint) ? 1000000 : 0;
|
|
150
|
-
|
|
151
|
-
// Round down to ensure we don't exceed maxCost
|
|
152
80
|
return Math.floor(execAmount + freeMintBonus).toString();
|
|
153
81
|
} else {
|
|
154
|
-
// Calculate how much ETH user will receive for their EXEC
|
|
155
82
|
const ethAmount = await this.blockchainService.getEthForExec(amount);
|
|
156
|
-
return ethAmount.toString();
|
|
83
|
+
return ethAmount.toString();
|
|
157
84
|
}
|
|
158
85
|
}
|
|
159
86
|
} catch (error) {
|
|
@@ -162,311 +89,110 @@ export class SwapInterface extends Component {
|
|
|
162
89
|
}
|
|
163
90
|
}
|
|
164
91
|
|
|
165
|
-
|
|
166
|
-
console.log(`[${this.instanceId}] SwapInterface
|
|
92
|
+
didMount() {
|
|
93
|
+
console.log(`[${this.instanceId}] SwapInterface didMount called`);
|
|
167
94
|
this.bindEvents();
|
|
168
|
-
|
|
95
|
+
|
|
169
96
|
const eventSubscriptions = [
|
|
170
|
-
['contractData:updated', this.
|
|
171
|
-
['transaction:pending', this.handleTransactionEvents, 'normal'],
|
|
172
|
-
['transaction:confirmed', this.handleTransactionEvents, 'normal'],
|
|
173
|
-
['transaction:success', this.handleTransactionEvents, 'normal'],
|
|
174
|
-
['transaction:error', this.handleTransactionEvents, 'normal'],
|
|
175
|
-
['balances:updated', this.handleBalanceUpdate, 'high'],
|
|
176
|
-
['transactionOptions:update', this.handleTransactionOptionsUpdate, 'low']
|
|
97
|
+
['contractData:updated', this.bind(this.handleContractDataUpdate), 'high'],
|
|
98
|
+
['transaction:pending', this.bind(this.handleTransactionEvents), 'normal'],
|
|
99
|
+
['transaction:confirmed', this.bind(this.handleTransactionEvents), 'normal'],
|
|
100
|
+
['transaction:success', this.bind(this.handleTransactionEvents), 'normal'],
|
|
101
|
+
['transaction:error', this.bind(this.handleTransactionEvents), 'normal'],
|
|
102
|
+
['balances:updated', this.bind(this.handleBalanceUpdate), 'high'],
|
|
103
|
+
['transactionOptions:update', this.bind(this.handleTransactionOptionsUpdate), 'low']
|
|
177
104
|
];
|
|
178
|
-
|
|
179
|
-
this.eventListeners = eventSubscriptions.map(([event, handler
|
|
180
|
-
console.log(`[${this.instanceId}] Subscribing to ${event} with priority ${priority}`);
|
|
105
|
+
|
|
106
|
+
this.eventListeners = eventSubscriptions.map(([event, handler]) => {
|
|
181
107
|
return this.eventBus.on(event, handler);
|
|
182
108
|
});
|
|
183
109
|
|
|
184
|
-
// Check if we already have data and can determine phase immediately
|
|
185
110
|
const { contractData } = this.state;
|
|
186
111
|
if (contractData && contractData.liquidityPool !== undefined) {
|
|
187
112
|
const isPhase2 = this.isLiquidityDeployed();
|
|
188
|
-
this.setState({
|
|
113
|
+
this.setState({
|
|
189
114
|
isPhase2: isPhase2,
|
|
190
115
|
dataReady: true
|
|
191
116
|
});
|
|
192
|
-
this.initializeChildComponents();
|
|
193
117
|
}
|
|
194
|
-
|
|
195
|
-
this.update();
|
|
196
|
-
|
|
197
|
-
requestAnimationFrame(() => {
|
|
198
|
-
this.mountChildComponents();
|
|
199
|
-
});
|
|
200
118
|
}
|
|
201
119
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const oldState = { ...this.state };
|
|
205
|
-
const newState = {
|
|
206
|
-
...this.state,
|
|
207
|
-
...newProps
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
if (this.shouldUpdate(oldState, newState)) {
|
|
211
|
-
this.setState(newState);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Initialize child components that depend on phase
|
|
217
|
-
* This is called once phase is determined (either in onMount or handleContractDataUpdate)
|
|
218
|
-
*/
|
|
219
|
-
initializeChildComponents() {
|
|
220
|
-
// Only initialize if phase is known and SwapInputs hasn't been created yet
|
|
221
|
-
if (this.state.isPhase2 === null) {
|
|
222
|
-
console.log(`[${this.instanceId}] Phase not yet determined, skipping SwapInputs initialization`);
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (!this.swapInputs) {
|
|
227
|
-
console.log(`[${this.instanceId}] Initializing SwapInputs with phase ${this.state.isPhase2 ? '2' : '1'}`);
|
|
228
|
-
this.swapInputs = new SwapInputs({
|
|
229
|
-
direction: this.state.direction,
|
|
230
|
-
ethAmount: this.state.ethAmount,
|
|
231
|
-
execAmount: this.state.execAmount,
|
|
232
|
-
calculatingAmount: this.state.calculatingAmount,
|
|
233
|
-
freeMint: this.state.freeMint,
|
|
234
|
-
isPhase2: this.state.isPhase2,
|
|
235
|
-
onInput: this.handleInput.bind(this)
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Add method to explicitly mount child components
|
|
241
|
-
mountChildComponents() {
|
|
242
|
-
// Mount price display
|
|
243
|
-
const priceContainer = this.element.querySelector('.price-display-container');
|
|
244
|
-
if (priceContainer && (!this.priceDisplay.element || !priceContainer.contains(this.priceDisplay.element))) {
|
|
245
|
-
console.log(`[${this.instanceId}] Mounting PriceDisplay component`);
|
|
246
|
-
this.priceDisplay.mount(priceContainer);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Mount transaction options
|
|
250
|
-
const optionsContainer = this.element.querySelector('.transaction-options-container');
|
|
251
|
-
if (optionsContainer && this.transactionOptions &&
|
|
252
|
-
(!this.transactionOptions.element || !optionsContainer.contains(this.transactionOptions.element))) {
|
|
253
|
-
console.log(`[${this.instanceId}] Mounting TransactionOptions component`);
|
|
254
|
-
this.transactionOptions.mount(optionsContainer);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// Mount swap inputs
|
|
258
|
-
const inputsContainer = this.element.querySelector('.swap-inputs-container');
|
|
259
|
-
if (inputsContainer && this.swapInputs) {
|
|
260
|
-
this.swapInputs.mount(inputsContainer);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Mount quick fill buttons
|
|
264
|
-
const quickFillContainer = this.element.querySelector('.quick-fill-buttons-container');
|
|
265
|
-
if (quickFillContainer) {
|
|
266
|
-
// Create a wrapper for just the quick fill buttons
|
|
267
|
-
quickFillContainer.innerHTML = '<div class="quick-fill-buttons"></div>';
|
|
268
|
-
const quickFillButtons = quickFillContainer.querySelector('.quick-fill-buttons');
|
|
269
|
-
if (quickFillButtons) {
|
|
270
|
-
// Render quick fill buttons directly
|
|
271
|
-
const { direction } = this.state;
|
|
272
|
-
quickFillButtons.innerHTML = direction === 'buy' ?
|
|
273
|
-
`<button data-amount="0.0025">0.0025</button>
|
|
274
|
-
<button data-amount="0.01">0.01</button>
|
|
275
|
-
<button data-amount="0.05">0.05</button>
|
|
276
|
-
<button data-amount="0.1">0.1</button>`
|
|
277
|
-
:
|
|
278
|
-
`<button data-percentage="25">25%</button>
|
|
279
|
-
<button data-percentage="50">50%</button>
|
|
280
|
-
<button data-percentage="75">75%</button>
|
|
281
|
-
<button data-percentage="100">100%</button>`;
|
|
282
|
-
|
|
283
|
-
// Attach event listeners
|
|
284
|
-
quickFillButtons.addEventListener('click', (e) => {
|
|
285
|
-
if (e.target.dataset.amount || e.target.dataset.percentage) {
|
|
286
|
-
this.handleQuickFill(e);
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Mount direction switch in the slot within swap-inputs
|
|
293
|
-
const directionSwitchSlot = this.element.querySelector('.direction-switch-slot');
|
|
294
|
-
if (directionSwitchSlot) {
|
|
295
|
-
directionSwitchSlot.innerHTML = '<button class="direction-switch">↑↓</button>';
|
|
296
|
-
directionSwitchSlot.querySelector('.direction-switch').addEventListener('click', (e) => {
|
|
297
|
-
this.handleDirectionSwitch(e);
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Mount swap button
|
|
302
|
-
const buttonContainer = this.element.querySelector('.swap-button-container');
|
|
303
|
-
if (buttonContainer && this.swapButton) {
|
|
304
|
-
this.swapButton.mount(buttonContainer);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
onUnmount() {
|
|
309
|
-
console.log(`[${this.instanceId}] SwapInterface onUnmount called`);
|
|
310
|
-
// Unsubscribe from all events
|
|
120
|
+
willUnmount() {
|
|
121
|
+
console.log(`[${this.instanceId}] SwapInterface willUnmount called`);
|
|
311
122
|
this.eventListeners.forEach(unsubscribe => {
|
|
312
123
|
if (typeof unsubscribe === 'function') {
|
|
313
124
|
unsubscribe();
|
|
314
125
|
}
|
|
315
126
|
});
|
|
316
|
-
|
|
317
|
-
// Clear the list
|
|
318
127
|
this.eventListeners = [];
|
|
319
|
-
|
|
320
|
-
// Remove child components
|
|
321
|
-
if (this.transactionOptions && this.transactionOptions.element) {
|
|
322
|
-
this.transactionOptions.element.remove();
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Ensure price display is cleaned up
|
|
326
|
-
if (this.priceDisplay) {
|
|
327
|
-
try {
|
|
328
|
-
this.priceDisplay.unmount();
|
|
329
|
-
} catch (e) {
|
|
330
|
-
console.warn('Error unmounting price display:', e);
|
|
331
|
-
}
|
|
332
|
-
this.priceDisplay = null;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Unmount sub-components
|
|
336
|
-
if (this.swapInputs) {
|
|
337
|
-
try {
|
|
338
|
-
this.swapInputs.unmount();
|
|
339
|
-
} catch (e) {
|
|
340
|
-
console.warn('Error unmounting swap inputs:', e);
|
|
341
|
-
}
|
|
342
|
-
this.swapInputs = null;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Quick fill and direction switch are handled inline, no unmount needed
|
|
346
|
-
|
|
347
|
-
if (this.swapButton) {
|
|
348
|
-
try {
|
|
349
|
-
this.swapButton.unmount();
|
|
350
|
-
} catch (e) {
|
|
351
|
-
console.warn('Error unmounting swap button:', e);
|
|
352
|
-
}
|
|
353
|
-
this.swapButton = null;
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// Make sure to close and clean up any open approval modal
|
|
128
|
+
|
|
357
129
|
if (this.approveModal) {
|
|
358
130
|
try {
|
|
359
|
-
// Close the modal - this will trigger the approveModal:closed event
|
|
360
|
-
// which will clean up related event listeners
|
|
361
131
|
this.approveModal.handleClose();
|
|
362
132
|
} catch (e) {
|
|
363
133
|
console.warn('Error closing approval modal during unmount:', e);
|
|
364
134
|
}
|
|
365
135
|
this.approveModal = null;
|
|
366
136
|
}
|
|
367
|
-
|
|
368
|
-
// Clear any pending timers
|
|
137
|
+
|
|
369
138
|
if (this.calculateTimer) {
|
|
370
139
|
clearTimeout(this.calculateTimer);
|
|
371
140
|
this.calculateTimer = null;
|
|
372
141
|
}
|
|
373
142
|
}
|
|
374
143
|
|
|
144
|
+
bindEvents() {
|
|
145
|
+
// Events are bound inline in render
|
|
146
|
+
}
|
|
147
|
+
|
|
375
148
|
handleTransactionEvents(event) {
|
|
376
|
-
console.log(`[${this.instanceId}] handleTransactionEvents called with:`, {
|
|
377
|
-
type: event?.type,
|
|
378
|
-
hasError: !!event?.error,
|
|
379
|
-
hasHash: !!event?.hash,
|
|
380
|
-
eventId: event?.id || 'none',
|
|
381
|
-
handled: event?.handled || false
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
// Skip if this event has already been handled by this instance
|
|
385
149
|
if (event?.handledBy?.includes(this.instanceId)) {
|
|
386
|
-
console.log(`[${this.instanceId}] Event already handled by this instance, skipping`);
|
|
387
150
|
return;
|
|
388
151
|
}
|
|
389
|
-
|
|
390
|
-
// Mark this event as handled by this instance
|
|
391
152
|
if (!event.handledBy) {
|
|
392
153
|
event.handledBy = [];
|
|
393
154
|
}
|
|
394
155
|
event.handledBy.push(this.instanceId);
|
|
395
|
-
|
|
156
|
+
|
|
396
157
|
const direction = this.state.direction === 'buy' ? 'Buy' : 'Sell';
|
|
397
158
|
|
|
398
|
-
// Check if this is a transaction event
|
|
399
159
|
if (!event || !event.type) {
|
|
400
|
-
console.warn('Invalid transaction event:', event);
|
|
401
160
|
return;
|
|
402
161
|
}
|
|
403
162
|
|
|
404
|
-
// For transaction events - only show if it's not an error
|
|
405
163
|
if ((event.type === 'buy' || event.type === 'sell' || event.type === 'swap') && !event.error) {
|
|
406
|
-
|
|
407
|
-
this.messagePopup.info(
|
|
408
|
-
`${direction} transaction. Simulating...`,
|
|
409
|
-
'Transaction Pending'
|
|
410
|
-
);
|
|
164
|
+
this.messagePopup.info(`${direction} transaction. Simulating...`, 'Transaction Pending');
|
|
411
165
|
}
|
|
412
166
|
|
|
413
|
-
// For confirmed transactions
|
|
414
167
|
if (event.hash) {
|
|
415
|
-
this.messagePopup.info(
|
|
416
|
-
`Transaction confirmed, waiting for completion...`,
|
|
417
|
-
'Transaction Confirmed'
|
|
418
|
-
);
|
|
168
|
+
this.messagePopup.info('Transaction confirmed, waiting for completion...', 'Transaction Confirmed');
|
|
419
169
|
}
|
|
420
170
|
|
|
421
|
-
// For successful transactions
|
|
422
171
|
if (event.receipt && (event.type === 'buy' || event.type === 'sell' || event.type === 'swap')) {
|
|
423
|
-
const amount = this.state.direction === 'buy'
|
|
172
|
+
const amount = this.state.direction === 'buy'
|
|
424
173
|
? this.state.execAmount + ' EXEC'
|
|
425
174
|
: this.state.ethAmount + ' ETH';
|
|
426
|
-
|
|
175
|
+
|
|
427
176
|
this.messagePopup.success(
|
|
428
177
|
`Successfully ${direction.toLowerCase() === 'buy' ? 'bought' : 'sold'} ${amount}`,
|
|
429
178
|
'Transaction Complete'
|
|
430
179
|
);
|
|
431
180
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
// Update child components directly
|
|
438
|
-
if (this.swapInputs) {
|
|
439
|
-
this.swapInputs.updateProps({
|
|
440
|
-
ethAmount: '',
|
|
441
|
-
execAmount: '',
|
|
442
|
-
calculatingAmount: false
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// Re-mount child components after state update
|
|
447
|
-
this.mountChildComponents();
|
|
181
|
+
this.setState({
|
|
182
|
+
ethAmount: '',
|
|
183
|
+
execAmount: '',
|
|
184
|
+
calculatingAmount: false
|
|
185
|
+
});
|
|
448
186
|
}
|
|
449
187
|
|
|
450
|
-
// For error transactions
|
|
451
188
|
if (event.error && !event.handled) {
|
|
452
|
-
console.log(`[${this.instanceId}] Handling error in handleTransactionEvents:`, event.error);
|
|
453
|
-
|
|
454
189
|
let errorMessage = event.error?.message || 'Transaction failed';
|
|
455
|
-
|
|
456
190
|
if (errorMessage.includes('Contract call')) {
|
|
457
191
|
const parts = errorMessage.split(': ');
|
|
458
192
|
errorMessage = parts[parts.length - 1];
|
|
459
193
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
'Buy Failed' :
|
|
463
|
-
'Sell Failed';
|
|
464
|
-
|
|
465
|
-
this.messagePopup.error(
|
|
466
|
-
`${context}: ${errorMessage}`,
|
|
467
|
-
'Transaction Failed'
|
|
468
|
-
);
|
|
469
|
-
|
|
194
|
+
const context = this.state.direction === 'buy' ? 'Buy Failed' : 'Sell Failed';
|
|
195
|
+
this.messagePopup.error(`${context}: ${errorMessage}`, 'Transaction Failed');
|
|
470
196
|
event.handled = true;
|
|
471
197
|
}
|
|
472
198
|
}
|
|
@@ -479,158 +205,99 @@ export class SwapInterface extends Component {
|
|
|
479
205
|
}
|
|
480
206
|
|
|
481
207
|
handleInput(inputType, value) {
|
|
482
|
-
// Clear any existing timer
|
|
483
208
|
if (this.calculateTimer) {
|
|
484
209
|
clearTimeout(this.calculateTimer);
|
|
485
210
|
}
|
|
486
211
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
212
|
+
const newState = {
|
|
213
|
+
activeInput: inputType,
|
|
214
|
+
calculatingAmount: true
|
|
215
|
+
};
|
|
216
|
+
|
|
492
217
|
if (this.state.direction === 'buy') {
|
|
493
218
|
if (inputType === 'top') {
|
|
494
|
-
|
|
219
|
+
newState.ethAmount = value;
|
|
495
220
|
} else {
|
|
496
|
-
|
|
221
|
+
newState.execAmount = value;
|
|
497
222
|
}
|
|
498
223
|
} else {
|
|
499
224
|
if (inputType === 'top') {
|
|
500
|
-
|
|
225
|
+
newState.execAmount = value;
|
|
501
226
|
} else {
|
|
502
|
-
|
|
227
|
+
newState.ethAmount = value;
|
|
503
228
|
}
|
|
504
229
|
}
|
|
505
|
-
|
|
506
|
-
// Update child components directly without triggering parent re-render
|
|
507
|
-
if (this.swapInputs) {
|
|
508
|
-
this.swapInputs.updateProps({
|
|
509
|
-
direction: this.state.direction,
|
|
510
|
-
ethAmount: this.state.ethAmount,
|
|
511
|
-
execAmount: this.state.execAmount,
|
|
512
|
-
calculatingAmount: this.state.calculatingAmount,
|
|
513
|
-
freeMint: this.state.freeMint,
|
|
514
|
-
isPhase2: this.state.isPhase2
|
|
515
|
-
});
|
|
516
|
-
}
|
|
517
230
|
|
|
518
|
-
|
|
231
|
+
this.setState(newState);
|
|
232
|
+
|
|
519
233
|
this.calculateTimer = setTimeout(async () => {
|
|
520
234
|
try {
|
|
521
235
|
const isEthInput = (this.state.direction === 'buy') === (inputType === 'top');
|
|
522
236
|
const calculatedAmount = await this.calculateSwapAmount(value, isEthInput ? 'eth' : 'exec');
|
|
523
|
-
|
|
524
|
-
// Update the opposite input after calculation
|
|
237
|
+
|
|
525
238
|
if (isEthInput) {
|
|
526
|
-
this.
|
|
527
|
-
this.state.calculatingAmount = false;
|
|
528
|
-
|
|
529
|
-
// Update child component directly
|
|
530
|
-
if (this.swapInputs) {
|
|
531
|
-
this.swapInputs.updateProps({
|
|
532
|
-
execAmount: calculatedAmount,
|
|
533
|
-
calculatingAmount: false
|
|
534
|
-
});
|
|
535
|
-
}
|
|
239
|
+
this.setState({ execAmount: calculatedAmount, calculatingAmount: false });
|
|
536
240
|
} else {
|
|
537
|
-
this.
|
|
538
|
-
this.state.calculatingAmount = false;
|
|
539
|
-
|
|
540
|
-
// Update child component directly
|
|
541
|
-
if (this.swapInputs) {
|
|
542
|
-
this.swapInputs.updateProps({
|
|
543
|
-
ethAmount: calculatedAmount,
|
|
544
|
-
calculatingAmount: false
|
|
545
|
-
});
|
|
546
|
-
}
|
|
241
|
+
this.setState({ ethAmount: calculatedAmount, calculatingAmount: false });
|
|
547
242
|
}
|
|
548
243
|
} catch (error) {
|
|
549
244
|
console.error('Error calculating swap amount:', error);
|
|
550
|
-
this.
|
|
551
|
-
|
|
552
|
-
// Update child component directly
|
|
553
|
-
if (this.swapInputs) {
|
|
554
|
-
this.swapInputs.updateProps({
|
|
555
|
-
calculatingAmount: false
|
|
556
|
-
});
|
|
557
|
-
}
|
|
245
|
+
this.setState({ calculatingAmount: false });
|
|
558
246
|
}
|
|
559
247
|
}, 750);
|
|
560
248
|
}
|
|
561
249
|
|
|
562
|
-
events() {
|
|
563
|
-
// Events are now handled by child components
|
|
564
|
-
return {};
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/**
|
|
568
|
-
* Override shouldUpdate to prevent re-renders on input changes
|
|
569
|
-
* Input changes are handled by child components directly
|
|
570
|
-
*/
|
|
571
|
-
shouldUpdate(oldState, newState) {
|
|
572
|
-
if (!oldState || !newState) return true;
|
|
573
|
-
if (oldState === newState) return false;
|
|
574
|
-
|
|
575
|
-
// Don't update if only input values changed (ethAmount, execAmount, activeInput, calculatingAmount)
|
|
576
|
-
// These are handled by child components directly
|
|
577
|
-
const inputOnlyChanges =
|
|
578
|
-
oldState.ethAmount !== newState.ethAmount ||
|
|
579
|
-
oldState.execAmount !== newState.execAmount ||
|
|
580
|
-
oldState.activeInput !== newState.activeInput ||
|
|
581
|
-
oldState.calculatingAmount !== newState.calculatingAmount;
|
|
582
|
-
|
|
583
|
-
// If only input values changed, don't re-render (child components handle it)
|
|
584
|
-
if (inputOnlyChanges &&
|
|
585
|
-
oldState.direction === newState.direction &&
|
|
586
|
-
oldState.freeMint === newState.freeMint &&
|
|
587
|
-
oldState.freeSupply === newState.freeSupply &&
|
|
588
|
-
oldState.isPhase2 === newState.isPhase2 &&
|
|
589
|
-
oldState.dataReady === newState.dataReady) {
|
|
590
|
-
return false;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// Update for other state changes (direction, phase, dataReady, etc.)
|
|
594
|
-
return true;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
250
|
handleDirectionSwitch(e) {
|
|
598
|
-
// Prevent default button behavior and stop propagation
|
|
599
251
|
if (e) {
|
|
600
252
|
e.preventDefault();
|
|
601
253
|
e.stopPropagation();
|
|
602
254
|
}
|
|
603
|
-
|
|
604
|
-
// Clear any pending calculations
|
|
255
|
+
|
|
605
256
|
if (this.calculateTimer) {
|
|
606
257
|
clearTimeout(this.calculateTimer);
|
|
607
258
|
}
|
|
608
259
|
|
|
609
260
|
const newDirection = this.state.direction === 'buy' ? 'sell' : 'buy';
|
|
610
|
-
|
|
611
|
-
console.log('Direction Switch - Current State:', {
|
|
612
|
-
direction: this.state.direction,
|
|
613
|
-
newDirection,
|
|
614
|
-
freeMint: this.state.freeMint,
|
|
615
|
-
freeSupply: this.state.freeSupply
|
|
616
|
-
});
|
|
617
261
|
|
|
618
|
-
// Use setState instead of directly modifying state
|
|
619
262
|
this.setState({
|
|
620
263
|
direction: newDirection,
|
|
621
264
|
calculatingAmount: false,
|
|
622
265
|
activeInput: null
|
|
623
266
|
});
|
|
624
267
|
|
|
625
|
-
// Notify parent component of the change
|
|
626
268
|
if (this.onDirectionChange) {
|
|
627
269
|
this.onDirectionChange(newDirection);
|
|
628
270
|
}
|
|
271
|
+
}
|
|
629
272
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
273
|
+
handleQuickFill(amount, percentage) {
|
|
274
|
+
let value;
|
|
275
|
+
|
|
276
|
+
if (amount) {
|
|
277
|
+
value = amount;
|
|
278
|
+
} else if (percentage) {
|
|
279
|
+
const { balances } = this.state;
|
|
280
|
+
const execBalance = balances.exec;
|
|
281
|
+
|
|
282
|
+
if (!execBalance || execBalance === '0') {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let readableBalance = BigInt(execBalance) / BigInt(1e18);
|
|
287
|
+
|
|
288
|
+
if (this.state.freeMint) {
|
|
289
|
+
readableBalance = readableBalance - BigInt(1000000);
|
|
290
|
+
if (readableBalance <= 0) {
|
|
291
|
+
this.messagePopup.info('You only have free mint tokens which cannot be sold.', 'Cannot Quick Fill');
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const fillAmount = (readableBalance * BigInt(percentage)) / BigInt(100);
|
|
297
|
+
value = fillAmount.toString();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
this.handleInput('top', value);
|
|
634
301
|
}
|
|
635
302
|
|
|
636
303
|
isLiquidityDeployed() {
|
|
@@ -638,34 +305,27 @@ export class SwapInterface extends Component {
|
|
|
638
305
|
if (!contractData || !contractData.liquidityPool) {
|
|
639
306
|
return false;
|
|
640
307
|
}
|
|
641
|
-
|
|
642
|
-
console.log('isLiquidityDeployed check:', {
|
|
643
|
-
liquidityPool: contractData.liquidityPool,
|
|
644
|
-
result: result
|
|
645
|
-
});
|
|
646
|
-
return result;
|
|
308
|
+
return contractData.liquidityPool !== '0x0000000000000000000000000000000000000000';
|
|
647
309
|
}
|
|
648
310
|
|
|
649
311
|
async handleSwap() {
|
|
650
312
|
try {
|
|
651
|
-
// Validate inputs
|
|
652
313
|
if (this.state.calculatingAmount) {
|
|
653
314
|
this.messagePopup.info('Please wait for the calculation to complete', 'Loading');
|
|
654
315
|
return;
|
|
655
316
|
}
|
|
656
|
-
|
|
317
|
+
|
|
657
318
|
const { ethAmount, execAmount, direction, balances, freeMint } = this.state;
|
|
658
|
-
|
|
319
|
+
|
|
659
320
|
if (!ethAmount || !execAmount || parseFloat(ethAmount) <= 0 || parseFloat(execAmount) <= 0) {
|
|
660
321
|
this.messagePopup.info('Please enter valid amounts', 'Invalid Input');
|
|
661
322
|
return;
|
|
662
323
|
}
|
|
663
|
-
|
|
664
|
-
// Check if user has enough balance
|
|
324
|
+
|
|
665
325
|
if (direction === 'buy') {
|
|
666
326
|
let ethBalance = parseFloat(this.blockchainService.formatEther(balances.eth || '0'));
|
|
667
327
|
const ethNeeded = parseFloat(ethAmount);
|
|
668
|
-
|
|
328
|
+
|
|
669
329
|
if (isNaN(ethNeeded) || isNaN(ethBalance) || ethNeeded > ethBalance) {
|
|
670
330
|
this.messagePopup.info(`Not enough ETH balance. You have ${ethBalance.toFixed(6)} ETH, need ${ethNeeded} ETH`, 'Insufficient Balance');
|
|
671
331
|
return;
|
|
@@ -674,7 +334,7 @@ export class SwapInterface extends Component {
|
|
|
674
334
|
const execAmountClean = execAmount.replace(/,/g, '');
|
|
675
335
|
const execBalance = BigInt(balances.exec || 0);
|
|
676
336
|
const execNeeded = BigInt(parseInt(execAmountClean) || 0);
|
|
677
|
-
|
|
337
|
+
|
|
678
338
|
if (execNeeded > execBalance) {
|
|
679
339
|
const execBalanceFormatted = parseInt(balances.exec || 0).toLocaleString();
|
|
680
340
|
const execNeededFormatted = parseInt(execAmountClean).toLocaleString();
|
|
@@ -683,12 +343,11 @@ export class SwapInterface extends Component {
|
|
|
683
343
|
}
|
|
684
344
|
}
|
|
685
345
|
|
|
686
|
-
// Check if a free mint token is being sold
|
|
687
346
|
if (direction === 'sell' && parseInt(execAmount.replace(/,/g, '')) <= 1000000 && freeMint) {
|
|
688
347
|
this.messagePopup.info('Free minted tokens cannot be sold directly.', 'Free Mint Restriction');
|
|
689
348
|
return;
|
|
690
349
|
}
|
|
691
|
-
|
|
350
|
+
|
|
692
351
|
const isLiquidityDeployed = this.isLiquidityDeployed();
|
|
693
352
|
const cleanExecAmount = this.state.execAmount.replace(/,/g, '');
|
|
694
353
|
|
|
@@ -696,7 +355,7 @@ export class SwapInterface extends Component {
|
|
|
696
355
|
const ethValue = this.blockchainService.parseEther(this.state.ethAmount);
|
|
697
356
|
const execAmountBI = this.blockchainService.parseExec(cleanExecAmount);
|
|
698
357
|
const address = await this.getAddress();
|
|
699
|
-
|
|
358
|
+
|
|
700
359
|
if (!address) {
|
|
701
360
|
this.messagePopup.error('No wallet address available. Please reconnect your wallet.', 'Wallet Error');
|
|
702
361
|
return;
|
|
@@ -707,19 +366,27 @@ export class SwapInterface extends Component {
|
|
|
707
366
|
} else {
|
|
708
367
|
const routerAddress = this.blockchainService.swapRouter?.address || this.blockchainService.swapRouterAddress;
|
|
709
368
|
const routerAllowance = await this.blockchainService.getApproval(address, routerAddress);
|
|
710
|
-
|
|
369
|
+
|
|
711
370
|
if (BigInt(routerAllowance) < BigInt(execAmountBI)) {
|
|
712
371
|
if (this.approveModal) {
|
|
713
372
|
try {
|
|
714
373
|
this.eventBus.off('approve:complete');
|
|
715
374
|
this.approveModal.handleClose();
|
|
716
|
-
} catch (e) {
|
|
375
|
+
} catch (e) { }
|
|
717
376
|
this.approveModal = null;
|
|
718
377
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
378
|
+
|
|
379
|
+
const modalRoot = document.createElement('div');
|
|
380
|
+
document.body.appendChild(modalRoot);
|
|
381
|
+
|
|
382
|
+
render(h(ApprovalModal, {
|
|
383
|
+
amount: cleanExecAmount,
|
|
384
|
+
blockchainService: this.blockchainService,
|
|
385
|
+
userAddress: address,
|
|
386
|
+
eventBus: this.eventBus,
|
|
387
|
+
ref: instance => this.approveModal = instance
|
|
388
|
+
}), modalRoot);
|
|
389
|
+
|
|
723
390
|
this.eventBus.once('approve:complete', async () => {
|
|
724
391
|
try {
|
|
725
392
|
await this.blockchainService.swapExactTokenForEthSupportingFeeOnTransferV2(address, { amount: execAmountBI });
|
|
@@ -727,19 +394,21 @@ export class SwapInterface extends Component {
|
|
|
727
394
|
this.messagePopup.error(`Swap Failed: ${error.message}`, 'Transaction Failed');
|
|
728
395
|
}
|
|
729
396
|
});
|
|
730
|
-
|
|
397
|
+
|
|
731
398
|
this.eventBus.once('approveModal:closed', () => {
|
|
399
|
+
if (modalRoot.parentNode) {
|
|
400
|
+
modalRoot.parentNode.removeChild(modalRoot);
|
|
401
|
+
}
|
|
732
402
|
this.approveModal = null;
|
|
733
403
|
});
|
|
734
|
-
|
|
735
|
-
this.approveModal
|
|
404
|
+
|
|
405
|
+
this.approveModal?.show();
|
|
736
406
|
return;
|
|
737
407
|
}
|
|
738
408
|
|
|
739
409
|
await this.blockchainService.swapExactTokenForEthSupportingFeeOnTransferV2(address, { amount: execAmountBI });
|
|
740
410
|
}
|
|
741
411
|
} else {
|
|
742
|
-
// Bonding curve logic
|
|
743
412
|
let proof;
|
|
744
413
|
try {
|
|
745
414
|
const currentTier = await this.blockchainService.getCurrentTier();
|
|
@@ -752,7 +421,7 @@ export class SwapInterface extends Component {
|
|
|
752
421
|
this.messagePopup.error('Failed to verify whitelist status.', 'Whitelist Check Failed');
|
|
753
422
|
return;
|
|
754
423
|
}
|
|
755
|
-
|
|
424
|
+
|
|
756
425
|
let adjustedExecAmount = cleanExecAmount;
|
|
757
426
|
if (this.state.direction === 'buy' && this.state.freeSupply > 0 && !this.state.freeMint) {
|
|
758
427
|
const numAmount = parseInt(cleanExecAmount);
|
|
@@ -792,181 +461,131 @@ export class SwapInterface extends Component {
|
|
|
792
461
|
}
|
|
793
462
|
}
|
|
794
463
|
|
|
795
|
-
handleQuickFill(e) {
|
|
796
|
-
e.preventDefault();
|
|
797
|
-
|
|
798
|
-
const amount = e.target.dataset.amount;
|
|
799
|
-
const percentage = e.target.dataset.percentage;
|
|
800
|
-
|
|
801
|
-
let value;
|
|
802
|
-
|
|
803
|
-
if (amount) {
|
|
804
|
-
value = amount;
|
|
805
|
-
} else if (percentage) {
|
|
806
|
-
const { balances } = this.state;
|
|
807
|
-
const execBalance = balances.exec;
|
|
808
|
-
|
|
809
|
-
if (!execBalance || execBalance === '0') {
|
|
810
|
-
console.warn('No EXEC balance available for quick fill');
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
let readableBalance = BigInt(execBalance) / BigInt(1e18);
|
|
815
|
-
|
|
816
|
-
if (this.state.freeMint) {
|
|
817
|
-
readableBalance = readableBalance - BigInt(1000000);
|
|
818
|
-
if (readableBalance <= 0) {
|
|
819
|
-
this.messagePopup.info('You only have free mint tokens which cannot be sold.', 'Cannot Quick Fill');
|
|
820
|
-
return;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
const amount = (readableBalance * BigInt(percentage)) / BigInt(100);
|
|
825
|
-
value = amount.toString();
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
this.handleInput('top', value);
|
|
829
|
-
}
|
|
830
|
-
|
|
831
464
|
handleContractDataUpdate() {
|
|
832
465
|
try {
|
|
833
466
|
const previousPhase = this.state.isPhase2;
|
|
834
467
|
const wasDataReady = this.state.dataReady;
|
|
835
|
-
const phaseWasUnknown = previousPhase === null;
|
|
836
|
-
|
|
837
|
-
const { contractData } = this.state;
|
|
838
468
|
const isPhase2 = this.isLiquidityDeployed();
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
this.setState({
|
|
847
|
-
requestAnimationFrame(() => this.mountChildComponents());
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
if (!wasDataReady && this.state.dataReady) {
|
|
852
|
-
console.log(`[${this.instanceId}] Data ready, mounting child components`);
|
|
853
|
-
this.setState({ dataReady: true, isPhase2 });
|
|
854
|
-
requestAnimationFrame(() => this.mountChildComponents());
|
|
855
|
-
return;
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
if (previousPhase !== this.state.isPhase2) {
|
|
859
|
-
console.log(`Phase changed`);
|
|
860
|
-
if (this.swapInputs) {
|
|
861
|
-
this.swapInputs.updateProps({ isPhase2: this.state.isPhase2 });
|
|
862
|
-
}
|
|
863
|
-
const priceContainer = this.element.querySelector('.price-display-container');
|
|
864
|
-
if (priceContainer && this.priceDisplay) {
|
|
865
|
-
this.priceDisplay.mount(priceContainer);
|
|
866
|
-
}
|
|
867
|
-
return;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
const priceContainer = this.element.querySelector('.price-display-container');
|
|
871
|
-
if (priceContainer && this.priceDisplay) {
|
|
872
|
-
const shouldRemount = !this.priceDisplay.element || !priceContainer.contains(this.priceDisplay.element);
|
|
873
|
-
if (shouldRemount) {
|
|
874
|
-
this.priceDisplay.mount(priceContainer);
|
|
875
|
-
} else {
|
|
876
|
-
this.priceDisplay.update();
|
|
877
|
-
}
|
|
469
|
+
|
|
470
|
+
if (previousPhase === null || !wasDataReady) {
|
|
471
|
+
this.setState({
|
|
472
|
+
isPhase2,
|
|
473
|
+
dataReady: true
|
|
474
|
+
});
|
|
475
|
+
} else if (previousPhase !== isPhase2) {
|
|
476
|
+
this.setState({ isPhase2 });
|
|
878
477
|
}
|
|
879
478
|
} catch (error) {
|
|
880
479
|
console.error('Error in handleContractDataUpdate:', error);
|
|
881
|
-
if (!this.state.dataReady) {
|
|
882
|
-
this.state.dataReady = true;
|
|
883
|
-
this.state.isPhase2 = this.isLiquidityDeployed();
|
|
884
|
-
if (!this.element || !this.element.innerHTML) {
|
|
885
|
-
this.update();
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
480
|
}
|
|
889
481
|
}
|
|
890
482
|
|
|
891
|
-
render() {
|
|
892
|
-
console.log('🎨 SwapInterface.render - Starting render');
|
|
893
|
-
const { direction, isPhase2, dataReady, balances, freeMint, freeSupply } = this.state;
|
|
894
|
-
|
|
895
|
-
if (!dataReady || isPhase2 === null) {
|
|
896
|
-
return `
|
|
897
|
-
<div class="price-display-container"></div>
|
|
898
|
-
<div class="quick-fill-buttons-container"></div>
|
|
899
|
-
<div class="swap-inputs-container">
|
|
900
|
-
<div style="padding: 20px; text-align: center;">Loading swap interface...</div>
|
|
901
|
-
</div>
|
|
902
|
-
<div class="transaction-options-container"></div>
|
|
903
|
-
<div class="swap-button-container"></div>
|
|
904
|
-
`;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
console.log('Render - Current State:', { direction, freeMint, freeSupply, isPhase2 });
|
|
908
|
-
|
|
909
|
-
const formattedEthBalance = parseFloat(balances.eth).toFixed(6);
|
|
910
|
-
const formattedExecBalance = parseInt(balances.exec).toLocaleString();
|
|
911
|
-
const availableExecBalance = direction === 'sell' && freeMint
|
|
912
|
-
? `Available: ${(parseInt(balances.exec) - 1000000).toLocaleString()}`
|
|
913
|
-
: `Balance: ${formattedExecBalance}`;
|
|
914
|
-
|
|
915
|
-
const result = `
|
|
916
|
-
<div class="price-display-container"></div>
|
|
917
|
-
${direction === 'sell' && freeMint && !isPhase2 ?
|
|
918
|
-
`<div class="free-mint-notice">You have 1,000,000 $EXEC you received for free that cannot be sold here.</div>`
|
|
919
|
-
: direction === 'buy' && freeSupply > 0 && !freeMint && !isPhase2 ?
|
|
920
|
-
`<div class="free-mint-notice free-mint-bonus">1,000,000 $EXEC will be added to your purchase. Thank you.</div>`
|
|
921
|
-
: ''
|
|
922
|
-
}
|
|
923
|
-
<div class="quick-fill-buttons-container"></div>
|
|
924
|
-
<div class="swap-inputs-container"></div>
|
|
925
|
-
<div class="transaction-options-container"></div>
|
|
926
|
-
<div class="swap-button-container"></div>
|
|
927
|
-
`;
|
|
928
|
-
console.log('🎨 SwapInterface.render - Completed render');
|
|
929
|
-
return result;
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
/**
|
|
933
|
-
* Get the user's wallet address, resolving any promise if needed
|
|
934
|
-
* @returns {Promise<string>} Resolved address
|
|
935
|
-
*/
|
|
936
483
|
async getAddress() {
|
|
937
484
|
try {
|
|
938
|
-
|
|
939
|
-
const resolvedAddress = await Promise.resolve(this._address);
|
|
940
|
-
|
|
941
|
-
// Log the resolved address for debugging
|
|
942
|
-
console.log(`[${this.instanceId}] Resolved address: ${resolvedAddress}`);
|
|
943
|
-
|
|
944
|
-
return resolvedAddress;
|
|
485
|
+
return await Promise.resolve(this._address);
|
|
945
486
|
} catch (error) {
|
|
946
487
|
console.error(`[${this.instanceId}] Error resolving address:`, error);
|
|
947
488
|
return null;
|
|
948
489
|
}
|
|
949
490
|
}
|
|
950
|
-
|
|
951
|
-
/**
|
|
952
|
-
* Update the user's wallet address
|
|
953
|
-
* @param {string} newAddress - The new wallet address
|
|
954
|
-
*/
|
|
491
|
+
|
|
955
492
|
setAddress(newAddress) {
|
|
956
493
|
this._address = newAddress;
|
|
957
494
|
}
|
|
958
|
-
|
|
959
|
-
/**
|
|
960
|
-
* Property to maintain backward compatibility with old code
|
|
961
|
-
*/
|
|
495
|
+
|
|
962
496
|
get address() {
|
|
963
497
|
return this._address;
|
|
964
498
|
}
|
|
965
|
-
|
|
966
|
-
/**
|
|
967
|
-
* Property setter to maintain backward compatibility
|
|
968
|
-
*/
|
|
499
|
+
|
|
969
500
|
set address(newAddress) {
|
|
970
501
|
this._address = newAddress;
|
|
971
502
|
}
|
|
972
|
-
|
|
503
|
+
|
|
504
|
+
render() {
|
|
505
|
+
const { direction, isPhase2, dataReady, balances, freeMint, freeSupply, ethAmount, execAmount, calculatingAmount } = this.state;
|
|
506
|
+
|
|
507
|
+
if (!dataReady || isPhase2 === null) {
|
|
508
|
+
return h('div', { className: 'swap-interface' },
|
|
509
|
+
h('div', { className: 'price-display-container' }),
|
|
510
|
+
h('div', { className: 'quick-fill-buttons-container' }),
|
|
511
|
+
h('div', { className: 'swap-inputs-container', style: { padding: '20px', textAlign: 'center' } },
|
|
512
|
+
'Loading swap interface...'
|
|
513
|
+
),
|
|
514
|
+
h('div', { className: 'transaction-options-container' }),
|
|
515
|
+
h('div', { className: 'swap-button-container' })
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const formattedEthBalance = parseFloat(balances.eth).toFixed(6);
|
|
520
|
+
const formattedExecBalance = parseInt(balances.exec).toLocaleString();
|
|
521
|
+
|
|
522
|
+
return h('div', { className: 'swap-interface' },
|
|
523
|
+
h(PriceDisplay, {
|
|
524
|
+
price: this.state.price,
|
|
525
|
+
contractData: this.state.contractData,
|
|
526
|
+
eventBus: this.eventBus
|
|
527
|
+
}),
|
|
528
|
+
|
|
529
|
+
// Free mint notice
|
|
530
|
+
direction === 'sell' && freeMint && !isPhase2 &&
|
|
531
|
+
h('div', { className: 'free-mint-notice' },
|
|
532
|
+
'You have 1,000,000 $EXEC you received for free that cannot be sold here.'
|
|
533
|
+
),
|
|
534
|
+
direction === 'buy' && freeSupply > 0 && !freeMint && !isPhase2 &&
|
|
535
|
+
h('div', { className: 'free-mint-notice free-mint-bonus' },
|
|
536
|
+
'1,000,000 $EXEC will be added to your purchase. Thank you.'
|
|
537
|
+
),
|
|
538
|
+
|
|
539
|
+
// Quick fill buttons
|
|
540
|
+
h('div', { className: 'quick-fill-buttons-container' },
|
|
541
|
+
h('div', { className: 'quick-fill-buttons' },
|
|
542
|
+
direction === 'buy' ? [
|
|
543
|
+
h('button', { key: '0.0025', onClick: () => this.handleQuickFill('0.0025') }, '0.0025'),
|
|
544
|
+
h('button', { key: '0.01', onClick: () => this.handleQuickFill('0.01') }, '0.01'),
|
|
545
|
+
h('button', { key: '0.05', onClick: () => this.handleQuickFill('0.05') }, '0.05'),
|
|
546
|
+
h('button', { key: '0.1', onClick: () => this.handleQuickFill('0.1') }, '0.1')
|
|
547
|
+
] : [
|
|
548
|
+
h('button', { key: '25', onClick: () => this.handleQuickFill(null, 25) }, '25%'),
|
|
549
|
+
h('button', { key: '50', onClick: () => this.handleQuickFill(null, 50) }, '50%'),
|
|
550
|
+
h('button', { key: '75', onClick: () => this.handleQuickFill(null, 75) }, '75%'),
|
|
551
|
+
h('button', { key: '100', onClick: () => this.handleQuickFill(null, 100) }, '100%')
|
|
552
|
+
]
|
|
553
|
+
)
|
|
554
|
+
),
|
|
555
|
+
|
|
556
|
+
// Swap inputs
|
|
557
|
+
h(SwapInputs, {
|
|
558
|
+
direction,
|
|
559
|
+
ethAmount,
|
|
560
|
+
execAmount,
|
|
561
|
+
calculatingAmount,
|
|
562
|
+
freeMint,
|
|
563
|
+
balances,
|
|
564
|
+
isPhase2,
|
|
565
|
+
onInput: this.bind(this.handleInput)
|
|
566
|
+
}),
|
|
567
|
+
|
|
568
|
+
// Direction switch
|
|
569
|
+
h('div', { className: 'direction-switch-container' },
|
|
570
|
+
h('button', {
|
|
571
|
+
className: 'direction-switch',
|
|
572
|
+
onClick: this.bind(this.handleDirectionSwitch)
|
|
573
|
+
}, '\u2195')
|
|
574
|
+
),
|
|
575
|
+
|
|
576
|
+
// Transaction options (Phase 1 only)
|
|
577
|
+
!isPhase2 && h(TransactionOptions, {
|
|
578
|
+
eventBus: this.eventBus,
|
|
579
|
+
swapDirection: direction,
|
|
580
|
+
isPhase2
|
|
581
|
+
}),
|
|
582
|
+
|
|
583
|
+
// Swap button
|
|
584
|
+
h(SwapButton, {
|
|
585
|
+
direction,
|
|
586
|
+
disabled: calculatingAmount,
|
|
587
|
+
onClick: this.bind(this.handleSwap)
|
|
588
|
+
})
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
}
|