diff --git a/packages/fhenix-hardhat-plugin/test/fixture-projects/hardhat-project/hardhat.config.ts b/packages/fhenix-hardhat-plugin/test/fixture-projects/hardhat-project/hardhat.config.ts index 54ec3e4..a474697 100644 --- a/packages/fhenix-hardhat-plugin/test/fixture-projects/hardhat-project/hardhat.config.ts +++ b/packages/fhenix-hardhat-plugin/test/fixture-projects/hardhat-project/hardhat.config.ts @@ -1,5 +1,6 @@ // We load the plugin here. import { HardhatUserConfig } from "hardhat/types"; +import "@nomicfoundation/hardhat-ethers"; import "../../../src/index"; diff --git a/packages/fhenix-hardhat-plugin/test/fixture-projects/localfhenix/hardhat.config.ts b/packages/fhenix-hardhat-plugin/test/fixture-projects/localfhenix/hardhat.config.ts index ad79d96..5a450ff 100644 --- a/packages/fhenix-hardhat-plugin/test/fixture-projects/localfhenix/hardhat.config.ts +++ b/packages/fhenix-hardhat-plugin/test/fixture-projects/localfhenix/hardhat.config.ts @@ -1,5 +1,6 @@ // We load the plugin here. import { HardhatUserConfig } from "hardhat/types"; +import "@nomicfoundation/hardhat-ethers"; import "../../../src/index"; @@ -9,6 +10,15 @@ const config: HardhatUserConfig = { networks: { localfhenix: { url: "http://localhost:8545", + accounts: { + mnemonic: + "demand hotel mass rally sphere tiger measure sick spoon evoke fashion comfort", + path: "m/44'/60'/0'/0", + initialIndex: 0, + count: 20, + accountsBalance: "10000000000000000000", + passphrase: "", + }, }, }, paths: { diff --git a/packages/fhenix-hardhat-plugin/test/mocks.ts b/packages/fhenix-hardhat-plugin/test/mocks.ts new file mode 100644 index 0000000..b481a94 --- /dev/null +++ b/packages/fhenix-hardhat-plugin/test/mocks.ts @@ -0,0 +1,92 @@ +import { ethers, AbiCoder } from "ethers"; +import { AbstractProvider, AbstractSigner } from "fhenixjs"; + +export const getNetworkPublicKeySig = "0x1b1b484e"; // cast sig "getNetworkPublicKey(int32)" + +const MockMnemonics = [ + "grant rice replace explain federal release fix clever romance raise often wild taxi quarter soccer fiber love must tape steak together observe swap guitar", // account a + "jelly shadow frog dirt dragon use armed praise universe win jungle close inmate rain oil canvas beauty pioneer chef soccer icon dizzy thunder meadow", // account b + "chair love bleak wonder skirt permit say assist aunt credit roast size obtain minute throw sand usual age smart exact enough room shadow charge", // account c +]; +export const BobWallet = ethers.Wallet.fromPhrase(MockMnemonics[1]); +export const AdaWallet = ethers.Wallet.fromPhrase(MockMnemonics[2]); + +export const fromHexString = (hexString: string): Uint8Array => { + const arr = hexString.replace(/^(0x)/, "").match(/.{1,2}/g); + if (!arr) return new Uint8Array(); + return Uint8Array.from(arr.map((byte) => parseInt(byte, 16))); +}; + +export class MockSigner implements AbstractSigner { + wallet: ethers.HDNodeWallet; + + constructor(wallet: ethers.HDNodeWallet) { + this.wallet = wallet; + } + + signTypedData = async (domain: any, types: any, value: any): Promise => { + return await this.wallet.signTypedData(domain, types, value); + }; + + getAddress = async (): Promise => { + return this.wallet.getAddress(); + }; +} + +export class MockProvider implements AbstractProvider { + publicKey: string; + wallet: ethers.HDNodeWallet; + chainId: string; + + constructor(pk: string, wallet?: ethers.HDNodeWallet, chainId?: string) { + this.publicKey = pk; + this.wallet = wallet ?? ethers.Wallet.fromPhrase(MockMnemonics[0]); + this.chainId = chainId || "0x10"; + } + + async getChainId(): Promise { + return `${this.chainId}`; + } + + async call(tx: { to: string; data: string }): Promise { + if (tx.data.startsWith(getNetworkPublicKeySig)) { + // Simulate an eth_call operation + if (typeof this.publicKey === "string") { + const abiCoder = new AbiCoder(); + const buff = fromHexString(this.publicKey); + return abiCoder.encode(["bytes"], [buff]); + } + return this.publicKey; + } + + throw new Error( + `MockProvider :: call :: not-implemented for fn: ${JSON.stringify( + tx, + undefined, + 2, + )}`, + ); + } + + async send(method: string, params: unknown[] | undefined): Promise { + if (method === "eth_chainId") { + return this.chainId; + } + + if (method === "eth_call") { + const { to, data } = (params?.[0] ?? { + to: "undefined", + data: "undefined", + }) as { to: string; data: string }; + return this.call({ to, data }); + } + + throw new Error( + `MockProvider :: send :: Method not implemented: ${method}`, + ); + } + + async getSigner(): Promise { + return new MockSigner(this.wallet); + } +} diff --git a/packages/fhenix-hardhat-plugin/test/project.test.ts b/packages/fhenix-hardhat-plugin/test/project.test.ts index a2d1750..3a32f22 100644 --- a/packages/fhenix-hardhat-plugin/test/project.test.ts +++ b/packages/fhenix-hardhat-plugin/test/project.test.ts @@ -8,7 +8,10 @@ import { import { FhenixHardhatRuntimeEnvironment } from "../src/FhenixHardhatRuntimeEnvironment"; import { useEnvironment } from "./helpers"; -import { Encryptable } from "fhenixjs"; +import { createTfhePublicKey, Encryptable } from "fhenixjs"; +import { BobWallet, MockProvider } from "./mocks"; + +const HARDHAT_NETWORK_ID = "31337"; describe("Test Fhenix Plugin", function () { describe("Test Runtime with default project", function () { @@ -36,8 +39,32 @@ describe("Test Fhenix Plugin", function () { it("checks that fhenixsdk is initialized in hre", function () { expect(this.hre.fhenixsdk != null).to.equal(true); }); - it("fhenixsdk can be initialized", function () {}); - it("fhenixsdk.initializeWithHHSigner utility function"); + it("fhenixsdk can be initialized", async function () { + const bobProvider = new MockProvider( + "0xPublicKeyMock", + BobWallet, + HARDHAT_NETWORK_ID, + ); + const bobSigner = await bobProvider.getSigner(); + + // Should initialize correctly, but fhe public key for hardhat not set + await this.hre.fhenixsdk.initialize({ + provider: bobProvider, + signer: bobSigner, + projects: ["TEST"], + }); + }); + it("fhenixsdk.initializeWithHHSigner utility function", async function () { + const [signer] = await this.hre.ethers.getSigners(); + await this.hre.fhenixsdk.initializeWithHHSigner({ + signer, + projects: ["TEST"], + }); + + // Should create a permit + const bobPermit = await this.hre.fhenixsdk.createPermit(); + expect(bobPermit).to.be.an("object"); + }); it("fhenixsdk encrypt", function () { const fakeEnc = this.hre.fhenixsdk.encrypt(Encryptable.uint8(5)); expect(fakeEnc).to.be.an("object"); @@ -45,7 +72,31 @@ describe("Test Fhenix Plugin", function () { expect(fakeEnc).to.have.property("securityZone"); expect(fakeEnc.securityZone).to.be.equal(0); }); - it("fhenixsdk permit management"); + it("fhenixsdk permit management", async function () { + // const bobProvider = new MockProvider(createTfhePublicKey, BobWallet); + + const bobProvider = new MockProvider( + createTfhePublicKey(), + BobWallet, + HARDHAT_NETWORK_ID, + ); + const bobSigner = await bobProvider.getSigner(); + + // Should initialize correctly, but fhe public key for hardhat not set + await this.hre.fhenixsdk.initialize({ + provider: bobProvider, + signer: bobSigner, + projects: ["TEST"], + }); + + // Should create a permit + const bobPermit = await this.hre.fhenixsdk.createPermit(); + expect(bobPermit).to.be.an("object"); + + // Active hash should match + const activeHash = this.hre.fhenixsdk.getPermit()?.data?.getHash(); + expect(bobPermit.getHash()).to.be.equal(activeHash); + }); }); describe("Hardhat Runtime Environment extension for localfhenix", function () { @@ -59,6 +110,34 @@ describe("Test Fhenix Plugin", function () { it("checks that fhenixjs methods get injected on localfhenix", function () { assert.equal(this.hre.fhenixjs.sayHello(), "hello"); }); + + // V2 + + it("checks that fhenixsdk is initialized in hre", function () { + expect(this.hre.fhenixsdk != null).to.equal(true); + }); + it("fhenixsdk can be initialized", async function () { + const bobProvider = new MockProvider(createTfhePublicKey(), BobWallet); + const bobSigner = await bobProvider.getSigner(); + + // Should initialize correctly, but fhe public key for hardhat not set + await this.hre.fhenixsdk.initialize({ + provider: bobProvider, + signer: bobSigner, + projects: ["TEST"], + }); + }); + it("fhenixsdk.initializeWithHHSigner utility function", async function () { + const [signer] = await this.hre.ethers.getSigners(); + await this.hre.fhenixsdk.initializeWithHHSigner({ + signer, + projects: ["TEST"], + }); + + // Should create a permit + const bobPermit = await this.hre.fhenixsdk.createPermit(); + expect(bobPermit).to.be.an("object"); + }); }); describe("Test Faucet command", async function () {