arnaucube
arnaucube/miksi-corePublic Self-hosted repository
miksi-core/test/contracts/miksi.test.ts
test/contracts/miksi.test.tsRaw
  1const DepositVerifier = artifacts.require("../../contracts/DepositVerifier");
  2const WithdrawVerifier = artifacts.require("../../contracts/WithdrawVerifier");
  3const Miksi = artifacts.require("../../contracts/Miksi.sol");
  4
  5const chai = require("chai");
  6const expect = chai.expect;
  7const truffleAssert = require('truffle-assertions');
  8
  9const fs = require("fs");
 10const { groth } = require('snarkjs');
 11const { stringifyBigInts, unstringifyBigInts } = require('ffjavascript').utils;
 12const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder;
 13const circomlib = require("circomlib");
 14const smt = require("circomlib").smt;
 15
 16contract("miksi", (accounts) => {
 17
 18
 19  const {
 20    0: owner,
 21    1: addr1, // used for the deposit
 22    2: addr2, // used for the withdraw
 23    3: addr3,
 24  } = accounts;
 25
 26  let insVerifier;
 27  let insMiksi;
 28
 29    const nLevels = 5;
 30    const secret = "1234567890";
 31
 32    const coinCode = "0"; // refearing to ETH
 33    const ethAmount = '1';
 34    const amount = web3.utils.toWei(ethAmount, 'ether');
 35    const nullifier = "567891234";
 36    let tree;
 37    let siblingsOld;
 38    let siblingsNew;
 39    let rootOld;
 40    let rootNew;
 41    let commitment;
 42    let proof;
 43    let publicSignals;
 44    let commitmentsArray;
 45
 46  before(async () => {
 47    insDepositVerifier = await DepositVerifier.new();
 48    insWithdrawVerifier = await WithdrawVerifier.new();
 49    insMiksi = await Miksi.new(insDepositVerifier.address, insWithdrawVerifier.address);
 50  });
 51
 52  before(async() => {
 53    let balance_wei = await web3.eth.getBalance(addr1);
 54    // console.log("Balance at " + addr1, web3.utils.fromWei(balance_wei, 'ether'));
 55    expect(balance_wei).to.be.equal('100000000000000000000');
 56
 57    const poseidon = circomlib.poseidon.createHash(6, 8, 57);
 58    commitment = poseidon([coinCode, amount, secret, nullifier]).toString();
 59
 60    // deposit
 61    // add commitment into SMT
 62    tree = await smt.newMemEmptyTrie();
 63    await tree.insert(1, 0);
 64
 65    rootOld = tree.root;
 66    const resC = await tree.find(commitment);
 67    assert(!resC.found);
 68    siblingsOld = resC.siblings;
 69    while (siblingsOld.length < nLevels) {
 70        siblingsOld.push("0");
 71    };
 72
 73    await tree.insert(commitment, 0);
 74    rootNew = tree.root;
 75
 76    expect(rootOld.toString()).to.be.equal('11499909227292257605992378629333104385616480982267969744564817844870636870870');
 77    expect(rootNew.toString()).to.be.equal('9328869343897770565751281504295758914771207504252217956739346620422361279598');
 78  });
 79
 80  it("Make the deposit", async () => {
 81    const resC = await tree.find(commitment);
 82    assert(resC.found);
 83    siblingsNew = resC.siblings;
 84    while (siblingsNew.length < nLevels) {
 85        siblingsNew.push("0");
 86    };
 87
 88    // calculate witness
 89    const wasm = await fs.promises.readFile("./build/deposit.wasm");
 90    const input = unstringifyBigInts({
 91      "coinCode": coinCode,
 92      "amount": amount,
 93      "secret": secret,
 94      "nullifier": nullifier,
 95      "siblingsOld": siblingsOld,
 96      "siblingsNew": siblingsNew,
 97      "rootOld": rootOld,
 98      "rootNew": rootNew,
 99      "commitment": commitment
100    });
101    const options = {};
102    // console.log("Calculate witness");
103    const wc = await WitnessCalculatorBuilder(wasm, options);
104    const w = await wc.calculateWitness(input);
105    const witness = unstringifyBigInts(stringifyBigInts(w));
106
107    // generate zkproof of commitment using snarkjs (as is a test)
108    const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync("./build/deposit-proving_key.json", "utf8")));
109
110    // console.log("Generate zkSNARK proof");
111    const res = groth.genProof(provingKey, witness);
112    proof = res.proof;
113    publicSignals = res.publicSignals;
114
115    const verificationKey = unstringifyBigInts(JSON.parse(fs.readFileSync("./build/deposit-verification_key.json", "utf8")));
116    let pubI = unstringifyBigInts([coinCode, amount, rootOld.toString(), rootNew.toString(), commitment]);
117    let validCheck = groth.isValid(verificationKey, proof, pubI);
118    assert(validCheck);
119    await insMiksi.deposit(
120      commitment,
121      tree.root.toString(),
122      [proof.pi_a[0].toString(), proof.pi_a[1].toString()],
123      [
124        [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()],
125        [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()]
126      ],
127      [proof.pi_c[0].toString(), proof.pi_c[1].toString()],
128      {from: addr1, value: amount}
129    );
130
131    balance_wei = await web3.eth.getBalance(addr1);
132    // console.log("Balance at " + addr1, web3.utils.fromWei(balance_wei, 'ether'));
133    // expect(balance_wei).to.be.equal('98993526980000000000');
134  });
135
136  it("Get the commitments data", async () => {
137    // getCommitments data
138    let res = await insMiksi.getCommitments();
139    expect(res[0][0].toString()).to.be.equal('189025084074544266465422070282645213792582195466360448472858620722286781863');
140    expect(res[1].toString()).to.be.equal('9328869343897770565751281504295758914771207504252217956739346620422361279598');
141    console.log(res[0]);
142    commitmentsArray = res[0];
143  });
144
145  it("Rebuild the tree from sc commitments", async () => {
146    let treeTmp = await smt.newMemEmptyTrie();
147    await treeTmp.insert(1, 0);
148    for (let i=0; i<commitmentsArray.length; i++) {
149      await treeTmp.insert(commitmentsArray[i], 0);
150    }
151    expect(treeTmp.root).to.be.equal(tree.root);
152  });
153
154  it("Calculate witness and generate the zkProof", async () => {
155    const resC = await tree.find(commitment);
156    assert(resC.found);
157    let siblings = resC.siblings;
158    while (siblings.length < nLevels) {
159        siblings.push("0");
160    };
161    // console.log("siblings", siblings);
162
163    // calculate witness
164    const wasm = await fs.promises.readFile("./build/withdraw.wasm");
165    const input = unstringifyBigInts({
166      "coinCode": coinCode,
167      "amount": amount,
168      "secret": secret,
169      "nullifier": nullifier,
170      "siblings": siblings,
171      "root": tree.root,
172      "address": addr2
173    });
174    const options = {};
175    // console.log("Calculate witness");
176    const wc = await WitnessCalculatorBuilder(wasm, options);
177    const w = await wc.calculateWitness(input);
178    const witness = unstringifyBigInts(stringifyBigInts(w));
179
180    // generate zkproof of commitment using snarkjs (as is a test)
181    const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync("./build/withdraw-proving_key.json", "utf8")));
182
183    // console.log("Generate zkSNARK proof");
184    const res = groth.genProof(provingKey, witness);
185    proof = res.proof;
186    publicSignals = res.publicSignals;
187  });
188
189  it("Try to use the zkProof with another address and get revert", async () => {
190    // console.log("Try to reuse the zkproof and expect revert");
191    await truffleAssert.fails(
192      insMiksi.withdraw(
193        addr1,
194        nullifier,
195        [proof.pi_a[0].toString(), proof.pi_a[1].toString()],
196        [
197          [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()],
198          [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()]
199        ],
200        [proof.pi_c[0].toString(), proof.pi_c[1].toString()]
201      ),
202      truffleAssert.ErrorType.REVERT,
203      "zkProof withdraw could not be verified"
204    );
205  });
206
207  it("Withdraw 1 ETH with the zkProof", async () => {
208    // withdraw
209    // console.log("Withdraw of " + ethAmount + " ETH to " + addr2);
210    let resW = await insMiksi.withdraw(
211      addr2,
212      nullifier,
213      [proof.pi_a[0].toString(), proof.pi_a[1].toString()],
214      [
215        [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()],
216        [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()]
217      ],
218      [proof.pi_c[0].toString(), proof.pi_c[1].toString()]
219    );
220    // console.log("resW", resW);
221
222    balance_wei = await web3.eth.getBalance(addr2);
223    // console.log("Balance at " + addr2, web3.utils.fromWei(balance_wei, 'ether'));
224    expect(balance_wei).to.be.equal('101000000000000000000');
225  });
226
227  it("Try to reuse the zkProof and get revert", async () => {
228    // console.log("Try to reuse the zkproof and expect revert");
229    await truffleAssert.fails(
230      insMiksi.withdraw(
231        addr2,
232        nullifier,
233        [proof.pi_a[0].toString(), proof.pi_a[1].toString()],
234        [
235          [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()],
236          [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()]
237        ],
238        [proof.pi_c[0].toString(), proof.pi_c[1].toString()]
239      ),
240      truffleAssert.ErrorType.REVERT,
241      "nullifier already used"
242    );
243    balance_wei = await web3.eth.getBalance(addr2);
244    expect(balance_wei).to.be.equal('101000000000000000000');
245  });
246});