abc-scaffold 1.0.2 → 1.0.4
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 +1 -1
- package/src/scaffold.js +11 -3
- package/templates/contracts/MyContract.sol +6 -0
- package/templates/frontend/src/App.css +12 -48
- package/templates/frontend/src/App.jsx +4 -41
- package/templates/frontend/src/components/Navbar.css +59 -0
- package/templates/frontend/src/components/Navbar.jsx +44 -0
- package/templates/scripts/deploy.js +18 -0
- package/templates/scripts/upgrade.js +20 -0
- package/templates/test/MyContract.test.js +10 -0
package/package.json
CHANGED
package/src/scaffold.js
CHANGED
|
@@ -295,9 +295,17 @@ export async function scaffold(initialName) {
|
|
|
295
295
|
|
|
296
296
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
297
297
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
298
|
+
// Copy starter files — directories are created implicitly by fse.copySync
|
|
299
|
+
const starterFiles = [
|
|
300
|
+
['contracts/MyContract.sol', 'contracts/MyContract.sol'],
|
|
301
|
+
['scripts/deploy.js', 'scripts/deploy.js'],
|
|
302
|
+
['scripts/upgrade.js', 'scripts/upgrade.js'],
|
|
303
|
+
['test/MyContract.test.js', 'test/MyContract.test.js'],
|
|
304
|
+
];
|
|
305
|
+
|
|
306
|
+
for (const [src, dest] of starterFiles) {
|
|
307
|
+
fse.copySync(path.join(TEMPLATES, src), path.join(targetDir, dest));
|
|
308
|
+
logger.success(dest);
|
|
301
309
|
}
|
|
302
310
|
|
|
303
311
|
// ── Copy configuration files ────────────────────────────────────────────────
|
|
@@ -19,7 +19,6 @@ body {
|
|
|
19
19
|
flex-direction: column;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/* ── Centered content ── */
|
|
23
22
|
.main {
|
|
24
23
|
flex: 1;
|
|
25
24
|
display: flex;
|
|
@@ -27,55 +26,20 @@ body {
|
|
|
27
26
|
justify-content: center;
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
background-color: #e94560;
|
|
33
|
-
color: #ffffff;
|
|
34
|
-
border: none;
|
|
35
|
-
border-radius: 10px;
|
|
36
|
-
padding: 1rem 2.5rem;
|
|
37
|
-
font-size: 1.1rem;
|
|
38
|
-
font-weight: 700;
|
|
39
|
-
cursor: pointer;
|
|
40
|
-
transition: background-color 0.18s ease, transform 0.12s ease;
|
|
41
|
-
letter-spacing: 0.3px;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
.connect-btn:hover:not(:disabled) {
|
|
45
|
-
background-color: #c73652;
|
|
46
|
-
transform: translateY(-2px);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.connect-btn:active:not(:disabled) {
|
|
50
|
-
transform: translateY(0);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.connect-btn:disabled {
|
|
54
|
-
background-color: #555566;
|
|
55
|
-
cursor: not-allowed;
|
|
29
|
+
.hero {
|
|
30
|
+
text-align: center;
|
|
56
31
|
}
|
|
57
32
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
border: 1px solid #e94560;
|
|
65
|
-
border-radius: 10px;
|
|
66
|
-
padding: 0.75rem 1.5rem;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.wallet-dot {
|
|
70
|
-
width: 10px;
|
|
71
|
-
height: 10px;
|
|
72
|
-
background-color: #4caf50;
|
|
73
|
-
border-radius: 50%;
|
|
74
|
-
flex-shrink: 0;
|
|
33
|
+
.hero h1 {
|
|
34
|
+
font-size: 3rem;
|
|
35
|
+
font-weight: 800;
|
|
36
|
+
color: #ffffff;
|
|
37
|
+
margin-bottom: 0.75rem;
|
|
38
|
+
letter-spacing: -0.5px;
|
|
75
39
|
}
|
|
76
40
|
|
|
77
|
-
.
|
|
78
|
-
font-
|
|
79
|
-
|
|
80
|
-
|
|
41
|
+
.subtitle {
|
|
42
|
+
font-size: 1.1rem;
|
|
43
|
+
color: #e94560;
|
|
44
|
+
font-weight: 500;
|
|
81
45
|
}
|
|
@@ -1,52 +1,15 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import { BrowserProvider } from 'ethers';
|
|
3
1
|
import Navbar from './components/Navbar.jsx';
|
|
4
2
|
import './App.css';
|
|
5
3
|
|
|
6
4
|
function App() {
|
|
7
|
-
const [account, setAccount] = useState(null);
|
|
8
|
-
const [connecting, setConnecting] = useState(false);
|
|
9
|
-
|
|
10
|
-
async function connectWallet() {
|
|
11
|
-
if (!window.ethereum) {
|
|
12
|
-
alert('MetaMask is not installed. Please install it at https://metamask.io');
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
setConnecting(true);
|
|
17
|
-
try {
|
|
18
|
-
const provider = new BrowserProvider(window.ethereum);
|
|
19
|
-
const accounts = await provider.send('eth_requestAccounts', []);
|
|
20
|
-
setAccount(accounts[0]);
|
|
21
|
-
} catch (err) {
|
|
22
|
-
console.error('Wallet connection rejected:', err);
|
|
23
|
-
} finally {
|
|
24
|
-
setConnecting(false);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function truncate(addr) {
|
|
29
|
-
return `${addr.slice(0, 6)}…${addr.slice(-4)}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
5
|
return (
|
|
33
6
|
<div className="app">
|
|
34
7
|
<Navbar />
|
|
35
8
|
<main className="main">
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
</div>
|
|
41
|
-
) : (
|
|
42
|
-
<button
|
|
43
|
-
className="connect-btn"
|
|
44
|
-
onClick={connectWallet}
|
|
45
|
-
disabled={connecting}
|
|
46
|
-
>
|
|
47
|
-
{connecting ? 'Connecting…' : 'Connect Wallet'}
|
|
48
|
-
</button>
|
|
49
|
-
)}
|
|
9
|
+
<div className="hero">
|
|
10
|
+
<h1>Your Blockchain Project</h1>
|
|
11
|
+
<p className="subtitle">Scaffolded by Africa's Blockchain Club</p>
|
|
12
|
+
</div>
|
|
50
13
|
</main>
|
|
51
14
|
</div>
|
|
52
15
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
.navbar {
|
|
2
2
|
display: flex;
|
|
3
3
|
align-items: center;
|
|
4
|
+
justify-content: space-between;
|
|
4
5
|
padding: 1rem 2rem;
|
|
5
6
|
background-color: #1a1a2e;
|
|
6
7
|
border-bottom: 1px solid #2a2a4a;
|
|
@@ -26,3 +27,61 @@
|
|
|
26
27
|
color: #e94560;
|
|
27
28
|
letter-spacing: 0.3px;
|
|
28
29
|
}
|
|
30
|
+
|
|
31
|
+
.navbar-actions {
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Connect button */
|
|
37
|
+
.connect-btn {
|
|
38
|
+
background-color: #e94560;
|
|
39
|
+
color: #ffffff;
|
|
40
|
+
border: none;
|
|
41
|
+
border-radius: 8px;
|
|
42
|
+
padding: 0.55rem 1.3rem;
|
|
43
|
+
font-size: 0.9rem;
|
|
44
|
+
font-weight: 600;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
transition: background-color 0.18s ease, transform 0.12s ease;
|
|
47
|
+
white-space: nowrap;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.connect-btn:hover:not(:disabled) {
|
|
51
|
+
background-color: #c73652;
|
|
52
|
+
transform: translateY(-1px);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.connect-btn:active:not(:disabled) {
|
|
56
|
+
transform: translateY(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.connect-btn:disabled {
|
|
60
|
+
background-color: #555566;
|
|
61
|
+
cursor: not-allowed;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Connected badge */
|
|
65
|
+
.wallet-badge {
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
gap: 0.5rem;
|
|
69
|
+
background-color: #0f3460;
|
|
70
|
+
border: 1px solid #e94560;
|
|
71
|
+
border-radius: 8px;
|
|
72
|
+
padding: 0.45rem 1rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.wallet-dot {
|
|
76
|
+
width: 8px;
|
|
77
|
+
height: 8px;
|
|
78
|
+
background-color: #4caf50;
|
|
79
|
+
border-radius: 50%;
|
|
80
|
+
flex-shrink: 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.wallet-address {
|
|
84
|
+
color: #e2e2e2;
|
|
85
|
+
font-family: 'Fira Code', 'Cascadia Code', monospace;
|
|
86
|
+
font-size: 0.875rem;
|
|
87
|
+
}
|
|
@@ -1,12 +1,56 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { BrowserProvider } from 'ethers';
|
|
1
3
|
import './Navbar.css';
|
|
2
4
|
|
|
3
5
|
export default function Navbar() {
|
|
6
|
+
const [account, setAccount] = useState(null);
|
|
7
|
+
const [connecting, setConnecting] = useState(false);
|
|
8
|
+
|
|
9
|
+
async function connectWallet() {
|
|
10
|
+
if (!window.ethereum) {
|
|
11
|
+
alert('MetaMask is not installed. Please install it at https://metamask.io');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
setConnecting(true);
|
|
16
|
+
try {
|
|
17
|
+
const provider = new BrowserProvider(window.ethereum);
|
|
18
|
+
const accounts = await provider.send('eth_requestAccounts', []);
|
|
19
|
+
setAccount(accounts[0]);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error('Wallet connection rejected:', err);
|
|
22
|
+
} finally {
|
|
23
|
+
setConnecting(false);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function truncate(addr) {
|
|
28
|
+
return `${addr.slice(0, 6)}…${addr.slice(-4)}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
4
31
|
return (
|
|
5
32
|
<nav className="navbar">
|
|
6
33
|
<div className="navbar-brand">
|
|
7
34
|
<span className="navbar-logo">🔗</span>
|
|
8
35
|
<span className="navbar-title">Africa's Blockchain Club</span>
|
|
9
36
|
</div>
|
|
37
|
+
|
|
38
|
+
<div className="navbar-actions">
|
|
39
|
+
{account ? (
|
|
40
|
+
<div className="wallet-badge">
|
|
41
|
+
<span className="wallet-dot" />
|
|
42
|
+
<span className="wallet-address">{truncate(account)}</span>
|
|
43
|
+
</div>
|
|
44
|
+
) : (
|
|
45
|
+
<button
|
|
46
|
+
className="connect-btn"
|
|
47
|
+
onClick={connectWallet}
|
|
48
|
+
disabled={connecting}
|
|
49
|
+
>
|
|
50
|
+
{connecting ? 'Connecting…' : 'Connect Wallet'}
|
|
51
|
+
</button>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
10
54
|
</nav>
|
|
11
55
|
);
|
|
12
56
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const { ethers } = require('hardhat');
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
|
|
5
|
+
const [deployer] = await ethers.getSigners();
|
|
6
|
+
console.log('Deploying from:', deployer.address);
|
|
7
|
+
|
|
8
|
+
const MyContract = await ethers.getContractFactory('MyContract');
|
|
9
|
+
const contract = await MyContract.deploy();
|
|
10
|
+
await contract.waitForDeployment();
|
|
11
|
+
|
|
12
|
+
console.log('MyContract deployed to:', await contract.getAddress());
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
main().catch((err) => {
|
|
16
|
+
console.error(err);
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { ethers, upgrades } = require('hardhat');
|
|
2
|
+
|
|
3
|
+
// Address of the proxy contract from your initial deployment
|
|
4
|
+
const PROXY_ADDRESS = '0xYOUR_PROXY_ADDRESS_HERE';
|
|
5
|
+
|
|
6
|
+
async function main() {
|
|
7
|
+
const [deployer] = await ethers.getSigners();
|
|
8
|
+
console.log('Upgrading from:', deployer.address);
|
|
9
|
+
|
|
10
|
+
const MyContractV2 = await ethers.getContractFactory('MyContractV2');
|
|
11
|
+
const upgraded = await upgrades.upgradeProxy(PROXY_ADDRESS, MyContractV2);
|
|
12
|
+
await upgraded.waitForDeployment();
|
|
13
|
+
|
|
14
|
+
console.log('Proxy upgraded at:', await upgraded.getAddress());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
main().catch((err) => {
|
|
18
|
+
console.error(err);
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { expect } = require('chai');
|
|
2
|
+
const { ethers } = require('hardhat');
|
|
3
|
+
|
|
4
|
+
describe('MyContract', function () {
|
|
5
|
+
it('should deploy successfully', async function () {
|
|
6
|
+
const MyContract = await ethers.getContractFactory('MyContract');
|
|
7
|
+
const contract = await MyContract.deploy();
|
|
8
|
+
expect(await contract.getAddress()).to.not.equal(ethers.ZeroAddress);
|
|
9
|
+
});
|
|
10
|
+
});
|