import pkg from 'hardhat'; const { ethers } = pkg; const { provider } = ethers; import { fileURLToPath } from 'url'; import { dirname } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); import { newBarretenbergApiSync } from '@aztec/bb.js/dest/index.js'; import { BigNumber } from "ethers"; import { expect } from "chai"; import path from 'path'; import { execSync } from 'child_process'; import { MerkleTree } from "../utils/MerkleTree.mjs"; import { generateUTXO, generateTestTransaction, generateTestPublish, generateDataToml, randomBytesFr, generateTreeProof } from '../utils/test_helpers.mjs'; import fs from "fs" describe('It compiles circuit.', () => { let verifierContract; before(async () => { execSync(`nargo check`) execSync(`nargo compile main`) if (!fs.existsSync('./contracts/plonk_vk.sol')) { execSync(`nargo codegen-verifier && cp ./contract/plonk_vk.sol ./contracts/plonk_vk.sol`) } }); before('Deploy contract', async () => { console.log('Deploying verifier contract...') execSync('npx hardhat compile', { cwd: path.join(__dirname, '../contracts') }); const Verifier = await ethers.getContractFactory('UltraVerifier'); verifierContract = await Verifier.deploy(); const verifierAddr = await verifierContract.deployed(); console.log(`Verifier deployed to ${verifierAddr.address}`); }); }); let signers; let recipient, recipient_new; const api = await newBarretenbergApiSync(); let trees = { utxo_tree: new MerkleTree(4, api), tx_tree: new MerkleTree(4, api), batch_tree: new MerkleTree(5, api), historic_tree: new MerkleTree(5, api), utxoTreeOld: new MerkleTree(4, api), txTreeOld: new MerkleTree(4, api), batchLeaf: "", newHistoricRoot: "" } let utxoIn = [] let utxoOut = [] let treeProof = [] let data = generateDataToml("0", "0", api) let amountPublic = { amountIn: BigInt(0), amountOut: BigInt(0) } before(async () => { signers = await ethers.getSigners(); recipient = signers[1].address; recipient = `0x`+ recipient.slice(2).padStart(64, "0") recipient_new = signers[2].address; recipient_new = `0x` + recipient_new.slice(2).padStart(64, "0") }); describe("Private Transfer works with Solidity verifier", () => { let Verifier, verifierContract, TechnicalPreview, technicalPreviewContract; before("Set up Verifier contract", async () => { TechnicalPreview = await ethers.getContractFactory("TechnicalPreview"); Verifier = await ethers.getContractFactory("UltraVerifier"); verifierContract = await Verifier.deploy(); technicalPreviewContract = await TechnicalPreview.deploy(verifierContract.address); }) it("Deposit works using Solidity verifier", async () => { console.log("** Generating Test Batch **") let batchSize0 = 10 let secret0 = [] for (let s = 0; s < batchSize0; s++) { secret0.push(randomBytesFr(32)) } let amountsOutUTXO = new Array(10).fill(BigInt(1e17)) utxoOut = generateUTXO(batchSize0, amountsOutUTXO, secret0, api); amountPublic.amountIn = BigInt(1e18) generateTestTransaction(utxoIn, utxoOut, trees, treeProof, amountPublic, data, recipient, api) console.log("** Generating Transaction Proof #1 (Deposit) **") generateTestPublish(trees, data, api) execSync(`nargo prove main`) let proof = fs.readFileSync('./proofs/main.proof').toString() proof = `0x`+ proof let amount_public_in, amount_public_out, commitment_out, new_root, nullifier_hashes, old_root, oracle, tx_in; eval(fs.readFileSync('./Verifier.toml').toString()); let public_inputs = [ tx_in, amount_public_in, amount_public_out, commitment_out, recipient, oracle, old_root, new_root, nullifier_hashes ] const before = await provider.getBalance(signers[1].address); const technicalPreviewSigner = technicalPreviewContract.connect(signers[1]); await technicalPreviewSigner.publish(proof, public_inputs, {value: amount_public_in, gasPrice: '0'}); const after = await provider.getBalance(signers[1].address); expect(before.sub(after)).to.equal(BigNumber.from(amount_public_in)); utxoIn = utxoOut; }); it("Private transfer works using Solidity verifier", async () => { console.log("** Generating Transaction Proof #2 (Withdraw/Transfer) **") let amountsOutUTXO = new Array(5).fill(BigInt(1e17)) treeProof = generateTreeProof(utxoIn, trees, api) let batchSize1 = 5 let secret1 = [] for (let s = 0; s < batchSize1; s++) { secret1.push(randomBytesFr(32)) } utxoOut = generateUTXO(batchSize1, amountsOutUTXO, secret1, api); amountPublic.amountIn = BigInt(0); amountPublic.amountOut = BigInt(5e17); let oldRoot = data.old_root let newRoot = data.new_root data = generateDataToml(oldRoot, newRoot, api) const before = await provider.getBalance(signers[2].address); generateTestTransaction(utxoIn, utxoOut, trees, treeProof, amountPublic, data, recipient_new, api) generateTestPublish(trees, data, api) execSync(`nargo prove main`) let proof = fs.readFileSync('./proofs/main.proof').toString() proof = `0x`+ proof let amount_public_in, amount_public_out, commitment_out, new_root, nullifier_hashes, old_root, oracle, tx_in; eval(fs.readFileSync('./Verifier.toml').toString()); let public_inputs = [ tx_in, amount_public_in, amount_public_out, commitment_out, recipient_new, oracle, old_root, new_root, nullifier_hashes ] await technicalPreviewContract.publish(proof, public_inputs) const after = await provider.getBalance(signers[2].address); expect(after.sub(before)).to.equal(BigNumber.from(amount_public_out)); }); });