diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
new file mode 100644
index 0000000..c37e774
--- /dev/null
+++ b/.github/workflows/test.yml
@@ -0,0 +1,25 @@
+name: Test
+
+on:
+ pull_request:
+ branches:
+ - main
+ push:
+ branches:
+ - main
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [20.x]
+ steps:
+ - uses: actions/checkout@v3
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v3
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: npm ci
+ - run: npm run prettier:check
+ - run: npm run build
diff --git a/README.md b/README.md
index b7dbdc6..4a7f818 100644
--- a/README.md
+++ b/README.md
@@ -18,9 +18,7 @@ Copy `.env.example` to `.env` and update the gateway URL, ACL address, and KMS a
npm run dev
```
-The server listens on [http://localhost:4173/](http://localhost:4173/)
-
-Note: HMR is currently broken because Vite does not handle WASM correctly. A workaround has been implemented as a script: running `npm run dev` will execute a build watch alongside Vite preview. If you have a solution for enabling the Vite dev server with HMR, feel free to open a pull request! :)
+The server listens on [http://localhost:5173/](http://localhost:5173/)
## Build
diff --git a/index.html b/index.html
index dde16aa..1780dda 100644
--- a/index.html
+++ b/index.html
@@ -1,10 +1,11 @@
-
+
+
- Vite + Vue + TS
+ fhEVM Vue demo
diff --git a/package-lock.json b/package-lock.json
index 59a748e..0e457e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,13 +9,14 @@
"version": "0.0.0",
"dependencies": {
"ethers": "^6.13.4",
- "fhevmjs": "^0.6.0",
+ "fhevmjs": "^0.6.2",
"idb": "^8.0.0",
+ "typescript": "5.6.2",
"vue": "^3.5.13"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
- "typescript": "^5.7.2",
+ "prettier": "^3.4.2",
"vite": "^5.4.11",
"vite-plugin-node-polyfills": "^0.22.0",
"vue-tsc": "^2.1.10"
@@ -1637,9 +1638,9 @@
}
},
"node_modules/fhevmjs": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/fhevmjs/-/fhevmjs-0.6.0.tgz",
- "integrity": "sha512-xukyiXv+KertTTEIhFuZp2jW31RBOXUC6TfVZBAUVEr1xiTnvXtePwuutvqj3rabnclRBTzr/j4UmEPvCaGXQw==",
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/fhevmjs/-/fhevmjs-0.6.2.tgz",
+ "integrity": "sha512-Kiq59DiqusavaCft8AzSVF2G92ZrNyf3u2dmu3zqlOxK5TGXAIY7PNICrV4xvT+pVxiAF88auNP+tH/dFqx1iA==",
"license": "BSD-3-Clause-Clear",
"dependencies": {
"bigint-buffer": "^1.1.5",
@@ -1647,9 +1648,9 @@
"fetch-mock": "^11.1.3",
"keccak": "^3.0.4",
"node-tfhe": "^0.9.1",
- "node-tkms": "0.9.0-rc36",
+ "node-tkms": "^0.9.0",
"tfhe": "^0.9.1",
- "tkms": "0.9.0-rc36",
+ "tkms": "^0.9.0",
"wasm-feature-detect": "^1.8.0"
},
"bin": {
@@ -2222,9 +2223,9 @@
"license": "BSD-3-Clause-Clear"
},
"node_modules/node-tkms": {
- "version": "0.9.0-rc36",
- "resolved": "https://registry.npmjs.org/node-tkms/-/node-tkms-0.9.0-rc36.tgz",
- "integrity": "sha512-oGqJfjvb/igd9VgQaqYbzKc+CmrnQ/eY0ShmdE3JDKXL3C4Re/tBswT0KkWmlT1aM+Lxt5ihRNOs2oHtrPqr5w==",
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/node-tkms/-/node-tkms-0.9.0.tgz",
+ "integrity": "sha512-ulhV23okeMW3WYnxzhvf9u87tcXqe64JqUFlvdgu64uKteG8re+zwOjzkOdxvF0xSWQbMtEU96dvcrvQM10PEg==",
"license": "BSD-3-Clause-Clear"
},
"node_modules/object-inspect": {
@@ -2445,6 +2446,22 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/prettier": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
+ "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@@ -2774,9 +2791,9 @@
}
},
"node_modules/tkms": {
- "version": "0.9.0-rc36",
- "resolved": "https://registry.npmjs.org/tkms/-/tkms-0.9.0-rc36.tgz",
- "integrity": "sha512-8IoRi6mYgnrmwTNBe/ejvHOFRhs5M6o2Ls2RVXCgAzSVBBBWJC1O8hquqlciHfME/VooUD4iokzEaBfADvoXZw==",
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/tkms/-/tkms-0.9.0.tgz",
+ "integrity": "sha512-dSzorTHvIXTYZtn6ACV/iz0GhO/kMRjqGbo3o7JJ3GNbFhsPzbIEtAQ/x+h9nJdwn//VRdsStnOAE0fxUVIGrQ==",
"license": "BSD-3-Clause-Clear"
},
"node_modules/tslib": {
@@ -2792,10 +2809,9 @@
"dev": true
},
"node_modules/typescript": {
- "version": "5.7.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz",
- "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
- "devOptional": true,
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
+ "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
diff --git a/package.json b/package.json
index c38eb0e..802bcb9 100644
--- a/package.json
+++ b/package.json
@@ -4,19 +4,22 @@
"version": "0.0.0",
"type": "module",
"scripts": {
- "dev": "node scripts/dev.js",
+ "dev": "vite",
"build": "vue-tsc && vite build",
- "preview": "vite preview"
+ "preview": "vite preview",
+ "prettier": "prettier --write \"**/*.{js,json,md,sol,ts,yml}\"",
+ "prettier:check": "prettier --check \"**/*.{js,json,md,sol,ts,yml}\""
},
"dependencies": {
"ethers": "^6.13.4",
- "fhevmjs": "^0.6.0",
+ "fhevmjs": "^0.6.2",
"idb": "^8.0.0",
+ "typescript": "5.6.2",
"vue": "^3.5.13"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
- "typescript": "^5.7.2",
+ "prettier": "^3.4.2",
"vite": "^5.4.11",
"vite-plugin-node-polyfills": "^0.22.0",
"vue-tsc": "^2.1.10"
diff --git a/scripts/dev.js b/scripts/dev.js
index 01e2308..ca070c2 100644
--- a/scripts/dev.js
+++ b/scripts/dev.js
@@ -1,23 +1,23 @@
-import { build, preview } from 'vite';
+import { build, preview } from "vite";
(async () => {
try {
await preview({
- BASE_URL: '/',
- MODE: 'production',
+ BASE_URL: "/",
+ MODE: "production",
DEV: false,
PROD: true,
});
- console.log('Preview server is running...');
- console.log('Listening on http://localhost:4173\n');
+ console.log("Preview server is running...");
+ console.log("Listening on http://localhost:4173\n");
const watcher = await build({
build: {
watch: {},
},
});
- console.log('Build in watch mode is running...');
+ console.log("Build in watch mode is running...");
} catch (err) {
- console.error('Error:', err);
+ console.error("Error:", err);
}
})();
diff --git a/src/components/Connect.vue b/src/components/Connect.vue
index fbb9fe8..9793304 100644
--- a/src/components/Connect.vue
+++ b/src/components/Connect.vue
@@ -20,8 +20,6 @@ const refreshNetwork = async () => {
loading.value = true;
await createFhevmInstance();
loading.value = false;
- } else {
- setValidNetwork(false);
}
};
diff --git a/src/components/Devnet.vue b/src/components/Devnet.vue
index e938bc8..4928f30 100644
--- a/src/components/Devnet.vue
+++ b/src/components/Devnet.vue
@@ -5,13 +5,12 @@ import { getInstance } from '../fhevmjs';
const toHexString = (bytes: Uint8Array) => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
-const handles = ref(null);
-const inputProof = ref(null);
+const handles = ref(null);
+const inputProof = ref(null);
const instance = getInstance();
-const encrypt = async (val: number) => {
- const now = Date.now();
+const encrypt = async () => {
const enc = await instance
.createEncryptedInput(
getAddress('0x309cf2aae85ad8a1db70ca88cfd4225bf17a7456'),
diff --git a/src/fhevmStorage.ts b/src/fhevmStorage.ts
index f505cea..c6fc445 100644
--- a/src/fhevmStorage.ts
+++ b/src/fhevmStorage.ts
@@ -1,4 +1,4 @@
-import { openDB, DBSchema, IDBPDatabase } from 'idb';
+import { openDB, DBSchema, IDBPDatabase } from "idb";
interface PublicParamsDB extends DBSchema {
publicKeyStore: {
@@ -17,32 +17,36 @@ interface PublicParamsDB extends DBSchema {
};
}
-const dbPromise: Promise> = openDB('fhevm', 1, {
- upgrade(db) {
- if (!db.objectStoreNames.contains('paramsStore')) {
- db.createObjectStore('paramsStore', { keyPath: 'acl' });
- }
- if (!db.objectStoreNames.contains('publicKeyStore')) {
- db.createObjectStore('publicKeyStore', { keyPath: 'acl' });
- }
+const dbPromise: Promise> = openDB(
+ "fhevm",
+ 1,
+ {
+ upgrade(db) {
+ if (!db.objectStoreNames.contains("paramsStore")) {
+ db.createObjectStore("paramsStore", { keyPath: "acl" });
+ }
+ if (!db.objectStoreNames.contains("publicKeyStore")) {
+ db.createObjectStore("publicKeyStore", { keyPath: "acl" });
+ }
+ },
},
-});
+);
export async function storePublicParams(
acl: string,
- value: { publicParamsId: string; publicParams: Uint8Array }
+ value: { publicParamsId: string; publicParams: Uint8Array },
): Promise {
const db = await dbPromise;
- await db.put('paramsStore', { acl, value });
+ await db.put("paramsStore", { acl, value });
console.log(`Stored public params for: ${acl}`);
}
export async function getPublicParams(
- acl: string
+ acl: string,
): Promise<{ publicParamsId: string; publicParams: Uint8Array } | null> {
const db = await dbPromise;
try {
- const result = await db.get('paramsStore', acl);
+ const result = await db.get("paramsStore", acl);
return result ? result.value : null;
} catch (e) {
return null;
@@ -51,17 +55,19 @@ export async function getPublicParams(
export async function storePublicKey(
acl: string,
- value: { publicKeyId: string; publicKey: Uint8Array }
+ value: { publicKeyId: string; publicKey: Uint8Array },
): Promise {
const db = await dbPromise;
- await db.put('publicKeyStore', { acl, value });
+ await db.put("publicKeyStore", { acl, value });
console.log(`Stored public key for: ${acl}`);
}
-export async function getPublicKey(acl: string): Promise<{ publicKeyId: string; publicKey: Uint8Array } | null> {
+export async function getPublicKey(
+ acl: string,
+): Promise<{ publicKeyId: string; publicKey: Uint8Array } | null> {
const db = await dbPromise;
try {
- const result = await db.get('publicKeyStore', acl);
+ const result = await db.get("publicKeyStore", acl);
return result ? result.value : null;
} catch (e) {
return null;
diff --git a/src/fhevmjs.ts b/src/fhevmjs.ts
index 227d5ee..02629f2 100644
--- a/src/fhevmjs.ts
+++ b/src/fhevmjs.ts
@@ -1,6 +1,11 @@
-import { isAddress } from 'ethers';
-import { initFhevm, createInstance, FhevmInstance } from 'fhevmjs';
-import { getPublicKey, getPublicParams, storePublicKey, storePublicParams } from './fhevmStorage';
+import { isAddress } from "ethers";
+import { initFhevm, createInstance, FhevmInstance } from "fhevmjs/bundle";
+import {
+ getPublicKey,
+ getPublicParams,
+ storePublicKey,
+ storePublicParams,
+} from "./fhevmStorage";
const ACL_ADDRESS: string = import.meta.env.VITE_ACL_ADDRESS;
@@ -16,9 +21,7 @@ type Keypairs = {
};
};
-export const init = async () => {
- await initFhevm({ thread: navigator.hardwareConcurrency });
-};
+export const init = initFhevm;
let instancePromise: Promise;
let instance: FhevmInstance;
@@ -33,7 +36,7 @@ export const createFhevmInstance = async () => {
const storedPublicParams = await getPublicParams(ACL_ADDRESS);
const publicParams = storedPublicParams
? {
- '2048': storedPublicParams,
+ "2048": storedPublicParams,
}
: null;
instancePromise = createInstance({
@@ -56,14 +59,23 @@ export const createFhevmInstance = async () => {
}
};
-export const setKeypair = (contractAddress: string, userAddress: string, keypair: Keypair) => {
+export const setKeypair = (
+ contractAddress: string,
+ userAddress: string,
+ keypair: Keypair,
+) => {
if (!isAddress(contractAddress) || !isAddress(userAddress)) return;
keypairs[userAddress][contractAddress] = keypair;
};
-export const getKeypair = (contractAddress: string, userAddress: string): Keypair | null => {
+export const getKeypair = (
+ contractAddress: string,
+ userAddress: string,
+): Keypair | null => {
if (!isAddress(contractAddress) || !isAddress(userAddress)) return null;
- return keypairs[userAddress] ? keypairs[userAddress][contractAddress] || null : null;
+ return keypairs[userAddress]
+ ? keypairs[userAddress][contractAddress] || null
+ : null;
};
export const getInstance = (): FhevmInstance => {
diff --git a/src/main.ts b/src/main.ts
index 2425c0f..3c9bfeb 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,5 +1,5 @@
-import { createApp } from 'vue'
-import './style.css'
-import App from './App.vue'
+import { createApp } from "vue";
+import "./style.css";
+import App from "./App.vue";
-createApp(App).mount('#app')
+createApp(App).mount("#app");
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts
index 31abf91..e2857a2 100644
--- a/src/vite-env.d.ts
+++ b/src/vite-env.d.ts
@@ -1,5 +1,7 @@
///
interface Window {
- ethereum: import('ethers').Eip1193Provider & { on: (event: string, cb: (param: any) => any) => void };
+ ethereum: import("ethers").Eip1193Provider & {
+ on: (event: string, cb: (param: any) => any) => void;
+ };
}
diff --git a/vite.config.ts b/vite.config.ts
index 185a193..0f41013 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,23 +1,14 @@
-import { defineConfig } from 'vite';
-import vue from '@vitejs/plugin-vue';
-import { nodePolyfills } from 'vite-plugin-node-polyfills';
+import { defineConfig } from "vite";
+import vue from "@vitejs/plugin-vue";
+import { nodePolyfills } from "vite-plugin-node-polyfills";
export default defineConfig({
- assetsInclude: ['**/*.bin'],
+ assetsInclude: ["**/*.bin"],
plugins: [vue(), nodePolyfills()],
server: {
- port: 9000,
headers: {
- 'Cross-Origin-Opener-Policy': 'same-origin',
- 'Cross-Origin-Embedder-Policy': 'require-corp',
- },
- },
- worker: {
- format: 'es',
- rollupOptions: {
- output: {
- entryFileNames: '[name].js',
- },
+ "Cross-Origin-Opener-Policy": "same-origin",
+ "Cross-Origin-Embedder-Policy": "require-corp",
},
},
});