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
 45  before(async () => {
 46
 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  });
142
143  it("Calculate witness and generate the zkProof", async () => {
144    const resC = await tree.find(commitment);
145    assert(resC.found);
146    let siblings = resC.siblings;
147    while (siblings.length < nLevels) {
148        siblings.push("0");
149    };
150    // console.log("siblings", siblings);
151
152    // calculate witness
153    const wasm = await fs.promises.readFile("./build/withdraw.wasm");
154    const input = unstringifyBigInts({
155      "coinCode": coinCode,
156      "amount": amount,
157      "secret": secret,
158      "nullifier": nullifier,
159      "siblings": siblings,
160      "root": tree.root,
161      "address": addr2
162    });
163    const options = {};
164    // console.log("Calculate witness");
165    const wc = await WitnessCalculatorBuilder(wasm, options);
166    const w = await wc.calculateWitness(input);
167    const witness = unstringifyBigInts(stringifyBigInts(w));
168
169    // generate zkproof of commitment using snarkjs (as is a test)
170    const provingKey = unstringifyBigInts(JSON.parse(fs.readFileSync("./build/withdraw-proving_key.json", "utf8")));
171
172    // console.log("Generate zkSNARK proof");
173    const res = groth.genProof(provingKey, witness);
174    proof = res.proof;
175    publicSignals = res.publicSignals;
176  });
177
178  it("Try to use the zkProof with another address and get revert", async () => {
179    // console.log("Try to reuse the zkproof and expect revert");
180    await truffleAssert.fails(
181      insMiksi.withdraw(
182        addr1,
183        nullifier,
184        [proof.pi_a[0].toString(), proof.pi_a[1].toString()],
185        [
186          [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()],
187          [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()]
188        ],
189        [proof.pi_c[0].toString(), proof.pi_c[1].toString()]
190      ),
191      truffleAssert.ErrorType.REVERT,
192      "zkProof withdraw could not be verified"
193    );
194  });
195
196  it("Withdraw 1 ETH with the zkProof", async () => {
197    // withdraw
198    // console.log("Withdraw of " + ethAmount + " ETH to " + addr2);
199    let resW = await insMiksi.withdraw(
200      addr2,
201      nullifier,
202      [proof.pi_a[0].toString(), proof.pi_a[1].toString()],
203      [
204        [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()],
205        [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()]
206      ],
207      [proof.pi_c[0].toString(), proof.pi_c[1].toString()]
208    );
209    // console.log("resW", resW);
210
211    balance_wei = await web3.eth.getBalance(addr2);
212    // console.log("Balance at " + addr2, web3.utils.fromWei(balance_wei, 'ether'));
213    expect(balance_wei).to.be.equal('101000000000000000000');
214  });
215
216  it("Try to reuse the zkProof and get revert", async () => {
217    // console.log("Try to reuse the zkproof and expect revert");
218    await truffleAssert.fails(
219      insMiksi.withdraw(
220        addr2,
221        nullifier,
222        [proof.pi_a[0].toString(), proof.pi_a[1].toString()],
223        [
224          [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()],
225          [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()]
226        ],
227        [proof.pi_c[0].toString(), proof.pi_c[1].toString()]
228      ),
229      truffleAssert.ErrorType.REVERT,
230      "nullifier already used"
231    );
232    balance_wei = await web3.eth.getBalance(addr2);
233    expect(balance_wei).to.be.equal('101000000000000000000');
234  });
235});