Skip to content

Commit 7ef045f

Browse files
authored
docs(common): regroup files (#353)
1 parent cbb4225 commit 7ef045f

19 files changed

Lines changed: 283 additions & 253 deletions

docs/examples/SUMMARY.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
- [Overview](example-overview.md)
22

3-
## Dapps Examples
3+
## Smart contract examples
4+
- Function examples
5+
- [FHEAdd](fheadd.md)
6+
- [FHEIfThenElse](fheifthenelse.md)
7+
- [FHEEncryptSingleValue](fhe-encrypt-single-value.md)
8+
- [FHEEncryptMultipleValue](fhe-encrypt-multiple-value.md)
9+
- [FHEDecryptSingleValue](fhe-decrypt-single-value.md)
410

5-
- Deberry
6-
- Confidential Token Portfolio
11+
- Use case examples
12+
- [FHE Counter](fhe-counter.md)
13+
- [Confidential ERC20 Wrapper](erc20-wrapper.md)
714

8-
## Smart Contract Templates
9-
10-
- Finance
11-
- Governance
12-
- ERC20
13-
- Utilities
14-
- [See all tutorials](see-all-tutorials.md)
15+
## dApp examples
16+
- Coming Soon

docs/examples/erc20-wrapper.md

Whitespace-only changes.

docs/examples/fhe-counter.md

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
This example demonstrate how to build an confidential counter using FHEVM, in comparison to a simple counter.
2+
3+
{% hint style="info" %}
4+
To run this example correctly, make sure the files are placed in the following directories:
5+
- `.sol` file → `<your-project-root-dir>/contracts/`
6+
- `.ts` file → `<your-project-root-dir>/test/`
7+
8+
This ensures Hardhat can compile and test your contracts as expected.
9+
{% endhint %}
10+
11+
## A simple counter
12+
{% tabs %}
13+
14+
{% tab title="counter.sol" %}
15+
```solidity
16+
// SPDX-License-Identifier: MIT
17+
pragma solidity ^0.8.24;
18+
19+
/// @title A simple counter contract
20+
contract Counter {
21+
uint32 private _count;
22+
23+
/// @notice Returns the current count
24+
function getCount() external view returns (uint32) {
25+
return _count;
26+
}
27+
28+
/// @notice Increments the counter by 1
29+
function increment(uint32 value) external {
30+
_count += value;
31+
}
32+
33+
/// @notice Decrements the counter by 1
34+
function decrement(uint32 value) external {
35+
require(_count > value, "Counter: cannot decrement below zero");
36+
_count -= value;
37+
}
38+
}
39+
```
40+
{% endtab %}
41+
42+
{% tab title="counter.ts" %}
43+
```ts
44+
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
45+
import { ethers } from "hardhat";
46+
import { Counter, Counter__factory } from "../types";
47+
import { expect } from "chai";
48+
49+
type Signers = {
50+
deployer: HardhatEthersSigner;
51+
alice: HardhatEthersSigner;
52+
bob: HardhatEthersSigner;
53+
};
54+
55+
async function deployFixture() {
56+
const factory = (await ethers.getContractFactory("Counter")) as Counter__factory;
57+
const counterContract = (await factory.deploy()) as Counter;
58+
const counterContractAddress = await counterContract.getAddress();
59+
60+
return { counterContract, counterContractAddress };
61+
}
62+
63+
describe("Counter", function () {
64+
let signers: Signers;
65+
let counterContract: Counter;
66+
67+
before(async function () {
68+
const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
69+
signers = { deployer: ethSigners[0], alice: ethSigners[1], bob: ethSigners[2] };
70+
});
71+
72+
beforeEach(async () => {
73+
({ counterContract } = await deployFixture());
74+
});
75+
76+
it("count should be zero after deployment", async function () {
77+
const count = await counterContract.getCount();
78+
console.log(`Counter.getCount() === ${count}`);
79+
// Expect initial count to be 0 after deployment
80+
expect(count).to.eq(0);
81+
});
82+
83+
it("increment the counter by 1", async function () {
84+
const countBeforeInc = await counterContract.getCount();
85+
const tx = await counterContract.connect(signers.alice).increment(1);
86+
await tx.wait();
87+
const countAfterInc = await counterContract.getCount();
88+
expect(countAfterInc).to.eq(countBeforeInc + 1n);
89+
});
90+
91+
it("decrement the counter by 1", async function () {
92+
// First increment, count becomes 1
93+
let tx = await counterContract.connect(signers.alice).increment();
94+
await tx.wait();
95+
// Then decrement, count goes back to 0
96+
tx = await counterContract.connect(signers.alice).decrement(1);
97+
await tx.wait();
98+
const count = await counterContract.getCount();
99+
expect(count).to.eq(0);
100+
});
101+
});
102+
```
103+
{% endtab %}
104+
105+
{% endtabs %}
106+
107+
## An FHE counter
108+
109+
{% tabs %}
110+
111+
{% tab title="FHECounter.sol" %}
112+
```solidity
113+
// SPDX-License-Identifier: MIT
114+
pragma solidity ^0.8.24;
115+
116+
import {FHE, euint32, externalEuint32} from "@fhevm/solidity/lib/FHE.sol";
117+
import {SepoliaConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
118+
119+
/// @title A simple FHE counter contract
120+
contract FHECounter is SepoliaConfig {
121+
euint32 private _count;
122+
123+
/// @notice Returns the current count
124+
function getCount() external view returns (euint32) {
125+
return _count;
126+
}
127+
128+
/// @notice Increments the counter by a specified encrypted value.
129+
/// @dev This example omits overflow/underflow checks for simplicity and readability.
130+
/// In a production contract, proper range checks should be implemented.
131+
function increment(externalEuint32 inputEuint32, bytes calldata inputProof) external {
132+
euint32 encryptedEuint32 = FHE.fromExternal(inputEuint32, inputProof);
133+
134+
_count = FHE.add(_count, encryptedEuint32);
135+
136+
FHE.allowThis(_count);
137+
FHE.allow(_count, msg.sender);
138+
}
139+
140+
/// @notice Decrements the counter by a specified encrypted value.
141+
/// @dev This example omits overflow/underflow checks for simplicity and readability.
142+
/// In a production contract, proper range checks should be implemented.
143+
function decrement(externalEuint32 inputEuint32, bytes calldata inputProof) external {
144+
euint32 encryptedEuint32 = FHE.fromExternal(inputEuint32, inputProof);
145+
146+
_count = FHE.sub(_count, encryptedEuint32);
147+
148+
FHE.allowThis(_count);
149+
FHE.allow(_count, msg.sender);
150+
}
151+
}
152+
```
153+
{% endtab %}
154+
155+
{% tab title="FHECounter.ts" %}
156+
```ts
157+
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";
158+
import { ethers, fhevm } from "hardhat";
159+
import { FHECounter, FHECounter__factory } from "../types";
160+
import { expect } from "chai";
161+
import { FhevmType } from "@fhevm/hardhat-plugin";
162+
163+
type Signers = {
164+
deployer: HardhatEthersSigner;
165+
alice: HardhatEthersSigner;
166+
bob: HardhatEthersSigner;
167+
};
168+
169+
async function deployFixture() {
170+
const factory = (await ethers.getContractFactory("FHECounter")) as FHECounter__factory;
171+
const fheCounterContract = (await factory.deploy()) as FHECounter;
172+
const fheCounterContractAddress = await fheCounterContract.getAddress();
173+
174+
return { fheCounterContract, fheCounterContractAddress };
175+
}
176+
177+
describe("FHECounter", function () {
178+
let signers: Signers;
179+
let fheCounterContract: FHECounter;
180+
let fheCounterContractAddress: string;
181+
182+
before(async function () {
183+
const ethSigners: HardhatEthersSigner[] = await ethers.getSigners();
184+
signers = { deployer: ethSigners[0], alice: ethSigners[1], bob: ethSigners[2] };
185+
});
186+
187+
beforeEach(async () => {
188+
({ fheCounterContract, fheCounterContractAddress } = await deployFixture());
189+
});
190+
191+
it("encrypted count should be uninitialized after deployment", async function () {
192+
const encryptedCount = await fheCounterContract.getCount();
193+
// Expect initial count to be bytes32(0) after deployment,
194+
// (meaning the encrypted count value is uninitialized)
195+
expect(encryptedCount).to.eq(ethers.ZeroHash);
196+
});
197+
198+
it("increment the counter by 1", async function () {
199+
const encryptedCountBeforeInc = await fheCounterContract.getCount();
200+
expect(encryptedCountBeforeInc).to.eq(ethers.ZeroHash);
201+
const clearCountBeforeInc = 0;
202+
203+
// Encrypt constant 1 as a euint32
204+
const clearOne = 1;
205+
const encryptedOne = await fhevm
206+
.createEncryptedInput(fheCounterContractAddress, signers.alice.address)
207+
.add32(clearOne)
208+
.encrypt();
209+
210+
const tx = await fheCounterContract
211+
.connect(signers.alice)
212+
.increment(encryptedOne.handles[0], encryptedOne.inputProof);
213+
await tx.wait();
214+
215+
const encryptedCountAfterInc = await fheCounterContract.getCount();
216+
const clearCountAfterInc = await fhevm.userDecryptEuint(
217+
FhevmType.euint32,
218+
encryptedCountAfterInc,
219+
fheCounterContractAddress,
220+
signers.alice,
221+
);
222+
223+
expect(clearCountAfterInc).to.eq(clearCountBeforeInc + clearOne);
224+
});
225+
226+
it("decrement the counter by 1", async function () {
227+
// Encrypt constant 1 as a euint32
228+
const clearOne = 1;
229+
const encryptedOne = await fhevm
230+
.createEncryptedInput(fheCounterContractAddress, signers.alice.address)
231+
.add32(clearOne)
232+
.encrypt();
233+
234+
// First increment by 1, count becomes 1
235+
let tx = await fheCounterContract
236+
.connect(signers.alice)
237+
.increment(encryptedOne.handles[0], encryptedOne.inputProof);
238+
await tx.wait();
239+
240+
// Then decrement by 1, count goes back to 0
241+
tx = await fheCounterContract.connect(signers.alice).decrement(encryptedOne.handles[0], encryptedOne.inputProof);
242+
await tx.wait();
243+
244+
const encryptedCountAfterDec = await fheCounterContract.getCount();
245+
const clearCountAfterInc = await fhevm.userDecryptEuint(
246+
FhevmType.euint32,
247+
encryptedCountAfterDec,
248+
fheCounterContractAddress,
249+
signers.alice,
250+
);
251+
252+
expect(clearCountAfterInc).to.eq(0);
253+
});
254+
});
255+
```
256+
{% endtab %}
257+
258+
{% endtabs %}

docs/examples/fhe-encrypt-multiple-value.md

Whitespace-only changes.

docs/examples/fhe-encrypt-single-value.md

Whitespace-only changes.

docs/examples/fheadd.md

Whitespace-only changes.

docs/examples/fheifthenelse.md

Whitespace-only changes.

docs/examples/tutorials/counter/code/contracts/Counter.sol.md

Lines changed: 0 additions & 25 deletions
This file was deleted.

docs/examples/tutorials/counter/code/test/Counter.ts.md

Lines changed: 0 additions & 60 deletions
This file was deleted.

0 commit comments

Comments
 (0)