@monygroupcorp/micro-web3 1.2.4 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monygroupcorp/micro-web3",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
4
4
  "description": "A lean, reusable Web3 toolkit with components for wallet connection, IPFS, and common Web3 UI patterns.",
5
5
  "main": "dist/micro-web3.cjs",
6
6
  "module": "dist/micro-web3.esm.js",
@@ -20,7 +20,7 @@
20
20
  "author": "arthurt <mony.group.corporation@gmail.com>",
21
21
  "license": "MIT",
22
22
  "peerDependencies": {
23
- "@monygroupcorp/microact": ">=0.1.0"
23
+ "@monygroupcorp/microact": ">=0.2.0"
24
24
  },
25
25
  "dependencies": {
26
26
  "ethers": "^5.7.2"
@@ -1,4 +1,4 @@
1
- import { Component } from '@monygroupcorp/microact';
1
+ import { Component, h } from '@monygroupcorp/microact';
2
2
 
3
3
  export class BondingCurve extends Component {
4
4
  constructor(props) {
@@ -14,13 +14,12 @@ export class BondingCurve extends Component {
14
14
  liquidityPool: props.contractData?.liquidityPool || null,
15
15
  chainId: props.chainId || null
16
16
  };
17
+ this.canvasRef = null;
17
18
  }
18
19
 
19
- onMount() {
20
- this.unsubscribeEvents = [
21
- this.eventBus.on('contractData:updated', (data) => this.updateProps({ contractData: data })),
22
- this.eventBus.on('price:updated', (data) => this.updateProps({ price: data.price }))
23
- ];
20
+ didMount() {
21
+ this.subscribe('contractData:updated', (data) => this.handleContractDataUpdate(data));
22
+ this.subscribe('price:updated', (data) => this.handlePriceUpdate(data));
24
23
 
25
24
  this.resizeHandler = () => requestAnimationFrame(() => this.drawCurve());
26
25
  window.addEventListener('resize', this.resizeHandler);
@@ -32,40 +31,39 @@ export class BondingCurve extends Component {
32
31
  }
33
32
  }
34
33
 
35
- updateProps(newProps) {
36
- const newState = { ...this.state };
37
- let shouldUpdate = false;
38
-
39
- if (newProps.contractData) {
40
- const { contractData } = newProps;
41
- newState.totalBondingSupply = contractData.totalBondingSupply;
42
- newState.totalMessages = contractData.totalMessages;
43
- newState.totalNFTs = contractData.totalNFTs;
44
- newState.contractEthBalance = contractData.contractEthBalance;
45
- if (newState.liquidityPool !== contractData.liquidityPool) {
46
- newState.liquidityPool = contractData.liquidityPool;
47
- shouldUpdate = true; // Phase changed
48
- }
49
- newState.dataReady = true;
50
- shouldUpdate = true;
51
- }
52
- if (newProps.price !== undefined) {
53
- newState.currentPrice = newProps.price;
54
- shouldUpdate = true;
34
+ willUnmount() {
35
+ if (this.resizeHandler) {
36
+ window.removeEventListener('resize', this.resizeHandler);
55
37
  }
56
- if (newProps.chainId !== undefined) {
57
- newState.chainId = newProps.chainId;
58
- shouldUpdate = true;
38
+ }
39
+
40
+ handleContractDataUpdate(contractData) {
41
+ const newState = {
42
+ totalBondingSupply: contractData.totalBondingSupply,
43
+ totalMessages: contractData.totalMessages,
44
+ totalNFTs: contractData.totalNFTs,
45
+ contractEthBalance: contractData.contractEthBalance,
46
+ dataReady: true
47
+ };
48
+
49
+ const oldLiquidityPool = this.state.liquidityPool;
50
+ if (oldLiquidityPool !== contractData.liquidityPool) {
51
+ newState.liquidityPool = contractData.liquidityPool;
59
52
  }
60
-
53
+
61
54
  this.setState(newState);
62
55
 
63
- if (shouldUpdate) {
64
- if (this.isLiquidityDeployed()) {
65
- this.renderDexToolsChart();
66
- } else {
67
- this.drawCurve();
68
- }
56
+ if (this.isLiquidityDeployed()) {
57
+ this.renderDexToolsChart();
58
+ } else {
59
+ this.drawCurve();
60
+ }
61
+ }
62
+
63
+ handlePriceUpdate(data) {
64
+ this.setState({ currentPrice: data.price });
65
+ if (!this.isLiquidityDeployed()) {
66
+ this.drawCurve();
69
67
  }
70
68
  }
71
69
 
@@ -75,57 +73,27 @@ export class BondingCurve extends Component {
75
73
  }
76
74
 
77
75
  renderDexToolsChart() {
76
+ if (!this.containerRef) return;
77
+
78
78
  try {
79
- const container = this.element.querySelector('.bonding-curve');
80
- if (!container) {
81
- return;
82
- }
79
+ const networkName = this.getNetworkName(this.state.chainId);
80
+ const chartUrl = `https://www.dextools.io/widget-chart/en/${networkName}/pe-light/${this.state.liquidityPool}?theme=dark&chartType=2&chartResolution=30&drawingToolbars=false`;
83
81
 
84
- // Clear any existing content
85
- container.innerHTML = '';
86
-
87
- // Construct the DEXTools URL dynamically
88
- const networkName = this.getNetworkName(this.state.chainId);
89
- const chartUrl = `https://www.dextools.io/widget-chart/en/${networkName}/pe-light/${this.state.liquidityPool}?theme=dark&chartType=2&chartResolution=30&drawingToolbars=false`;
90
-
91
- // Use exact DEXTools iframe format from share button
92
- // Note: This will fail on localhost due to X-Frame-Options, but that's expected
93
- container.innerHTML = `
94
- <iframe
95
- id="dextools-widget"
96
- title="$EXEC DEXTools Trading Chart"
97
- width="100%"
98
- height="100%"
99
- src="${chartUrl}"
100
- style="border: none;"
101
- onerror="console.warn('DEXTools chart failed to load (expected on localhost)')"
102
- ></iframe>
103
- `;
104
-
105
- // Add error handler for iframe load failures (expected on localhost)
106
- const iframe = container.querySelector('#dextools-widget');
107
- if (iframe) {
108
- iframe.onerror = () => {
109
- console.warn('DEXTools chart iframe failed to load (expected on localhost due to X-Frame-Options)');
110
- // Show a fallback message instead of breaking
111
- container.innerHTML = `
112
- <div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #888;">
113
- <div>Chart will be available in production</div>
114
- </div>
115
- `;
116
- };
117
- }
82
+ // Clear and insert iframe
83
+ this.containerRef.innerHTML = '';
84
+ const iframe = document.createElement('iframe');
85
+ iframe.id = 'dextools-widget';
86
+ iframe.title = '$EXEC DEXTools Trading Chart';
87
+ iframe.width = '100%';
88
+ iframe.height = '100%';
89
+ iframe.src = chartUrl;
90
+ iframe.style.border = 'none';
91
+ iframe.onerror = () => {
92
+ this.containerRef.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #888;"><div>Chart unavailable</div></div>';
93
+ };
94
+ this.containerRef.appendChild(iframe);
118
95
  } catch (error) {
119
96
  console.error('Error rendering DEXTools chart:', error);
120
- // Don't let chart errors break the component
121
- const container = this.element.querySelector('.bonding-curve');
122
- if (container) {
123
- container.innerHTML = `
124
- <div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #888;">
125
- <div>Chart unavailable (expected on localhost)</div>
126
- </div>
127
- `;
128
- }
129
97
  }
130
98
  }
131
99
 
@@ -133,27 +101,24 @@ export class BondingCurve extends Component {
133
101
  const networks = {
134
102
  1: 'ether',
135
103
  5: 'goerli',
136
- // Add more networks as needed
137
104
  };
138
105
  return networks[chainId] || 'ether';
139
106
  }
140
107
 
141
108
  drawCurve() {
142
- const canvas = this.element.querySelector('#curveChart');
143
- if (!canvas) {
144
- return;
145
- }
109
+ if (!this.canvasRef) return;
146
110
 
111
+ const canvas = this.canvasRef;
147
112
  const ctx = canvas.getContext('2d');
148
-
113
+
149
114
  canvas.width = canvas.offsetWidth;
150
115
  canvas.height = canvas.offsetHeight;
151
-
116
+
152
117
  ctx.clearRect(0, 0, canvas.width, canvas.height);
153
118
  this.drawBaseCurve(ctx, canvas);
154
119
 
155
120
  if (this.state.dataReady) {
156
- this.drawDataElements(ctx);
121
+ this.drawDataElements(ctx, canvas);
157
122
  } else {
158
123
  this.drawPlaceholderLabels(ctx);
159
124
  }
@@ -169,11 +134,11 @@ export class BondingCurve extends Component {
169
134
  this.drawCurvePath(ctx, points);
170
135
  }
171
136
 
172
- drawDataElements(ctx) {
137
+ drawDataElements(ctx, canvas) {
173
138
  const curve = (x) => Math.pow(0.1 + (x * 0.8), 3.5);
174
139
  const maxPrice = 0.08;
175
- const currentPosition = Math.max(0.1, Math.min(0.9, Math.pow(this.state.currentPrice / maxPrice, 1/3.5)));
176
- const points = this.calculateCurvePoints(this.element.querySelector('#curveChart'), curve);
140
+ const currentPosition = Math.max(0.1, Math.min(0.9, Math.pow(this.state.currentPrice / maxPrice, 1 / 3.5)));
141
+ const points = this.calculateCurvePoints(canvas, curve);
177
142
  this.drawCurrentPosition(ctx, points, currentPosition);
178
143
  this.drawLabels(ctx);
179
144
  }
@@ -210,24 +175,24 @@ export class BondingCurve extends Component {
210
175
 
211
176
  drawCurrentPosition(ctx, points, currentPosition) {
212
177
  const segmentSize = 0.05;
213
- const startIndex = Math.floor((currentPosition - segmentSize/2) * points.length);
214
- const endIndex = Math.floor((currentPosition + segmentSize/2) * points.length);
215
-
178
+ const startIndex = Math.floor((currentPosition - segmentSize / 2) * points.length);
179
+ const endIndex = Math.floor((currentPosition + segmentSize / 2) * points.length);
180
+
216
181
  if (startIndex >= 0 && endIndex < points.length) {
217
182
  const curveColor = getComputedStyle(document.documentElement).getPropertyValue('--bonding-curve-color').trim() || '#764ba2';
218
183
  ctx.beginPath();
219
184
  ctx.strokeStyle = curveColor;
220
185
  ctx.lineWidth = 4;
221
-
186
+
222
187
  ctx.moveTo(points[startIndex].x, points[startIndex].y);
223
188
  for (let i = startIndex; i <= endIndex; i++) {
224
189
  ctx.lineTo(points[i].x, points[i].y);
225
190
  }
226
191
  ctx.stroke();
227
-
192
+
228
193
  const centerIndex = Math.floor((startIndex + endIndex) / 2);
229
194
  const centerPoint = points[centerIndex];
230
-
195
+
231
196
  ctx.beginPath();
232
197
  ctx.arc(centerPoint.x, centerPoint.y, 4, 0, Math.PI * 2);
233
198
  ctx.fillStyle = '#FF0000';
@@ -244,23 +209,22 @@ export class BondingCurve extends Component {
244
209
  ctx.fillText(`Total NFTs: ${this.state.totalNFTs.toLocaleString()}`, 10, 80);
245
210
  ctx.fillText(`Contract ETH Balance: ${this.state.contractEthBalance}`, 10, 100);
246
211
  }
247
-
248
- unmount() {
249
- if (this.unsubscribeEvents) {
250
- this.unsubscribeEvents.forEach(unsubscribe => unsubscribe());
251
- }
252
- if (this.resizeHandler) {
253
- window.removeEventListener('resize', this.resizeHandler);
254
- }
255
- super.unmount();
256
- }
257
212
 
258
213
  render() {
259
- return `
260
- <div class="bonding-curve marble-bg">
261
- ${this.isLiquidityDeployed() ? '' : '<canvas id="curveChart"></canvas>'}
262
- </div>
263
- `;
214
+ const isLiquidityDeployed = this.isLiquidityDeployed();
215
+
216
+ return h('div', {
217
+ className: 'bonding-curve marble-bg',
218
+ ref: el => this.containerRef = el
219
+ },
220
+ !isLiquidityDeployed && h('canvas', {
221
+ id: 'curveChart',
222
+ ref: el => {
223
+ this.canvasRef = el;
224
+ if (el) this.drawCurve();
225
+ }
226
+ })
227
+ );
264
228
  }
265
229
 
266
230
  static get styles() {
@@ -293,4 +257,4 @@ export class BondingCurve extends Component {
293
257
  }
294
258
  }
295
259
 
296
- export default BondingCurve;
260
+ export default BondingCurve;
@@ -1,4 +1,4 @@
1
- import { Component } from '@monygroupcorp/microact';
1
+ import { Component, h } from '@monygroupcorp/microact';
2
2
 
3
3
  export class BalanceDisplay extends Component {
4
4
  constructor(props) {
@@ -9,73 +9,49 @@ export class BalanceDisplay extends Component {
9
9
  loading: props.loading !== undefined ? props.loading : true,
10
10
  error: props.error || null,
11
11
  };
12
-
13
- this.handleBalanceUpdate = this.handleBalanceUpdate.bind(this);
14
12
  }
15
13
 
16
- template() {
17
- const { balances, loading, error } = this.state;
18
-
19
- return `
20
- <div class="balance-display marble-bg ${loading ? 'loading' : ''} ${error ? 'error' : ''}">
21
- <div class="balance-header">
22
- <h3>Your Balances</h3>
23
- ${balances.lastUpdated ? `
24
- <span class="last-updated">
25
- Last updated: ${new Date(balances.lastUpdated).toLocaleTimeString()}
26
- </span>
27
- ` : ''}
28
- </div>
29
-
30
- <div class="balance-content">
31
- ${loading ? `
32
- <div class="loading-indicator">Loading balances...</div>
33
- ` : error ? `
34
- <div class="error-message">${error}</div>
35
- ` : `
36
- <div class="balance-grid">
37
- <div class="balance-item eth">
38
- <span class="label">ETH Balance</span>
39
- <span class="amount">${balances.eth}</span>
40
- </div>
41
- <div class="balance-item exec">
42
- <span class="label">EXEC Balance</span>
43
- <span class="amount">${balances.exec}</span>
44
- </div>
45
- </div>
46
- `}
47
- </div>
48
- </div>
49
- `;
50
- }
51
-
52
- render() {
53
- return this.template();
54
- }
55
-
56
- onMount() {
14
+ didMount() {
57
15
  if (this.eventBus) {
58
- this.unsubscribeEvents = [
59
- this.eventBus.on('balances:updated', this.handleBalanceUpdate)
60
- ];
16
+ this.subscribe('balances:updated', this.bind(this.handleBalanceUpdate));
61
17
  }
62
18
  }
63
19
 
64
- onUnmount() {
65
- if (this.unsubscribeEvents) {
66
- this.unsubscribeEvents.forEach(unsubscribe => unsubscribe());
67
- }
20
+ handleBalanceUpdate(balances) {
21
+ this.setState({ balances, loading: false, error: null });
68
22
  }
69
23
 
70
- updateProps(newProps) {
71
- this.setState({
72
- balances: newProps.balances !== undefined ? newProps.balances : this.state.balances,
73
- loading: newProps.loading !== undefined ? newProps.loading : this.state.loading,
74
- error: newProps.error !== undefined ? newProps.error : this.state.error,
75
- });
76
- }
24
+ render() {
25
+ const { balances, loading, error } = this.state;
77
26
 
78
- handleBalanceUpdate(balances) {
79
- this.setState({ balances, loading: false, error: null });
27
+ const classNames = ['balance-display', 'marble-bg'];
28
+ if (loading) classNames.push('loading');
29
+ if (error) classNames.push('error');
30
+
31
+ return h('div', { className: classNames.join(' ') },
32
+ h('div', { className: 'balance-header' },
33
+ h('h3', null, 'Your Balances'),
34
+ balances.lastUpdated && h('span', { className: 'last-updated' },
35
+ `Last updated: ${new Date(balances.lastUpdated).toLocaleTimeString()}`
36
+ )
37
+ ),
38
+
39
+ h('div', { className: 'balance-content' },
40
+ loading
41
+ ? h('div', { className: 'loading-indicator' }, 'Loading balances...')
42
+ : error
43
+ ? h('div', { className: 'error-message' }, error)
44
+ : h('div', { className: 'balance-grid' },
45
+ h('div', { className: 'balance-item eth' },
46
+ h('span', { className: 'label' }, 'ETH Balance'),
47
+ h('span', { className: 'amount' }, balances.eth)
48
+ ),
49
+ h('div', { className: 'balance-item exec' },
50
+ h('span', { className: 'label' }, 'EXEC Balance'),
51
+ h('span', { className: 'amount' }, balances.exec)
52
+ )
53
+ )
54
+ )
55
+ );
80
56
  }
81
- }
57
+ }
@@ -1,4 +1,4 @@
1
- import { Component } from '@monygroupcorp/microact';
1
+ import { Component, h } from '@monygroupcorp/microact';
2
2
 
3
3
  // Add event name constants
4
4
  const EVENTS = {
@@ -18,38 +18,15 @@ export class PriceDisplay extends Component {
18
18
  loading: props.loading !== undefined ? props.loading : true,
19
19
  error: props.error || null
20
20
  };
21
-
22
- this.handlePriceUpdate = this.handlePriceUpdate.bind(this);
23
- this.handleStatusUpdate = this.handleStatusUpdate.bind(this);
24
21
  }
25
22
 
26
- onMount() {
23
+ didMount() {
27
24
  if (this.eventBus) {
28
- this.eventBus.on(EVENTS.UPDATE.PRICE, this.handlePriceUpdate);
29
- this.eventBus.on(EVENTS.UPDATE.STATUS, this.handleStatusUpdate);
25
+ this.subscribe(EVENTS.UPDATE.PRICE, this.bind(this.handlePriceUpdate));
26
+ this.subscribe(EVENTS.UPDATE.STATUS, this.bind(this.handleStatusUpdate));
30
27
  }
31
28
  }
32
29
 
33
- onUnmount() {
34
- if (this.eventBus) {
35
- this.eventBus.off(EVENTS.UPDATE.PRICE, this.handlePriceUpdate);
36
- this.eventBus.off(EVENTS.UPDATE.STATUS, this.handleStatusUpdate);
37
- }
38
- }
39
-
40
- updateProps(newProps) {
41
- this.setState({
42
- price: newProps.price !== undefined ? newProps.price : this.state.price,
43
- lastUpdated: newProps.lastUpdated !== undefined ? newProps.lastUpdated : this.state.lastUpdated,
44
- loading: newProps.loading !== undefined ? newProps.loading : this.state.loading,
45
- error: newProps.error !== undefined ? newProps.error : this.state.error
46
- });
47
- }
48
-
49
- setState(newState) {
50
- super.setState(newState);
51
- }
52
-
53
30
  handlePriceUpdate({ price }) {
54
31
  this.setState({
55
32
  price: price || 0,
@@ -61,51 +38,46 @@ export class PriceDisplay extends Component {
61
38
  this.setState({ loading, error });
62
39
  }
63
40
 
64
- template() {
41
+ render() {
65
42
  const { price, lastUpdated, loading, error } = this.state;
66
-
67
- if (loading) return `
68
- <div class="price-display loading marble-bg">
69
- <div class="price-header">
70
- <h3>Cult Exec </h3>
71
- <h3>Bonding Curve Presale</h3>
72
- </div>
73
- <div class="price-content">
74
- <div class="loading-indicator">Loading...</div>
75
- </div>
76
- </div>`;
77
-
78
- if (error) return `
79
- <div class="price-display error marble-bg">
80
- <div class="price-header">
81
- <h3>Cult Exec </h3>
82
- <h3>Bonding Curve Presale</h3>
83
- </div>
84
- <div class="price-content">
85
- <div class="error-message">Error: ${error}</div>
86
- </div>
87
- </div>`;
88
-
89
- return `
90
- <div class="price-display marble-bg">
91
- <div class="price-header">
92
- <h3>Cult Exec </h3>
93
- <h3>Bonding Curve Presale</h3>
94
- </div>
95
-
96
- <div class="price-content">
97
- <div class="price-value">
98
- <span class="amount">${Number(price).toFixed(8)}</span>
99
- <span class="currency">ETH / Cult Exec</span>
100
- </div>
101
- </div>
102
- </div>
103
- `;
104
- }
105
43
 
106
- render() {
107
- const result = this.template();
108
- return result;
44
+ if (loading) {
45
+ return h('div', { className: 'price-display loading marble-bg' },
46
+ h('div', { className: 'price-header' },
47
+ h('h3', null, 'Cult Exec '),
48
+ h('h3', null, 'Bonding Curve Presale')
49
+ ),
50
+ h('div', { className: 'price-content' },
51
+ h('div', { className: 'loading-indicator' }, 'Loading...')
52
+ )
53
+ );
54
+ }
55
+
56
+ if (error) {
57
+ return h('div', { className: 'price-display error marble-bg' },
58
+ h('div', { className: 'price-header' },
59
+ h('h3', null, 'Cult Exec '),
60
+ h('h3', null, 'Bonding Curve Presale')
61
+ ),
62
+ h('div', { className: 'price-content' },
63
+ h('div', { className: 'error-message' }, `Error: ${error}`)
64
+ )
65
+ );
66
+ }
67
+
68
+ return h('div', { className: 'price-display marble-bg' },
69
+ h('div', { className: 'price-header' },
70
+ h('h3', null, 'Cult Exec '),
71
+ h('h3', null, 'Bonding Curve Presale')
72
+ ),
73
+
74
+ h('div', { className: 'price-content' },
75
+ h('div', { className: 'price-value' },
76
+ h('span', { className: 'amount' }, Number(price).toFixed(8)),
77
+ h('span', { className: 'currency' }, 'ETH / Cult Exec')
78
+ )
79
+ )
80
+ );
109
81
  }
110
82
 
111
83
  // Add component styles
@@ -211,4 +183,4 @@ export class PriceDisplay extends Component {
211
183
  }
212
184
  `;
213
185
  }
214
- }
186
+ }