@0xflydev/labz 1.0.21 → 1.0.23
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/index.js +72 -0
- package/package.json +1 -1
- package/templates/buildable/projects/counter/test/Counter.test.ts.tmpl +47 -53
- package/templates/buildable/projects/prediction-market/test/PredictionMarket.test.ts.tmpl +10 -6
- package/templates/buildable/projects/voting/contracts/Voting.sol.tmpl +5 -5
- package/templates/buildable/projects/auction/deploy/deploy.ts.tmpl +0 -38
- package/templates/buildable/projects/token/deploy/deploy.ts.tmpl +0 -32
- package/templates/buildable/projects/voting/deploy/deploy.ts.tmpl +0 -28
package/dist/index.js
CHANGED
|
@@ -1616,8 +1616,11 @@ async function writeProject(outputDir, result, base, templatesDir) {
|
|
|
1616
1616
|
if (fs4.existsSync(pkgPath)) {
|
|
1617
1617
|
const pkg = JSON.parse(fs4.readFileSync(pkgPath, "utf-8"));
|
|
1618
1618
|
pkg.name = path4.basename(outputDir);
|
|
1619
|
+
pkg.description = base.description || "FHEVM Smart Contract";
|
|
1619
1620
|
fs4.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2), "utf-8");
|
|
1620
1621
|
}
|
|
1622
|
+
const readmeContent = generateBuildReadme(path4.basename(outputDir), base, result);
|
|
1623
|
+
fs4.writeFileSync(path4.join(outputDir, "README.md"), readmeContent, "utf-8");
|
|
1621
1624
|
cleanupGitkeep(outputDir);
|
|
1622
1625
|
}
|
|
1623
1626
|
function cleanupGitkeep(dir) {
|
|
@@ -1648,6 +1651,75 @@ function copyDirSync(src, dest) {
|
|
|
1648
1651
|
}
|
|
1649
1652
|
}
|
|
1650
1653
|
}
|
|
1654
|
+
function generateBuildReadme(projectName, base, result) {
|
|
1655
|
+
const contractName = result.stats.baseTemplate.charAt(0).toUpperCase() + result.stats.baseTemplate.slice(1);
|
|
1656
|
+
const modules = result.stats.modulesApplied || [];
|
|
1657
|
+
const lines = [];
|
|
1658
|
+
lines.push(`# ${projectName}`);
|
|
1659
|
+
lines.push("");
|
|
1660
|
+
lines.push(`${base.description}`);
|
|
1661
|
+
lines.push("");
|
|
1662
|
+
lines.push("## Overview");
|
|
1663
|
+
lines.push("");
|
|
1664
|
+
lines.push(`Base template: **${base.name}**`);
|
|
1665
|
+
if (modules.length > 0) {
|
|
1666
|
+
lines.push("");
|
|
1667
|
+
lines.push("### Modules Applied");
|
|
1668
|
+
lines.push("");
|
|
1669
|
+
for (const mod of modules) {
|
|
1670
|
+
lines.push(`- ${mod}`);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
lines.push("");
|
|
1674
|
+
lines.push("## Quick Start");
|
|
1675
|
+
lines.push("");
|
|
1676
|
+
lines.push("```bash");
|
|
1677
|
+
lines.push("# Install dependencies");
|
|
1678
|
+
lines.push("npm install");
|
|
1679
|
+
lines.push("");
|
|
1680
|
+
lines.push("# Compile contracts");
|
|
1681
|
+
lines.push("npx hardhat compile");
|
|
1682
|
+
lines.push("");
|
|
1683
|
+
lines.push("# Run tests");
|
|
1684
|
+
lines.push("npx hardhat test");
|
|
1685
|
+
lines.push("");
|
|
1686
|
+
lines.push("# Deploy (local)");
|
|
1687
|
+
lines.push("npx hardhat run deploy/deploy.ts");
|
|
1688
|
+
lines.push("```");
|
|
1689
|
+
lines.push("");
|
|
1690
|
+
lines.push("## Project Structure");
|
|
1691
|
+
lines.push("");
|
|
1692
|
+
lines.push("```");
|
|
1693
|
+
lines.push(`${projectName}/`);
|
|
1694
|
+
lines.push(" contracts/");
|
|
1695
|
+
lines.push(` ${contractName}.sol`);
|
|
1696
|
+
lines.push(" test/");
|
|
1697
|
+
lines.push(` ${contractName}.test.ts`);
|
|
1698
|
+
lines.push(" deploy/");
|
|
1699
|
+
lines.push(" deploy.ts");
|
|
1700
|
+
lines.push(" hardhat.config.ts");
|
|
1701
|
+
lines.push(" package.json");
|
|
1702
|
+
lines.push("```");
|
|
1703
|
+
lines.push("");
|
|
1704
|
+
lines.push("## FHE Operations");
|
|
1705
|
+
lines.push("");
|
|
1706
|
+
lines.push("This contract uses encrypted data types from FHEVM:");
|
|
1707
|
+
lines.push("- `euint64`, `euint32`, `ebool` - Encrypted integers and booleans");
|
|
1708
|
+
lines.push("- `FHE.add`, `FHE.sub`, `FHE.mul` - Encrypted arithmetic");
|
|
1709
|
+
lines.push("- `FHE.lt`, `FHE.gt`, `FHE.eq` - Encrypted comparisons");
|
|
1710
|
+
lines.push("- `FHE.select` - Encrypted conditional selection");
|
|
1711
|
+
lines.push("");
|
|
1712
|
+
lines.push("## Resources");
|
|
1713
|
+
lines.push("");
|
|
1714
|
+
lines.push("- [FHEVM Documentation](https://docs.zama.ai/fhevm)");
|
|
1715
|
+
lines.push("- [Lab-Z CLI](https://github.com/Farukest/Lab-Z)");
|
|
1716
|
+
lines.push("");
|
|
1717
|
+
lines.push("---");
|
|
1718
|
+
lines.push("");
|
|
1719
|
+
lines.push("Generated with [Lab-Z](https://github.com/Farukest/Lab-Z)");
|
|
1720
|
+
lines.push("");
|
|
1721
|
+
return lines.join("\n");
|
|
1722
|
+
}
|
|
1651
1723
|
|
|
1652
1724
|
// src/commands/doctor.ts
|
|
1653
1725
|
var import_commander7 = require("commander");
|
package/package.json
CHANGED
|
@@ -1,71 +1,65 @@
|
|
|
1
1
|
import { expect } from "chai";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { ethers, fhevm } from "hardhat";
|
|
3
|
+
import { FhevmType } from "@fhevm/hardhat-plugin";
|
|
4
|
+
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
|
4
5
|
|
|
5
6
|
describe("{{CONTRACT_NAME}}", function () {
|
|
6
7
|
let contract: any;
|
|
7
8
|
let contractAddress: string;
|
|
8
|
-
let
|
|
9
|
-
let signers: any[];
|
|
9
|
+
let signers: HardhatEthersSigner[];
|
|
10
10
|
|
|
11
11
|
before(async function () {
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
signers = await ethers.getSigners();
|
|
13
|
+
});
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
const Factory = await
|
|
15
|
+
beforeEach(async function () {
|
|
16
|
+
const Factory = await ethers.getContractFactory("{{CONTRACT_NAME}}");
|
|
17
17
|
contract = await Factory.deploy();
|
|
18
18
|
await contract.waitForDeployment();
|
|
19
19
|
contractAddress = await contract.getAddress();
|
|
20
|
-
|
|
21
|
-
// Create FHEVM instance
|
|
22
|
-
fhevm = await createInstance({
|
|
23
|
-
networkUrl: hre.network.config.url || "http://localhost:8545",
|
|
24
|
-
gatewayUrl: "http://localhost:7077",
|
|
25
|
-
});
|
|
26
20
|
});
|
|
27
21
|
|
|
28
22
|
describe("Increment", function () {
|
|
29
23
|
it("should increment the counter with encrypted value", async function () {
|
|
30
24
|
const [signer] = signers;
|
|
31
|
-
|
|
32
|
-
// Encrypt the value to add
|
|
33
25
|
const valueToAdd = 5;
|
|
34
|
-
const encrypted = await fhevm.encrypt32(valueToAdd);
|
|
35
26
|
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
27
|
+
// Create encrypted input using hardhat plugin
|
|
28
|
+
const encryptedInput = await fhevm
|
|
29
|
+
.createEncryptedInput(contractAddress, signer.address)
|
|
30
|
+
.add32(valueToAdd)
|
|
31
|
+
.encrypt();
|
|
32
|
+
|
|
33
|
+
// Call increment with encrypted value and proof
|
|
34
|
+
const tx = await contract
|
|
35
|
+
.connect(signer)
|
|
36
|
+
.increment(encryptedInput.handles[0], encryptedInput.inputProof);
|
|
41
37
|
await tx.wait();
|
|
42
38
|
|
|
43
39
|
// Get the encrypted count
|
|
44
40
|
const encryptedCount = await contract.getCount();
|
|
45
|
-
|
|
46
|
-
// Request decryption (in real scenario, would use gateway)
|
|
47
|
-
expect(encryptedCount).to.not.equal(0n);
|
|
41
|
+
expect(encryptedCount).to.not.equal(ethers.ZeroHash);
|
|
48
42
|
});
|
|
49
43
|
|
|
50
44
|
it("should allow multiple increments", async function () {
|
|
51
45
|
const [signer] = signers;
|
|
52
46
|
|
|
53
47
|
// First increment
|
|
54
|
-
const encrypted1 = await fhevm
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
48
|
+
const encrypted1 = await fhevm
|
|
49
|
+
.createEncryptedInput(contractAddress, signer.address)
|
|
50
|
+
.add32(10)
|
|
51
|
+
.encrypt();
|
|
52
|
+
await contract.connect(signer).increment(encrypted1.handles[0], encrypted1.inputProof);
|
|
59
53
|
|
|
60
54
|
// Second increment
|
|
61
|
-
const encrypted2 = await fhevm
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
);
|
|
55
|
+
const encrypted2 = await fhevm
|
|
56
|
+
.createEncryptedInput(contractAddress, signer.address)
|
|
57
|
+
.add32(20)
|
|
58
|
+
.encrypt();
|
|
59
|
+
await contract.connect(signer).increment(encrypted2.handles[0], encrypted2.inputProof);
|
|
66
60
|
|
|
67
61
|
const encryptedCount = await contract.getCount();
|
|
68
|
-
expect(encryptedCount).to.not.equal(
|
|
62
|
+
expect(encryptedCount).to.not.equal(ethers.ZeroHash);
|
|
69
63
|
});
|
|
70
64
|
});
|
|
71
65
|
|
|
@@ -74,21 +68,21 @@ describe("{{CONTRACT_NAME}}", function () {
|
|
|
74
68
|
const [signer] = signers;
|
|
75
69
|
|
|
76
70
|
// First add some value
|
|
77
|
-
const addValue = await fhevm
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
);
|
|
71
|
+
const addValue = await fhevm
|
|
72
|
+
.createEncryptedInput(contractAddress, signer.address)
|
|
73
|
+
.add32(100)
|
|
74
|
+
.encrypt();
|
|
75
|
+
await contract.connect(signer).increment(addValue.handles[0], addValue.inputProof);
|
|
82
76
|
|
|
83
77
|
// Then decrement
|
|
84
|
-
const subValue = await fhevm
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
);
|
|
78
|
+
const subValue = await fhevm
|
|
79
|
+
.createEncryptedInput(contractAddress, signer.address)
|
|
80
|
+
.add32(30)
|
|
81
|
+
.encrypt();
|
|
82
|
+
await contract.connect(signer).decrement(subValue.handles[0], subValue.inputProof);
|
|
89
83
|
|
|
90
84
|
const encryptedCount = await contract.getCount();
|
|
91
|
-
expect(encryptedCount).to.not.equal(
|
|
85
|
+
expect(encryptedCount).to.not.equal(ethers.ZeroHash);
|
|
92
86
|
});
|
|
93
87
|
});
|
|
94
88
|
|
|
@@ -96,15 +90,15 @@ describe("{{CONTRACT_NAME}}", function () {
|
|
|
96
90
|
it("should grant access to caller after increment", async function () {
|
|
97
91
|
const [signer] = signers;
|
|
98
92
|
|
|
99
|
-
const encrypted = await fhevm
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
);
|
|
93
|
+
const encrypted = await fhevm
|
|
94
|
+
.createEncryptedInput(contractAddress, signer.address)
|
|
95
|
+
.add32(1)
|
|
96
|
+
.encrypt();
|
|
97
|
+
await contract.connect(signer).increment(encrypted.handles[0], encrypted.inputProof);
|
|
104
98
|
|
|
105
99
|
// Caller should be able to get the count
|
|
106
100
|
const count = await contract.connect(signer).getCount();
|
|
107
|
-
expect(count).to.not.equal(
|
|
101
|
+
expect(count).to.not.equal(ethers.ZeroHash);
|
|
108
102
|
});
|
|
109
103
|
});
|
|
110
104
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { expect } from "chai";
|
|
2
2
|
import { ethers } from "hardhat";
|
|
3
|
+
import { time } from "@nomicfoundation/hardhat-network-helpers";
|
|
3
4
|
import { {{CONTRACT_NAME}} } from "../typechain-types";
|
|
4
5
|
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
|
|
5
6
|
|
|
@@ -72,13 +73,15 @@ describe("{{CONTRACT_NAME}}", function () {
|
|
|
72
73
|
let deadline: number;
|
|
73
74
|
|
|
74
75
|
beforeEach(async function () {
|
|
75
|
-
|
|
76
|
+
// Get current block timestamp and add 60 seconds
|
|
77
|
+
const block = await ethers.provider.getBlock("latest");
|
|
78
|
+
deadline = block!.timestamp + 60;
|
|
76
79
|
const tx = await market.createMarket("Test question?", deadline);
|
|
77
80
|
await tx.wait();
|
|
78
81
|
marketId = 0;
|
|
79
82
|
|
|
80
|
-
//
|
|
81
|
-
await
|
|
83
|
+
// Advance blockchain time past deadline
|
|
84
|
+
await time.increaseTo(deadline + 1);
|
|
82
85
|
});
|
|
83
86
|
|
|
84
87
|
it("Should allow oracle to resolve market", async function () {
|
|
@@ -140,11 +143,12 @@ describe("{{CONTRACT_NAME}}", function () {
|
|
|
140
143
|
it("Should handle complete market lifecycle", async function () {
|
|
141
144
|
// 1. Create market
|
|
142
145
|
const question = "Will BTC hit $100k?";
|
|
143
|
-
const
|
|
146
|
+
const block = await ethers.provider.getBlock("latest");
|
|
147
|
+
const deadline = block!.timestamp + 60;
|
|
144
148
|
await market.createMarket(question, deadline);
|
|
145
149
|
|
|
146
|
-
// 2.
|
|
147
|
-
await
|
|
150
|
+
// 2. Advance time past deadline
|
|
151
|
+
await time.increaseTo(deadline + 1);
|
|
148
152
|
|
|
149
153
|
// 3. Resolve market
|
|
150
154
|
await market.resolveMarket(0, true);
|
|
@@ -80,8 +80,8 @@ contract {{CONTRACT_NAME}} is {{INHERITS}} {
|
|
|
80
80
|
Proposal storage proposal = _proposals[proposalId];
|
|
81
81
|
proposal.description = description;
|
|
82
82
|
proposal.endTime = block.timestamp + durationSeconds;
|
|
83
|
-
proposal.yesVotes = FHE.
|
|
84
|
-
proposal.noVotes = FHE.
|
|
83
|
+
proposal.yesVotes = FHE.asEuint32(0);
|
|
84
|
+
proposal.noVotes = FHE.asEuint32(0);
|
|
85
85
|
proposal.exists = true;
|
|
86
86
|
|
|
87
87
|
// Set ACL for vote counts
|
|
@@ -118,13 +118,13 @@ contract {{CONTRACT_NAME}} is {{INHERITS}} {
|
|
|
118
118
|
[[VOTE_TYPE]] eVote = FHE.fromExternal(encryptedVote, inputProof);
|
|
119
119
|
|
|
120
120
|
// Encrypted vote: if vote > 0, it's a yes vote
|
|
121
|
-
ebool isYes = FHE.gt(eVote, FHE.
|
|
121
|
+
ebool isYes = FHE.gt(eVote, FHE.asEuint32(0));
|
|
122
122
|
|
|
123
123
|
// Homomorphic conditional addition
|
|
124
124
|
// yesVotes += isYes ? 1 : 0
|
|
125
125
|
// noVotes += isYes ? 0 : 1
|
|
126
|
-
[[VOTE_TYPE]] one = FHE.
|
|
127
|
-
[[VOTE_TYPE]] zero = FHE.
|
|
126
|
+
[[VOTE_TYPE]] one = FHE.asEuint32(1);
|
|
127
|
+
[[VOTE_TYPE]] zero = FHE.asEuint32(0);
|
|
128
128
|
|
|
129
129
|
proposal.yesVotes = FHE.add(proposal.yesVotes, FHE.select(isYes, one, zero));
|
|
130
130
|
proposal.noVotes = FHE.add(proposal.noVotes, FHE.select(isYes, zero, one));
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { ethers } from "hardhat";
|
|
2
|
-
|
|
3
|
-
async function main() {
|
|
4
|
-
const itemDescription = "Rare Digital Collectible";
|
|
5
|
-
const durationSeconds = 86400; // 1 day
|
|
6
|
-
|
|
7
|
-
console.log("Deploying {{CONTRACT_NAME}}...");
|
|
8
|
-
console.log(" Item:", itemDescription);
|
|
9
|
-
console.log(" Duration:", durationSeconds / 3600, "hours");
|
|
10
|
-
|
|
11
|
-
const AuctionFactory = await ethers.getContractFactory("{{CONTRACT_NAME}}");
|
|
12
|
-
const auction = await AuctionFactory.deploy(itemDescription, durationSeconds);
|
|
13
|
-
|
|
14
|
-
await auction.waitForDeployment();
|
|
15
|
-
|
|
16
|
-
const address = await auction.getAddress();
|
|
17
|
-
console.log("\n{{CONTRACT_NAME}} deployed to:", address);
|
|
18
|
-
|
|
19
|
-
console.log("\nAuction Lifecycle:");
|
|
20
|
-
console.log(" 1. Bid: bid(encryptedAmount, inputProof)");
|
|
21
|
-
console.log(" - Bids are encrypted and sealed");
|
|
22
|
-
console.log(" - No one can see competitors' bids");
|
|
23
|
-
console.log(" 2. Wait: Auction runs until endTime");
|
|
24
|
-
console.log(" 3. Request Reveal: requestWinnerReveal()");
|
|
25
|
-
console.log(" - Marks winner for decryption");
|
|
26
|
-
console.log(" 4. Finalize: finalizeWinner(winnerAddress, winningBid, proof)");
|
|
27
|
-
console.log(" - Verifies decryption proof");
|
|
28
|
-
console.log(" - Announces winner");
|
|
29
|
-
console.log("\nPrivacy Guarantees:");
|
|
30
|
-
console.log(" - Bids encrypted until reveal");
|
|
31
|
-
console.log(" - Losing bids never disclosed");
|
|
32
|
-
console.log(" - Fair competition guaranteed");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
main().catch((error) => {
|
|
36
|
-
console.error(error);
|
|
37
|
-
process.exitCode = 1;
|
|
38
|
-
});
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { ethers } from "hardhat";
|
|
2
|
-
|
|
3
|
-
async function main() {
|
|
4
|
-
const tokenName = "Confidential Token";
|
|
5
|
-
const tokenSymbol = "CFHE";
|
|
6
|
-
|
|
7
|
-
console.log("Deploying {{CONTRACT_NAME}}...");
|
|
8
|
-
console.log(" Name:", tokenName);
|
|
9
|
-
console.log(" Symbol:", tokenSymbol);
|
|
10
|
-
|
|
11
|
-
const TokenFactory = await ethers.getContractFactory("{{CONTRACT_NAME}}");
|
|
12
|
-
const token = await TokenFactory.deploy(tokenName, tokenSymbol);
|
|
13
|
-
|
|
14
|
-
await token.waitForDeployment();
|
|
15
|
-
|
|
16
|
-
const address = await token.getAddress();
|
|
17
|
-
console.log("\n{{CONTRACT_NAME}} deployed to:", address);
|
|
18
|
-
|
|
19
|
-
console.log("\nToken Operations:");
|
|
20
|
-
console.log(" - mint(to, encryptedAmount): Mint tokens (owner only)");
|
|
21
|
-
console.log(" - transfer(to, encryptedAmount): Transfer tokens");
|
|
22
|
-
console.log(" - balanceOf(account): Get encrypted balance handle");
|
|
23
|
-
console.log("\nPrivacy Guarantees:");
|
|
24
|
-
console.log(" - Balances are encrypted");
|
|
25
|
-
console.log(" - Transfer amounts are private");
|
|
26
|
-
console.log(" - Only balance owner can decrypt");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
main().catch((error) => {
|
|
30
|
-
console.error(error);
|
|
31
|
-
process.exitCode = 1;
|
|
32
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { ethers } from "hardhat";
|
|
2
|
-
|
|
3
|
-
async function main() {
|
|
4
|
-
console.log("Deploying {{CONTRACT_NAME}}...");
|
|
5
|
-
|
|
6
|
-
const VotingFactory = await ethers.getContractFactory("{{CONTRACT_NAME}}");
|
|
7
|
-
const voting = await VotingFactory.deploy();
|
|
8
|
-
|
|
9
|
-
await voting.waitForDeployment();
|
|
10
|
-
|
|
11
|
-
const address = await voting.getAddress();
|
|
12
|
-
console.log("\n{{CONTRACT_NAME}} deployed to:", address);
|
|
13
|
-
|
|
14
|
-
console.log("\nVoting Operations:");
|
|
15
|
-
console.log(" - createProposal(title, description, duration): Create proposal");
|
|
16
|
-
console.log(" - vote(proposalId, encryptedVote): Cast encrypted vote");
|
|
17
|
-
console.log(" - requestTally(proposalId): Request vote count reveal");
|
|
18
|
-
console.log(" - finalizeTally(proposalId, yesVotes, noVotes, proof): Finalize");
|
|
19
|
-
console.log("\nPrivacy Guarantees:");
|
|
20
|
-
console.log(" - Individual votes are encrypted");
|
|
21
|
-
console.log(" - Only final tally is revealed");
|
|
22
|
-
console.log(" - No one knows how you voted");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
main().catch((error) => {
|
|
26
|
-
console.error(error);
|
|
27
|
-
process.exitCode = 1;
|
|
28
|
-
});
|