diff --git a/contracts/Miksi.sol b/contracts/Miksi.sol index 72c6f27..7263488 100644 --- a/contracts/Miksi.sol +++ b/contracts/Miksi.sol @@ -14,6 +14,7 @@ contract Miksi { struct Deposit { uint256 coinCode; uint256 amount; + bool used; } function deposit( @@ -21,7 +22,7 @@ contract Miksi { // uint256 amount, uint256 commitment ) public payable { - deposits[commitment] = Deposit(coinCode, msg.value); + deposits[commitment] = Deposit(coinCode, msg.value, false); } function getDeposit( @@ -49,6 +50,8 @@ contract Miksi { ]; require(verifier.verifyProof(a, b, c, input), "zkProof withdraw could not be verified"); // zk verification passed, proceed with the withdraw + require(!deposits[commitment].used, "deposit already withdrawed"); + deposits[commitment].used = true; _address.send(deposits[commitment].amount); // _address.call.value(deposits[commitment].amount).gas(20317)(); diff --git a/package-lock.json b/package-lock.json index 1d8a818..d163696 100644 --- a/package-lock.json +++ b/package-lock.json @@ -555,7 +555,18 @@ "resolved": "https://registry.npmjs.org/circom_runtime/-/circom_runtime-0.0.5.tgz", "integrity": "sha512-WEZHnRO1AJIDI2w1yX6rq4G1/MMKnExT3qirjBQR7x43i9Ww3E/wusBHTbXWLb8aYyxsBU07LGy0YXPywPGYvA==", "requires": { + "ffjavascript": "0.1.0", "fnv-plus": "^1.3.1" + }, + "dependencies": { + "ffjavascript": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz", + "integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==", + "requires": { + "big-integer": "^1.6.48" + } + } } }, "circomlib": { @@ -566,6 +577,7 @@ "blake-hash": "^1.1.0", "blake2b": "^2.1.3", "circom": "0.5.9", + "ffjavascript": "0.1.0", "web3": "^1.2.6" }, "dependencies": { @@ -578,12 +590,21 @@ "circom_runtime": "0.0.5", "fastfile": "0.0.1", "ffiasm": "0.0.2", + "ffjavascript": "0.1.0", "ffwasm": "0.0.7", "fnv-plus": "^1.3.1", "r1csfile": "0.0.5", "tmp-promise": "^2.0.2", "wasmbuilder": "0.0.10" } + }, + "ffjavascript": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz", + "integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==", + "requires": { + "big-integer": "^1.6.48" + } } } }, @@ -1797,6 +1818,12 @@ "p-locate": "^4.1.0" } }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -2360,7 +2387,18 @@ "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.5.tgz", "integrity": "sha512-B+BdKPb/WUTp4N/3X4d1Spgx9Ojx5tFVejGZRJxpTtzq34mC8Vi/czWfiPj85V8kud31lCfYcZ16z7+czvM0Sw==", "requires": { - "fastfile": "0.0.1" + "fastfile": "0.0.1", + "ffjavascript": "0.1.0" + }, + "dependencies": { + "ffjavascript": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ffjavascript/-/ffjavascript-0.1.0.tgz", + "integrity": "sha512-dmKlUasSfvUcxBm8nCSKl2x7EFJsXA7OVP8XLFA03T2+6mAc3IiVLC2ambEVOcMOhyhl0vJfVZjM9f9d38D1rw==", + "requires": { + "big-integer": "^1.6.48" + } + } } }, "ramda": { @@ -3101,6 +3139,16 @@ "original-require": "1.0.1" } }, + "truffle-assertions": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/truffle-assertions/-/truffle-assertions-0.9.2.tgz", + "integrity": "sha512-9g2RhaxU2F8DeWhqoGQvL/bV8QVoSnQ6PY+ZPvYRP5eF7+/8LExb4mjLx/FeliLTjc3Tv1SABG05Gu5qQ/ErmA==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "lodash.isequal": "^4.5.0" + } + }, "ts-node": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", diff --git a/package.json b/package.json index 09bdfca..8763e5c 100644 --- a/package.json +++ b/package.json @@ -15,20 +15,21 @@ "circomlib": "0.2.2" }, "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.6", "@types/node": "^12.12.0", + "chai": "^4.2.0", "circom": "0.5.10", "eslint-plugin-mocha": "^6.1.0", - "snarkjs": "^0.1.31", "ffjavascript": "0.1.3", - "@types/chai": "^4.1.7", - "@types/mocha": "^5.2.6", - "chai": "^4.2.0", "mocha": "^5.2.0", "mocha-steps": "^1.3.0", + "snarkjs": "^0.1.31", + "truffle": "^5.0.0-beta.0", + "truffle-assertions": "^0.9.2", "ts-node": "^7.0.1", "tslint": "^5.18.0", "typescript": "^3.5.3", - "truffle": "^5.0.0-beta.0", "web3": "^1.0.0-beta.30" } } diff --git a/test/contracts/miksi.test.ts b/test/contracts/miksi.test.ts index 18e5057..85bcd8f 100644 --- a/test/contracts/miksi.test.ts +++ b/test/contracts/miksi.test.ts @@ -3,6 +3,7 @@ const Miksi = artifacts.require("../../contracts/Miksi.sol"); const chai = require("chai"); const expect = chai.expect; +const truffleAssert = require('truffle-assertions'); const fs = require("fs"); const { groth } = require('snarkjs'); @@ -49,7 +50,7 @@ contract("miksi", (accounts) => { balance_wei = await web3.eth.getBalance(addr1); console.log("Balance at " + addr1, web3.utils.fromWei(balance_wei, 'ether')); - expect(balance_wei).to.be.equal('99499141300000000000'); + expect(balance_wei).to.be.equal('99499107180000000000'); // getDeposit data const res = await insMiksi.getDeposit(commitment); @@ -80,7 +81,7 @@ contract("miksi", (accounts) => { // withdraw console.log("Withdraw of " + ethAmount + " ETH to " + addr2); - const resW = await insMiksi.withdraw( + let resW = await insMiksi.withdraw( commitment, addr2, [proof.pi_a[0].toString(), proof.pi_a[1].toString()], @@ -95,5 +96,23 @@ contract("miksi", (accounts) => { balance_wei = await web3.eth.getBalance(addr2); console.log("Balance at " + addr2, web3.utils.fromWei(balance_wei, 'ether')); expect(balance_wei).to.be.equal('100500000000000000000'); + + console.log("Try to reuse the zkproof and expect revert"); + await truffleAssert.fails( + insMiksi.withdraw( + commitment, + addr2, + [proof.pi_a[0].toString(), proof.pi_a[1].toString()], + [ + [proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString()], + [proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString()] + ], + [proof.pi_c[0].toString(), proof.pi_c[1].toString()] + ), + truffleAssert.ErrorType.REVERT, + "deposit already withdrawed" + ); + balance_wei = await web3.eth.getBalance(addr2); + expect(balance_wei).to.be.equal('100500000000000000000'); }); });