const { cofhejs, FheTypes, Encryptable } = require("cofhejs/node");
const { ethers } = require("ethers");
// Initialize your web3 provider
const provider = new ethers.JsonRpcProvider("http://127.0.0.1:42069");
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
// Initialize cofhejs Client with ethers
const initResult = await cofhejs.initializeWithEthers({
ethersProvider: provider,
ethersSigner: wallet,
environment: "TESTNET"
});
if (!initResult.success) {
console.error("Failed to initialize cofhejs:", initResult.error);
process.exit(1);
}
// Set up the contract instance
const contract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, wallet);
// Set up encryption state logging callback
const logState = (state) => {
console.log(`Encryption State: ${state}`);
};
// Step 5: Function to read decrypted counter value
// This reads the counter after it has been decrypted on-chain
const readCounterDecryptedValue = async () => {
try {
const result = await contract.get_counter_value();
console.log("Decrypted counter value:", result.toString());
return result;
} catch (error) {
console.error("Error reading decrypted counter:", error);
throw error;
}
};
// Step 6: Function to read encrypted counter value and unseal it
// This demonstrates the unsealing process for encrypted data
const readCounterEncryptedValue = async () => {
try {
// Get the encrypted counter value from the contract
const encryptedResult = await contract.get_encrypted_counter_value();
console.log("Encrypted counter value:", encryptedResult);
// Step 7: Create a permit to authorize unsealing
// The permit proves you own the private key to decrypt this data
const permitResult = await cofhejs.createPermit({
type: "self",
issuer: wallet.address
});
if (!permitResult.success) {
console.error("Failed to create permit:", permitResult.error);
return;
}
const permit = permitResult.data;
// Step 8: Unseal the encrypted value
// When creating a permit, cofhejs will use it automatically,
// but you can pass it manually as well for explicit control
const unsealResult = await cofhejs.unseal(
encryptedResult,
FheTypes.Uint64,
permit.data.issuer,
permit.data.getHash()
);
if (!unsealResult.success) {
console.error("Failed to unseal counter:", unsealResult.error);
return;
}
console.log("Unsealed counter value:", unsealResult.data.toString());
return unsealResult.data;
} catch (error) {
console.error("Error reading encrypted counter:", error);
throw error;
}
};
// Step 9: Function to increment the counter
// This adds 1 to the encrypted counter value on-chain
const incrementCounter = async () => {
try {
const tx = await contract.increment_counter();
console.log("Increment transaction hash:", tx.hash);
// Wait for transaction confirmation
const receipt = await tx.wait();
console.log("Transaction confirmed in block:", receipt.blockNumber);
return receipt;
} catch (error) {
console.error("Error incrementing counter:", error);
throw error;
}
};
// Step 10: Function to reset the counter with an encrypted value
// This demonstrates encrypting input data before sending to the contract
const resetCounter = async (encryptedValue) => {
try {
// Send the encrypted value to the contract
const tx = await contract.reset_counter(encryptedValue);
console.log("Reset counter transaction hash:", tx.hash);
// Wait for transaction confirmation
const receipt = await tx.wait();
console.log("Transaction confirmed in block:", receipt.blockNumber);
return receipt;
} catch (error) {
console.error("Error resetting counter:", error);
throw error;
}
};
// Step 11: Function to decrypt the counter on-chain
// This requests the contract to decrypt the counter value
const decryptCounter = async () => {
try {
const tx = await contract.decrypt_counter();
console.log("Decrypt counter transaction hash:", tx.hash);
// Wait for transaction confirmation
const receipt = await tx.wait();
console.log("Transaction confirmed in block:", receipt.blockNumber);
return receipt;
} catch (error) {
console.error("Error decrypting counter:", error);
throw error;
}
};
// ============================================
// Example Usage Flow
// ============================================
async function main() {
console.log("=== Starting End-to-End Example ===\n");
try {
// Step 1: Read initial counter value
// Expected: 0 (or uninitialized)
console.log("1. Reading initial counter value...");
const initialValue = await readCounterDecryptedValue();
console.log(` ✓ Initial value: ${initialValue.toString()}`);
// Step 2: Increment the counter
// Adds 1 to the encrypted counter value on-chain
console.log("\n2. Incrementing counter...");
await incrementCounter();
console.log(" ✓ Counter incremented successfully");
// Step 3: Read and unseal encrypted counter
// Expected: 1 (after unsealing)
console.log("\n3. Reading encrypted counter value...");
const unsealedValue1 = await readCounterEncryptedValue();
console.log(` ✓ Unsealed value: ${unsealedValue1.toString()}`);
// Step 4: Increment again
console.log("\n4. Incrementing counter again...");
await incrementCounter();
console.log(" ✓ Counter incremented successfully");
// Step 5: Decrypt the counter on-chain
console.log("\n5. Decrypting counter on-chain...");
await decryptCounter();
console.log(" ✓ Counter decrypted on-chain");
// Step 6: Read the decrypted value
// Expected: 2
console.log("\n6. Reading decrypted counter value...");
const decryptedValue = await readCounterDecryptedValue();
console.log(` ✓ Decrypted value: ${decryptedValue.toString()}`);
// Step 7: Encrypt new value and reset counter
console.log("\n7. Encrypting new value (10) and resetting counter...");
const encryptResult = await cofhejs.encrypt([Encryptable.uint64(10n)], logState);
if (!encryptResult.success) {
console.error("Failed to encrypt value:", encryptResult.error);
return;
}
await resetCounter(encryptResult.data[0]);
console.log(" ✓ Counter reset with encrypted value 10");
// Step 8: Read encrypted counter after reset
// Expected: 10 (after unsealing)
console.log("\n8. Reading encrypted counter value after reset...");
const unsealedValue2 = await readCounterEncryptedValue();
console.log(` ✓ Unsealed value: ${unsealedValue2.toString()}`);
console.log("\n=== Example completed successfully ===");
} catch (error) {
console.error("\n=== Example failed ===");
console.error("Error:", error);
process.exit(1);
}
}
// Run the example
main();