mirror of
https://github.com/zama-ai/fhevm-solidity.git
synced 2026-01-08 20:18:02 -05:00
feat() add hardhat test and template
This commit is contained in:
10
.env.example
Normal file
10
.env.example
Normal file
@@ -0,0 +1,10 @@
|
||||
export INFURA_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||
export MNEMONIC="adapt mosquito move limb mobile illegal tree voyage juice mosquito burger raise father hope layer"
|
||||
|
||||
# Block explorer API keys
|
||||
export ARBISCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||
export BSCSCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||
export ETHERSCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||
export OPTIMISM_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||
export POLYGONSCAN_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||
export SNOWTRACE_API_KEY="zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
|
||||
21
.eslintignore
Normal file
21
.eslintignore
Normal file
@@ -0,0 +1,21 @@
|
||||
# directories
|
||||
.coverage_artifacts
|
||||
.coverage_cache
|
||||
.coverage_contracts
|
||||
artifacts
|
||||
build
|
||||
cache
|
||||
coverage
|
||||
dist
|
||||
node_modules
|
||||
types
|
||||
|
||||
# files
|
||||
*.env
|
||||
*.log
|
||||
.DS_Store
|
||||
.pnp.*
|
||||
coverage.json
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
22
.eslintrc.yml
Normal file
22
.eslintrc.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
extends:
|
||||
- "eslint:recommended"
|
||||
- "plugin:@typescript-eslint/eslint-recommended"
|
||||
- "plugin:@typescript-eslint/recommended"
|
||||
- "prettier"
|
||||
parser: "@typescript-eslint/parser"
|
||||
parserOptions:
|
||||
project: "tsconfig.json"
|
||||
plugins:
|
||||
- "@typescript-eslint"
|
||||
root: true
|
||||
rules:
|
||||
"@typescript-eslint/no-floating-promises":
|
||||
- error
|
||||
- ignoreIIFE: true
|
||||
ignoreVoid: true
|
||||
"@typescript-eslint/no-inferrable-types": "off"
|
||||
"@typescript-eslint/no-non-null-assertion": "off"
|
||||
"@typescript-eslint/no-unused-vars":
|
||||
- error
|
||||
- argsIgnorePattern: "_"
|
||||
varsIgnorePattern: "_"
|
||||
142
.gitignore
vendored
142
.gitignore
vendored
@@ -1,18 +1,132 @@
|
||||
decrypt/target
|
||||
decrypt/ciphertexts
|
||||
res/
|
||||
node_modules/
|
||||
.venv
|
||||
.vscode
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.env
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
coverage.json
|
||||
typechain
|
||||
typechain-types
|
||||
*.lcov
|
||||
|
||||
# Hardhat files
|
||||
cache
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
public/
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
||||
|
||||
# Python app
|
||||
res/
|
||||
.venv
|
||||
.env
|
||||
|
||||
# Hardhat
|
||||
artifacts
|
||||
|
||||
.coverage_artifacts
|
||||
.coverage_cache
|
||||
.coverage_contracts
|
||||
coverage.json
|
||||
build
|
||||
cache
|
||||
types
|
||||
deployments
|
||||
typechain
|
||||
typechain-types
|
||||
10
.gitpod.yml
Normal file
10
.gitpod.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
image: "gitpod/workspace-node:latest"
|
||||
|
||||
tasks:
|
||||
- init: "pnpm install"
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- "esbenp.prettier-vscode"
|
||||
- "NomicFoundation.hardhat-solidity"
|
||||
- "ritwickdey.LiveServer"
|
||||
21
.prettierignore
Normal file
21
.prettierignore
Normal file
@@ -0,0 +1,21 @@
|
||||
# directories
|
||||
.coverage_artifacts
|
||||
.coverage_cache
|
||||
.coverage_contracts
|
||||
artifacts
|
||||
build
|
||||
cache
|
||||
coverage
|
||||
dist
|
||||
node_modules
|
||||
types
|
||||
|
||||
# files
|
||||
*.env
|
||||
*.log
|
||||
.DS_Store
|
||||
.pnp.*
|
||||
coverage.json
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
23
.prettierrc.yml
Normal file
23
.prettierrc.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
bracketSpacing: true
|
||||
plugins:
|
||||
- "@trivago/prettier-plugin-sort-imports"
|
||||
- "prettier-plugin-solidity"
|
||||
printWidth: 120
|
||||
proseWrap: "always"
|
||||
singleQuote: false
|
||||
tabWidth: 2
|
||||
trailingComma: "all"
|
||||
|
||||
overrides:
|
||||
- files: "*.sol"
|
||||
options:
|
||||
compiler: "0.8.17"
|
||||
parser: "solidity-parse"
|
||||
tabWidth: 4
|
||||
- files: "*.ts"
|
||||
options:
|
||||
importOrder: ["<THIRD_PARTY_MODULES>", "^[./]"]
|
||||
importOrderParserPlugins: ["typescript"]
|
||||
importOrderSeparation: true
|
||||
importOrderSortSpecifiers: true
|
||||
parser: "typescript"
|
||||
7
.solcover.js
Normal file
7
.solcover.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
istanbulReporter: ["html", "lcov"],
|
||||
providerOptions: {
|
||||
mnemonic: process.env.MNEMONIC,
|
||||
},
|
||||
skipFiles: ["test"],
|
||||
};
|
||||
19
.solhint.json
Normal file
19
.solhint.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "solhint:recommended",
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"code-complexity": ["error", 8],
|
||||
"compiler-version": ["error", ">=0.8.4"],
|
||||
"func-visibility": ["error", { "ignoreConstructors": true }],
|
||||
"max-line-length": ["error", 120],
|
||||
"named-parameters-mapping": "warn",
|
||||
"no-console": "off",
|
||||
"not-rely-on-time": "off",
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
3
.solhintignore
Normal file
3
.solhintignore
Normal file
@@ -0,0 +1,3 @@
|
||||
# directories
|
||||
**/artifacts
|
||||
**/node_modules
|
||||
@@ -1,10 +1,83 @@
|
||||
import { HardhatUserConfig } from "hardhat/config";
|
||||
import "./tasks/accounts";
|
||||
import "./tasks/mint";
|
||||
import "./tasks/taskDeploy";
|
||||
import "@nomicfoundation/hardhat-toolbox";
|
||||
import { config as dotenvConfig } from "dotenv";
|
||||
import "hardhat-deploy";
|
||||
import type { HardhatUserConfig } from "hardhat/config";
|
||||
import type { NetworkUserConfig } from "hardhat/types";
|
||||
import { resolve } from "path";
|
||||
|
||||
const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || "./.env";
|
||||
dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) });
|
||||
|
||||
// Ensure that we have all the environment variables we need.
|
||||
const mnemonic: string | undefined = process.env.MNEMONIC;
|
||||
if (!mnemonic) {
|
||||
throw new Error("Please set your MNEMONIC in a .env file");
|
||||
}
|
||||
|
||||
const chainIds = {
|
||||
zama: 8009,
|
||||
};
|
||||
|
||||
function getChainConfig(chain: keyof typeof chainIds): NetworkUserConfig {
|
||||
let jsonRpcUrl: string;
|
||||
switch (chain) {
|
||||
case "zama":
|
||||
jsonRpcUrl = "https://devnet.zama.ai";
|
||||
break;
|
||||
}
|
||||
return {
|
||||
accounts: {
|
||||
count: 10,
|
||||
mnemonic,
|
||||
path: "m/44'/60'/0'/0",
|
||||
},
|
||||
chainId: chainIds[chain],
|
||||
url: jsonRpcUrl,
|
||||
};
|
||||
}
|
||||
|
||||
const config: HardhatUserConfig = {
|
||||
solidity: "0.8.18",
|
||||
defaultNetwork: "zama",
|
||||
namedAccounts: {
|
||||
deployer: 0,
|
||||
},
|
||||
gasReporter: {
|
||||
currency: "USD",
|
||||
enabled: process.env.REPORT_GAS ? true : false,
|
||||
excludeContracts: [],
|
||||
src: "./contracts",
|
||||
},
|
||||
networks: {
|
||||
zama: getChainConfig("zama"),
|
||||
},
|
||||
paths: {
|
||||
sources: "./examples",
|
||||
artifacts: "./artifacts",
|
||||
cache: "./cache",
|
||||
sources: "./contracts",
|
||||
tests: "./test",
|
||||
},
|
||||
solidity: {
|
||||
version: "0.8.17",
|
||||
settings: {
|
||||
metadata: {
|
||||
// Not including the metadata hash
|
||||
// https://github.com/paulrberg/hardhat-template/issues/31
|
||||
bytecodeHash: "none",
|
||||
},
|
||||
// Disable the optimizer when debugging
|
||||
// https://hardhat.org/hardhat-network/#solidity-optimizer-support
|
||||
optimizer: {
|
||||
enabled: true,
|
||||
runs: 800,
|
||||
},
|
||||
},
|
||||
},
|
||||
typechain: {
|
||||
outDir: "types",
|
||||
target: "ethers-v6",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
10239
package-lock.json
generated
10239
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@@ -8,11 +8,18 @@
|
||||
"lib": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"codegen": "cd ./lib && python ../codegen/codegen.py && npm run prettier && cd ..",
|
||||
"lint": "prettier --list-different '**/*.sol'",
|
||||
"prettier": "prettier --write '**/*.sol'",
|
||||
"clean": "rimraf ./artifacts ./cache ./coverage ./types ./coverage.json && npm run typechain",
|
||||
"compile": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat compile",
|
||||
"coverage": "hardhat coverage --solcoverjs ./.solcover.js --temp artifacts --testfiles \"test/**/*.ts\" && pnpm typechain",
|
||||
"deploy:contracts": "hardhat deploy",
|
||||
"lint": "npm run lint:sol && npm run lint:ts && npm run prettier:check",
|
||||
"lint:sol": "solhint --max-warnings 0 \"contracts/**/*.sol\"",
|
||||
"lint:ts": "eslint --ignore-path ./.eslintignore --ext .js,.ts .",
|
||||
"prettier:check": "prettier --check \"**/*.{js,json,md,sol,ts,yml}\"",
|
||||
"prettier": "prettier --write \"**/*.{js,json,md,sol,ts,yml}\"",
|
||||
"test": "hardhat test",
|
||||
"build": "hardhat compile"
|
||||
"typechain": "cross-env TS_NODE_TRANSPILE_ONLY=true hardhat typechain",
|
||||
"codegen": "cd ./lib && python ../codegen/codegen.py && npm run prettier && cd .."
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -25,12 +32,44 @@
|
||||
},
|
||||
"homepage": "https://github.com/zama-ai/fhevm-solidity#readme",
|
||||
"devDependencies": {
|
||||
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
|
||||
"@nomicfoundation/hardhat-ethers": "^3.0.0",
|
||||
"@nomicfoundation/hardhat-network-helpers": "^1.0.6",
|
||||
"@nomicfoundation/hardhat-toolbox": "^3.0.0",
|
||||
"hardhat": "^2.16.1",
|
||||
"@nomicfoundation/hardhat-verify": "^1.0.0",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
|
||||
"@typechain/ethers-v6": "^0.4.0",
|
||||
"@typechain/hardhat": "^8.0.0",
|
||||
"@types/chai": "^4.3.4",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "^18.11.9",
|
||||
"@typescript-eslint/eslint-plugin": "^5.44.0",
|
||||
"@typescript-eslint/parser": "^5.44.0",
|
||||
"chai": "^4.3.7",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"ethers": "^6.4.0",
|
||||
"fhevmjs": "^0.1.3",
|
||||
"fs-extra": "^10.1.0",
|
||||
"ganache-cli": "^6.12.2",
|
||||
"hardhat": "^2.12.2",
|
||||
"hardhat-deploy": "^0.11.29",
|
||||
"hardhat-gas-reporter": "^1.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"mocha": "^10.1.0",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-solidity": "^1.1.3",
|
||||
"rimraf": "^4.1.2",
|
||||
"solhint": "^3.4.0",
|
||||
"solhint-plugin-prettier": "^0.0.5",
|
||||
"solidity-coverage": "^0.8.1",
|
||||
"ts-generator": "^0.1.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.5"
|
||||
"typechain": "^8.2.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^4.9.2"
|
||||
|
||||
9
tasks/accounts.ts
Normal file
9
tasks/accounts.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { task } from "hardhat/config";
|
||||
|
||||
task("accounts", "Prints the list of accounts", async (_taskArgs, hre) => {
|
||||
const accounts = await hre.ethers.getSigners();
|
||||
|
||||
for (const account of accounts) {
|
||||
console.log(account.address);
|
||||
}
|
||||
});
|
||||
22
tasks/mint.ts
Normal file
22
tasks/mint.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { task } from "hardhat/config";
|
||||
import type { TaskArguments } from "hardhat/types";
|
||||
|
||||
import { getInstance } from "../test/instance";
|
||||
|
||||
task("task:mint")
|
||||
.addParam("mint", "Tokens to mint")
|
||||
.addParam("account", "Specify which account [0, 9]")
|
||||
.setAction(async function (taskArguments: TaskArguments, hre) {
|
||||
const { ethers, deployments } = hre;
|
||||
const EncryptedERC20 = await deployments.get("EncryptedERC20");
|
||||
|
||||
const instance = await getInstance(EncryptedERC20.address, ethers);
|
||||
|
||||
const signers = await ethers.getSigners();
|
||||
|
||||
const encryptedERC20 = await ethers.getContractAt("EncryptedERC20", EncryptedERC20.address);
|
||||
|
||||
await encryptedERC20.connect(signers[taskArguments.account]).mint(instance.encrypt32(taskArguments.mint));
|
||||
|
||||
console.log("Mint done: ", taskArguments.mint);
|
||||
});
|
||||
10
tasks/taskDeploy.ts
Normal file
10
tasks/taskDeploy.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { task } from "hardhat/config";
|
||||
import type { TaskArguments } from "hardhat/types";
|
||||
|
||||
task("task:deployERC20").setAction(async function (taskArguments: TaskArguments, { ethers }) {
|
||||
const signers = await ethers.getSigners();
|
||||
const erc20Factory = await ethers.getContractFactory("EncryptedERC20");
|
||||
const encryptedERC20 = await erc20Factory.connect(signers[0]).deploy();
|
||||
await encryptedERC20.waitForDeployment();
|
||||
console.log("EncryptedERC20 deployed to: ", await encryptedERC20.getAddress());
|
||||
});
|
||||
14
test/encryptedERC20/EncryptedERC20.fixture.ts
Normal file
14
test/encryptedERC20/EncryptedERC20.fixture.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
import type { EncryptedERC20 } from "../../types/contracts/EncryptedERC20";
|
||||
|
||||
export async function deployEncryptedERC20Fixture(): Promise<EncryptedERC20> {
|
||||
const signers = await ethers.getSigners();
|
||||
const admin = signers[0];
|
||||
|
||||
const contractFactory = await ethers.getContractFactory("EncryptedERC20");
|
||||
const contract = await contractFactory.connect(admin).deploy();
|
||||
await contract.waitForDeployment();
|
||||
|
||||
return contract;
|
||||
}
|
||||
113
test/encryptedERC20/EncryptedERC20.ts
Normal file
113
test/encryptedERC20/EncryptedERC20.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { createInstances } from "../instance";
|
||||
import type { Signers } from "../types";
|
||||
import { deployEncryptedERC20Fixture } from "./EncryptedERC20.fixture";
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "hardhat";
|
||||
|
||||
describe("Unit tests", function () {
|
||||
before(async function () {
|
||||
this.signers = {} as Signers;
|
||||
const signers = await ethers.getSigners();
|
||||
this.signers.alice = signers[0];
|
||||
this.signers.bob = signers[1];
|
||||
this.signers.carol = signers[2];
|
||||
this.signers.dave = signers[3];
|
||||
});
|
||||
|
||||
describe("EncryptedERC20", function () {
|
||||
beforeEach(async function () {
|
||||
const contract = await deployEncryptedERC20Fixture();
|
||||
this.contractAddress = await contract.getAddress();
|
||||
this.erc20 = contract;
|
||||
const instances = await createInstances(
|
||||
this.contractAddress,
|
||||
ethers,
|
||||
this.signers
|
||||
);
|
||||
this.instances = instances;
|
||||
});
|
||||
|
||||
it("should mint the contract", async function () {
|
||||
const encryptedAmount = this.instances.alice.encrypt32(1000);
|
||||
const transaction = await this.erc20.mint(encryptedAmount);
|
||||
await transaction.wait();
|
||||
// Call the method
|
||||
const token = this.instances.alice.getTokenSignature(
|
||||
this.contractAddress
|
||||
) || {
|
||||
signature: "",
|
||||
publicKey: "",
|
||||
};
|
||||
const encryptedBalance = await this.erc20.balanceOf(
|
||||
token.publicKey,
|
||||
token.signature
|
||||
);
|
||||
// Decrypt the balance
|
||||
const balance = this.instances.alice.decrypt(
|
||||
this.contractAddress,
|
||||
encryptedBalance
|
||||
);
|
||||
expect(balance).to.equal(1000);
|
||||
|
||||
const encryptedTotalSupply = await this.erc20.getTotalSupply(
|
||||
token.publicKey,
|
||||
token.signature
|
||||
);
|
||||
// Decrypt the total supply
|
||||
const totalSupply = this.instances.alice.decrypt(
|
||||
this.contractAddress,
|
||||
encryptedTotalSupply
|
||||
);
|
||||
expect(totalSupply).to.equal(1000);
|
||||
});
|
||||
|
||||
it("should transfer tokens between two users", async function () {
|
||||
const encryptedAmount = this.instances.alice.encrypt32(10000);
|
||||
const transaction = await this.erc20.mint(encryptedAmount);
|
||||
await transaction.wait();
|
||||
|
||||
const encryptedTransferAmount = this.instances.alice.encrypt32(1337);
|
||||
const tx = await this.erc20["transfer(address,bytes)"](
|
||||
this.signers.bob.address,
|
||||
encryptedTransferAmount
|
||||
);
|
||||
await tx.wait();
|
||||
|
||||
const tokenAlice = this.instances.alice.getTokenSignature(
|
||||
this.contractAddress
|
||||
)!;
|
||||
|
||||
const encryptedBalanceAlice = await this.erc20.balanceOf(
|
||||
tokenAlice.publicKey,
|
||||
tokenAlice.signature
|
||||
);
|
||||
|
||||
// Decrypt the balance
|
||||
const balanceAlice = this.instances.alice.decrypt(
|
||||
this.contractAddress,
|
||||
encryptedBalanceAlice
|
||||
);
|
||||
|
||||
expect(balanceAlice).to.equal(10000 - 1337);
|
||||
|
||||
const bobErc20 = this.erc20.connect(this.signers.bob);
|
||||
|
||||
const tokenBob = this.instances.bob.getTokenSignature(
|
||||
this.contractAddress
|
||||
)!;
|
||||
|
||||
const encryptedBalanceBob = await bobErc20.balanceOf(
|
||||
tokenBob.publicKey,
|
||||
tokenBob.signature
|
||||
);
|
||||
|
||||
// Decrypt the balance
|
||||
const balanceBob = this.instances.bob.decrypt(
|
||||
this.contractAddress,
|
||||
encryptedBalanceBob
|
||||
);
|
||||
|
||||
expect(balanceBob).to.equal(1337);
|
||||
});
|
||||
});
|
||||
});
|
||||
61
test/instance.ts
Normal file
61
test/instance.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { FhevmInstances, Signers } from "./types";
|
||||
import { Signer } from "ethers";
|
||||
import fhevmjs, { FhevmInstance } from "fhevmjs";
|
||||
import { ethers as hethers } from "hardhat";
|
||||
|
||||
let publicKey: string;
|
||||
let chainId: number;
|
||||
|
||||
export const createInstances = async (
|
||||
contractAddress: string,
|
||||
ethers: typeof hethers,
|
||||
accounts: Signers
|
||||
): Promise<FhevmInstances> => {
|
||||
if (!publicKey || !chainId) {
|
||||
// 1. Get chain id
|
||||
const provider = ethers.provider;
|
||||
|
||||
const network = await provider.getNetwork();
|
||||
chainId = +network.chainId.toString(); // Need to be a number
|
||||
|
||||
// Get blockchain public key
|
||||
publicKey = await provider.call({
|
||||
to: "0x0000000000000000000000000000000000000044",
|
||||
});
|
||||
}
|
||||
|
||||
// Create instance
|
||||
const instances: FhevmInstances = {} as FhevmInstances;
|
||||
await Promise.all(
|
||||
Object.keys(accounts).map(async (k) => {
|
||||
const instance = await fhevmjs.createInstance({ chainId, publicKey });
|
||||
await generateToken(
|
||||
contractAddress,
|
||||
accounts[k as keyof Signers],
|
||||
instance
|
||||
);
|
||||
instances[k as keyof FhevmInstances] = instance;
|
||||
})
|
||||
);
|
||||
|
||||
return instances;
|
||||
};
|
||||
|
||||
const generateToken = async (
|
||||
contractAddress: string,
|
||||
signer: Signer,
|
||||
instance: FhevmInstance
|
||||
) => {
|
||||
// Generate token to decrypt
|
||||
const generatedToken = instance.generateToken({
|
||||
verifyingContract: contractAddress,
|
||||
});
|
||||
|
||||
// Sign the public key
|
||||
const signature = await signer.signTypedData(
|
||||
generatedToken.token.domain,
|
||||
{ Reencrypt: generatedToken.token.types.Reencrypt }, // Need to remove EIP712Domain from types
|
||||
generatedToken.token.message
|
||||
);
|
||||
instance.setTokenSignature(contractAddress, signature);
|
||||
};
|
||||
26
test/types.ts
Normal file
26
test/types.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import type { EncryptedERC20 } from "../types/contracts/EncryptedERC20";
|
||||
import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/dist/src/signer-with-address";
|
||||
import type { FhevmInstance } from "fhevmjs";
|
||||
|
||||
declare module "mocha" {
|
||||
export interface Context {
|
||||
signers: Signers;
|
||||
contractAddress: string;
|
||||
instances: FhevmInstances;
|
||||
erc20: EncryptedERC20;
|
||||
}
|
||||
}
|
||||
|
||||
export interface Signers {
|
||||
alice: SignerWithAddress;
|
||||
bob: SignerWithAddress;
|
||||
carol: SignerWithAddress;
|
||||
dave: SignerWithAddress;
|
||||
}
|
||||
|
||||
export interface FhevmInstances {
|
||||
alice: FhevmInstance;
|
||||
bob: FhevmInstance;
|
||||
carol: FhevmInstance;
|
||||
dave: FhevmInstance;
|
||||
}
|
||||
@@ -1,11 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"lib": ["es2020"],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": true,
|
||||
"removeComments": true,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
"target": "es2020"
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"files": ["./hardhat.config.ts"],
|
||||
"include": ["src/**/*", "tasks/**/*", "test/**/*", "deploy/**/*", "types/"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user