stylus-toolkit 0.2.10 → 2.0.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/README.md +230 -80
- package/dist/cli.js +9 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +3 -2
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/dashboard.d.ts +6 -0
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/commands/dashboard.js +48 -0
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +17 -80
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +157 -48
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/profile.d.ts.map +1 -1
- package/dist/commands/profile.js +74 -44
- package/dist/commands/profile.js.map +1 -1
- package/dist/config/constants.d.ts +56 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +26 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/profiler/comparator.d.ts.map +1 -1
- package/dist/profiler/comparator.js +3 -7
- package/dist/profiler/comparator.js.map +1 -1
- package/dist/profiler/gas-profiler.d.ts.map +1 -1
- package/dist/profiler/gas-profiler.js +30 -51
- package/dist/profiler/gas-profiler.js.map +1 -1
- package/dist/storage/results-store.d.ts +3 -0
- package/dist/storage/results-store.d.ts.map +1 -1
- package/dist/storage/results-store.js +25 -0
- package/dist/storage/results-store.js.map +1 -1
- package/dist/utils/gas-estimator.d.ts +22 -0
- package/dist/utils/gas-estimator.d.ts.map +1 -0
- package/dist/utils/gas-estimator.js +46 -0
- package/dist/utils/gas-estimator.js.map +1 -0
- package/package.json +5 -1
- package/src/dashboard/dashboard.js +276 -0
- package/src/dashboard/index.html +147 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface GasEstimationConfig {
|
|
2
|
+
baseGas: number;
|
|
3
|
+
activationGas: number;
|
|
4
|
+
perByteGas: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class GasEstimator {
|
|
7
|
+
private static readonly STYLUS_DEPLOY_CONFIG;
|
|
8
|
+
private static readonly STYLUS_PROFILE_CONFIG;
|
|
9
|
+
private static readonly EVM_CONFIG;
|
|
10
|
+
/**
|
|
11
|
+
* Estimate gas for actual deployment (deploy command).
|
|
12
|
+
* Includes full 14M activation cost + 2.5x safety buffer.
|
|
13
|
+
*/
|
|
14
|
+
static estimateDeploymentGas(bytecodeSize: number, language: 'rust' | 'solidity', safetyMultiplier?: number): number;
|
|
15
|
+
/**
|
|
16
|
+
* Estimate gas for profiling / TCO comparison.
|
|
17
|
+
* Uses bytecode storage cost only — no activation overhead.
|
|
18
|
+
* This gives an honest apples-to-apples comparison with Solidity.
|
|
19
|
+
*/
|
|
20
|
+
static estimateProfileGas(bytecodeSize: number, language: 'rust' | 'solidity'): number;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=gas-estimator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gas-estimator.d.ts","sourceRoot":"","sources":["../../src/utils/gas-estimator.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,YAAY;IAEvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAI1C;IAIF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAI3C;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAIhC;IAEF;;;OAGG;IACH,MAAM,CAAC,qBAAqB,CAC1B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GAAG,UAAU,EAC7B,gBAAgB,GAAE,MAAU,GAC3B,MAAM;IAST;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CACvB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GAAG,UAAU,GAC5B,MAAM;CAQV"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GasEstimator = void 0;
|
|
4
|
+
class GasEstimator {
|
|
5
|
+
/**
|
|
6
|
+
* Estimate gas for actual deployment (deploy command).
|
|
7
|
+
* Includes full 14M activation cost + 2.5x safety buffer.
|
|
8
|
+
*/
|
|
9
|
+
static estimateDeploymentGas(bytecodeSize, language, safetyMultiplier = 1) {
|
|
10
|
+
const config = language === 'rust' ? this.STYLUS_DEPLOY_CONFIG : this.EVM_CONFIG;
|
|
11
|
+
return Math.ceil(config.baseGas +
|
|
12
|
+
config.activationGas +
|
|
13
|
+
(bytecodeSize * config.perByteGas * safetyMultiplier));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Estimate gas for profiling / TCO comparison.
|
|
17
|
+
* Uses bytecode storage cost only — no activation overhead.
|
|
18
|
+
* This gives an honest apples-to-apples comparison with Solidity.
|
|
19
|
+
*/
|
|
20
|
+
static estimateProfileGas(bytecodeSize, language) {
|
|
21
|
+
const config = language === 'rust' ? this.STYLUS_PROFILE_CONFIG : this.EVM_CONFIG;
|
|
22
|
+
return Math.ceil(config.baseGas +
|
|
23
|
+
config.activationGas +
|
|
24
|
+
(bytecodeSize * config.perByteGas));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.GasEstimator = GasEstimator;
|
|
28
|
+
// Full deployment config — used by `deploy` command (includes 14M activation)
|
|
29
|
+
GasEstimator.STYLUS_DEPLOY_CONFIG = {
|
|
30
|
+
baseGas: 21000,
|
|
31
|
+
activationGas: 14000000,
|
|
32
|
+
perByteGas: 16,
|
|
33
|
+
};
|
|
34
|
+
// Profiling config — bytecode storage cost only, no activation overhead
|
|
35
|
+
// Activation is a one-time fixed cost; TCO comparison uses per-byte storage
|
|
36
|
+
GasEstimator.STYLUS_PROFILE_CONFIG = {
|
|
37
|
+
baseGas: 21000,
|
|
38
|
+
activationGas: 300000,
|
|
39
|
+
perByteGas: 16,
|
|
40
|
+
};
|
|
41
|
+
GasEstimator.EVM_CONFIG = {
|
|
42
|
+
baseGas: 21000,
|
|
43
|
+
activationGas: 32000,
|
|
44
|
+
perByteGas: 200,
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=gas-estimator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gas-estimator.js","sourceRoot":"","sources":["../../src/utils/gas-estimator.ts"],"names":[],"mappings":";;;AAMA,MAAa,YAAY;IAsBvB;;;OAGG;IACH,MAAM,CAAC,qBAAqB,CAC1B,YAAoB,EACpB,QAA6B,EAC7B,mBAA2B,CAAC;QAE5B,MAAM,MAAM,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;QACjF,OAAO,IAAI,CAAC,IAAI,CACd,MAAM,CAAC,OAAO;YACd,MAAM,CAAC,aAAa;YACpB,CAAC,YAAY,GAAG,MAAM,CAAC,UAAU,GAAG,gBAAgB,CAAC,CACtD,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,kBAAkB,CACvB,YAAoB,EACpB,QAA6B;QAE7B,MAAM,MAAM,GAAG,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;QAClF,OAAO,IAAI,CAAC,IAAI,CACd,MAAM,CAAC,OAAO;YACd,MAAM,CAAC,aAAa;YACpB,CAAC,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,CACnC,CAAC;IACJ,CAAC;;AAtDH,oCAuDC;AAtDC,8EAA8E;AACtD,iCAAoB,GAAwB;IAClE,OAAO,EAAE,KAAK;IACd,aAAa,EAAE,QAAQ;IACvB,UAAU,EAAE,EAAE;CACf,CAAC;AAEF,wEAAwE;AACxE,4EAA4E;AACpD,kCAAqB,GAAwB;IACnE,OAAO,EAAE,KAAK;IACd,aAAa,EAAE,MAAM;IACrB,UAAU,EAAE,EAAE;CACf,CAAC;AAEsB,uBAAU,GAAwB;IACxD,OAAO,EAAE,KAAK;IACd,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,GAAG;CAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stylus-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A comprehensive CLI development environment for Arbitrum Stylus smart contracts with automated gas profiling",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"files": [
|
|
45
45
|
"dist/",
|
|
46
46
|
"src/templates/Cargo.lock",
|
|
47
|
+
"src/dashboard/",
|
|
47
48
|
"README.md",
|
|
48
49
|
"LICENSE"
|
|
49
50
|
],
|
|
@@ -56,16 +57,19 @@
|
|
|
56
57
|
"dotenv": "^16.3.1",
|
|
57
58
|
"ethers": "^6.9.0",
|
|
58
59
|
"execa": "^5.1.1",
|
|
60
|
+
"express": "^4.18.2",
|
|
59
61
|
"fast-csv": "^4.3.6",
|
|
60
62
|
"fs-extra": "^11.2.0",
|
|
61
63
|
"handlebars": "^4.7.8",
|
|
62
64
|
"inquirer": "^8.2.6",
|
|
63
65
|
"json2csv": "^6.0.0-alpha.2",
|
|
66
|
+
"open": "^8.4.2",
|
|
64
67
|
"ora": "^5.4.1",
|
|
65
68
|
"solc": "^0.8.33",
|
|
66
69
|
"yaml": "^2.3.4"
|
|
67
70
|
},
|
|
68
71
|
"devDependencies": {
|
|
72
|
+
"@types/express": "^4.17.21",
|
|
69
73
|
"@types/fs-extra": "^11.0.4",
|
|
70
74
|
"@types/inquirer": "^8.2.10",
|
|
71
75
|
"@types/jest": "^29.5.11",
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
async function loadData() {
|
|
2
|
+
try {
|
|
3
|
+
const response = await fetch('/data.json');
|
|
4
|
+
if (!response.ok) {
|
|
5
|
+
throw new Error('Failed to load data');
|
|
6
|
+
}
|
|
7
|
+
return await response.json();
|
|
8
|
+
} catch (error) {
|
|
9
|
+
throw new Error(`Error loading data: ${error.message}`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function calculateStats(data) {
|
|
14
|
+
if (data.length === 0) {
|
|
15
|
+
return {
|
|
16
|
+
totalProfiles: 0,
|
|
17
|
+
avgSavings: 0,
|
|
18
|
+
maxSavings: 0,
|
|
19
|
+
contractsProfiled: 0
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const totalProfiles = data.length;
|
|
24
|
+
const avgSavings = data.reduce((sum, r) => sum + r.tco.tcoPercentage, 0) / totalProfiles;
|
|
25
|
+
const maxSavings = Math.max(...data.map(r => r.tco.tcoPercentage));
|
|
26
|
+
const uniqueContracts = new Set(data.map(r => r.contractName));
|
|
27
|
+
const contractsProfiled = uniqueContracts.size;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
totalProfiles,
|
|
31
|
+
avgSavings: avgSavings.toFixed(2),
|
|
32
|
+
maxSavings: maxSavings.toFixed(2),
|
|
33
|
+
contractsProfiled
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function renderStats(stats) {
|
|
38
|
+
const statsContainer = document.getElementById('stats');
|
|
39
|
+
statsContainer.innerHTML = `
|
|
40
|
+
<div class="stat-card">
|
|
41
|
+
<div class="stat-label">Total Profiles</div>
|
|
42
|
+
<div class="stat-value">${stats.totalProfiles}</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="stat-card">
|
|
45
|
+
<div class="stat-label">Average TCO Savings</div>
|
|
46
|
+
<div class="stat-value ${stats.avgSavings < 0 ? 'negative' : ''}">${stats.avgSavings}%</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="stat-card">
|
|
49
|
+
<div class="stat-label">Maximum Savings</div>
|
|
50
|
+
<div class="stat-value">${stats.maxSavings}%</div>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="stat-card">
|
|
53
|
+
<div class="stat-label">Contracts Profiled</div>
|
|
54
|
+
<div class="stat-value">${stats.contractsProfiled}</div>
|
|
55
|
+
</div>
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function renderCharts(data) {
|
|
60
|
+
if (data.length === 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// TCO Trend Chart
|
|
65
|
+
const tcoCtx = document.getElementById('tcoChart').getContext('2d');
|
|
66
|
+
new Chart(tcoCtx, {
|
|
67
|
+
type: 'line',
|
|
68
|
+
data: {
|
|
69
|
+
labels: data.map(r => new Date(r.timestamp).toLocaleDateString()),
|
|
70
|
+
datasets: [
|
|
71
|
+
{
|
|
72
|
+
label: 'Rust (Stylus) TCO',
|
|
73
|
+
data: data.map(r => r.tco.rustTCO),
|
|
74
|
+
borderColor: 'rgb(139, 92, 246)',
|
|
75
|
+
backgroundColor: 'rgba(139, 92, 246, 0.1)',
|
|
76
|
+
tension: 0.4,
|
|
77
|
+
fill: true
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: 'Solidity TCO',
|
|
81
|
+
data: data.map(r => r.tco.solidityTCO),
|
|
82
|
+
borderColor: 'rgb(239, 68, 68)',
|
|
83
|
+
backgroundColor: 'rgba(239, 68, 68, 0.1)',
|
|
84
|
+
tension: 0.4,
|
|
85
|
+
fill: true
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
options: {
|
|
90
|
+
responsive: true,
|
|
91
|
+
maintainAspectRatio: false,
|
|
92
|
+
plugins: {
|
|
93
|
+
title: {
|
|
94
|
+
display: false
|
|
95
|
+
},
|
|
96
|
+
legend: {
|
|
97
|
+
labels: {
|
|
98
|
+
color: '#e2e8f0'
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
scales: {
|
|
103
|
+
y: {
|
|
104
|
+
beginAtZero: true,
|
|
105
|
+
grid: {
|
|
106
|
+
color: '#334155'
|
|
107
|
+
},
|
|
108
|
+
ticks: {
|
|
109
|
+
color: '#94a3b8'
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
x: {
|
|
113
|
+
grid: {
|
|
114
|
+
color: '#334155'
|
|
115
|
+
},
|
|
116
|
+
ticks: {
|
|
117
|
+
color: '#94a3b8'
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Savings Percentage Chart
|
|
125
|
+
const savingsCtx = document.getElementById('savingsChart').getContext('2d');
|
|
126
|
+
new Chart(savingsCtx, {
|
|
127
|
+
type: 'bar',
|
|
128
|
+
data: {
|
|
129
|
+
labels: data.map((r, i) => `${r.contractName} (${new Date(r.timestamp).toLocaleDateString()})`),
|
|
130
|
+
datasets: [{
|
|
131
|
+
label: 'TCO Savings %',
|
|
132
|
+
data: data.map(r => r.tco.tcoPercentage),
|
|
133
|
+
backgroundColor: data.map(r => r.tco.tcoPercentage >= 0 ? 'rgba(16, 185, 129, 0.8)' : 'rgba(239, 68, 68, 0.8)'),
|
|
134
|
+
borderColor: data.map(r => r.tco.tcoPercentage >= 0 ? 'rgb(16, 185, 129)' : 'rgb(239, 68, 68)'),
|
|
135
|
+
borderWidth: 1
|
|
136
|
+
}]
|
|
137
|
+
},
|
|
138
|
+
options: {
|
|
139
|
+
responsive: true,
|
|
140
|
+
maintainAspectRatio: false,
|
|
141
|
+
plugins: {
|
|
142
|
+
title: {
|
|
143
|
+
display: false
|
|
144
|
+
},
|
|
145
|
+
legend: {
|
|
146
|
+
labels: {
|
|
147
|
+
color: '#e2e8f0'
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
scales: {
|
|
152
|
+
y: {
|
|
153
|
+
beginAtZero: true,
|
|
154
|
+
grid: {
|
|
155
|
+
color: '#334155'
|
|
156
|
+
},
|
|
157
|
+
ticks: {
|
|
158
|
+
color: '#94a3b8',
|
|
159
|
+
callback: function(value) {
|
|
160
|
+
return value + '%';
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
x: {
|
|
165
|
+
grid: {
|
|
166
|
+
color: '#334155'
|
|
167
|
+
},
|
|
168
|
+
ticks: {
|
|
169
|
+
color: '#94a3b8',
|
|
170
|
+
maxRotation: 45,
|
|
171
|
+
minRotation: 45
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Costs Breakdown Chart
|
|
179
|
+
const costsCtx = document.getElementById('costsChart').getContext('2d');
|
|
180
|
+
const latestData = data[data.length - 1];
|
|
181
|
+
|
|
182
|
+
new Chart(costsCtx, {
|
|
183
|
+
type: 'bar',
|
|
184
|
+
data: {
|
|
185
|
+
labels: ['Deployment', 'Execution (100 calls)'],
|
|
186
|
+
datasets: [
|
|
187
|
+
{
|
|
188
|
+
label: 'Rust (Stylus)',
|
|
189
|
+
data: [
|
|
190
|
+
latestData.rustProfile.deploymentGas,
|
|
191
|
+
latestData.tco.rustTCO - latestData.rustProfile.deploymentGas
|
|
192
|
+
],
|
|
193
|
+
backgroundColor: 'rgba(139, 92, 246, 0.8)',
|
|
194
|
+
borderColor: 'rgb(139, 92, 246)',
|
|
195
|
+
borderWidth: 1
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
label: 'Solidity',
|
|
199
|
+
data: [
|
|
200
|
+
latestData.solidityProfile.deploymentGas,
|
|
201
|
+
latestData.tco.solidityTCO - latestData.solidityProfile.deploymentGas
|
|
202
|
+
],
|
|
203
|
+
backgroundColor: 'rgba(239, 68, 68, 0.8)',
|
|
204
|
+
borderColor: 'rgb(239, 68, 68)',
|
|
205
|
+
borderWidth: 1
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
options: {
|
|
210
|
+
responsive: true,
|
|
211
|
+
maintainAspectRatio: false,
|
|
212
|
+
plugins: {
|
|
213
|
+
title: {
|
|
214
|
+
display: false
|
|
215
|
+
},
|
|
216
|
+
legend: {
|
|
217
|
+
labels: {
|
|
218
|
+
color: '#e2e8f0'
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
scales: {
|
|
223
|
+
y: {
|
|
224
|
+
beginAtZero: true,
|
|
225
|
+
grid: {
|
|
226
|
+
color: '#334155'
|
|
227
|
+
},
|
|
228
|
+
ticks: {
|
|
229
|
+
color: '#94a3b8',
|
|
230
|
+
callback: function(value) {
|
|
231
|
+
return value.toLocaleString() + ' gas';
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
x: {
|
|
236
|
+
grid: {
|
|
237
|
+
color: '#334155'
|
|
238
|
+
},
|
|
239
|
+
ticks: {
|
|
240
|
+
color: '#94a3b8'
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function renderDashboard() {
|
|
249
|
+
const loadingEl = document.getElementById('loading');
|
|
250
|
+
const errorEl = document.getElementById('error');
|
|
251
|
+
const dashboardEl = document.getElementById('dashboard');
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const data = await loadData();
|
|
255
|
+
|
|
256
|
+
loadingEl.style.display = 'none';
|
|
257
|
+
|
|
258
|
+
if (data.length === 0) {
|
|
259
|
+
errorEl.style.display = 'block';
|
|
260
|
+
document.getElementById('error-message').textContent = 'No profiling data available yet. Run "stylus-toolkit profile" to generate data.';
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const stats = calculateStats(data);
|
|
265
|
+
renderStats(stats);
|
|
266
|
+
renderCharts(data);
|
|
267
|
+
|
|
268
|
+
dashboardEl.style.display = 'block';
|
|
269
|
+
} catch (error) {
|
|
270
|
+
loadingEl.style.display = 'none';
|
|
271
|
+
errorEl.style.display = 'block';
|
|
272
|
+
document.getElementById('error-message').textContent = error.message;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
renderDashboard();
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Stylus Toolkit - Gas Analytics Dashboard</title>
|
|
7
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
|
8
|
+
<style>
|
|
9
|
+
* {
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
body {
|
|
16
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
17
|
+
background: #0f172a;
|
|
18
|
+
color: #e2e8f0;
|
|
19
|
+
padding: 20px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.container {
|
|
23
|
+
max-width: 1400px;
|
|
24
|
+
margin: 0 auto;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
header {
|
|
28
|
+
margin-bottom: 40px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
h1 {
|
|
32
|
+
font-size: 2.5rem;
|
|
33
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
34
|
+
-webkit-background-clip: text;
|
|
35
|
+
-webkit-text-fill-color: transparent;
|
|
36
|
+
margin-bottom: 10px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.subtitle {
|
|
40
|
+
color: #94a3b8;
|
|
41
|
+
font-size: 1.1rem;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.stats-grid {
|
|
45
|
+
display: grid;
|
|
46
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
47
|
+
gap: 20px;
|
|
48
|
+
margin-bottom: 40px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.stat-card {
|
|
52
|
+
background: #1e293b;
|
|
53
|
+
border-radius: 12px;
|
|
54
|
+
padding: 24px;
|
|
55
|
+
border: 1px solid #334155;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.stat-label {
|
|
59
|
+
color: #94a3b8;
|
|
60
|
+
font-size: 0.875rem;
|
|
61
|
+
margin-bottom: 8px;
|
|
62
|
+
text-transform: uppercase;
|
|
63
|
+
letter-spacing: 0.05em;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.stat-value {
|
|
67
|
+
font-size: 2rem;
|
|
68
|
+
font-weight: 700;
|
|
69
|
+
color: #10b981;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.stat-value.negative {
|
|
73
|
+
color: #ef4444;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.chart-container {
|
|
77
|
+
background: #1e293b;
|
|
78
|
+
border-radius: 12px;
|
|
79
|
+
padding: 30px;
|
|
80
|
+
margin-bottom: 30px;
|
|
81
|
+
border: 1px solid #334155;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.chart-title {
|
|
85
|
+
font-size: 1.5rem;
|
|
86
|
+
margin-bottom: 20px;
|
|
87
|
+
color: #f1f5f9;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
canvas {
|
|
91
|
+
max-height: 400px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.loading {
|
|
95
|
+
text-align: center;
|
|
96
|
+
padding: 60px;
|
|
97
|
+
color: #94a3b8;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.error {
|
|
101
|
+
background: #7f1d1d;
|
|
102
|
+
border: 1px solid #991b1b;
|
|
103
|
+
border-radius: 12px;
|
|
104
|
+
padding: 20px;
|
|
105
|
+
color: #fecaca;
|
|
106
|
+
}
|
|
107
|
+
</style>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<div class="container">
|
|
111
|
+
<header>
|
|
112
|
+
<h1>Stylus Toolkit Analytics</h1>
|
|
113
|
+
<p class="subtitle">Real-time gas profiling insights for your Arbitrum Stylus contracts</p>
|
|
114
|
+
</header>
|
|
115
|
+
|
|
116
|
+
<div id="loading" class="loading">
|
|
117
|
+
<p>Loading analytics data...</p>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div id="error" class="error" style="display: none;">
|
|
121
|
+
<h3>Error Loading Data</h3>
|
|
122
|
+
<p id="error-message"></p>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<div id="dashboard" style="display: none;">
|
|
126
|
+
<div id="stats" class="stats-grid"></div>
|
|
127
|
+
|
|
128
|
+
<div class="chart-container">
|
|
129
|
+
<h2 class="chart-title">Total Cost of Ownership (TCO) Trends</h2>
|
|
130
|
+
<canvas id="tcoChart"></canvas>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div class="chart-container">
|
|
134
|
+
<h2 class="chart-title">Gas Savings by Contract</h2>
|
|
135
|
+
<canvas id="savingsChart"></canvas>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<div class="chart-container">
|
|
139
|
+
<h2 class="chart-title">Deployment vs Execution Costs</h2>
|
|
140
|
+
<canvas id="costsChart"></canvas>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<script src="dashboard.js"></script>
|
|
146
|
+
</body>
|
|
147
|
+
</html>
|