mirror of
https://github.com/tornadocash/tornado-nova
synced 2024-02-02 14:53:56 +01:00
134 lines
4.7 KiB
JavaScript
134 lines
4.7 KiB
JavaScript
/* global ethers */
|
|
const { expect, should } = require('chai')
|
|
should()
|
|
const { BigNumber } = ethers
|
|
|
|
const {
|
|
poseidonHash2,
|
|
toFixedHex,
|
|
takeSnapshot,
|
|
revertSnapshot,
|
|
packEncryptedMessage,
|
|
unpackEncryptedMessage,
|
|
} = require('../src/utils')
|
|
const Utxo = require('../src/utxo')
|
|
|
|
const MERKLE_TREE_HEIGHT = 5
|
|
const MerkleTree = require('fixed-merkle-tree')
|
|
|
|
const { deposit, transact, withdraw, merge } = require('../src/index')
|
|
const Keypair = require('../src/keypair')
|
|
|
|
describe('TornadoPool', () => {
|
|
let snapshotId, tornadoPool
|
|
|
|
/* prettier-ignore */
|
|
before(async function () {
|
|
const Verifier2 = await ethers.getContractFactory('Verifier2')
|
|
const verifier2 = await Verifier2.deploy()
|
|
await verifier2.deployed()
|
|
|
|
const Verifier16 = await ethers.getContractFactory('Verifier16')
|
|
const verifier16 = await Verifier16.deploy()
|
|
await verifier16.deployed()
|
|
|
|
const tree = new MerkleTree(MERKLE_TREE_HEIGHT, [], { hashFunction: poseidonHash2 })
|
|
const root = await tree.root()
|
|
|
|
const Pool = await ethers.getContractFactory('TornadoPool')
|
|
tornadoPool = await Pool.deploy(verifier2.address, verifier16.address, toFixedHex(root))
|
|
|
|
snapshotId = await takeSnapshot()
|
|
})
|
|
|
|
it('encryp -> pack -> unpack -> decrypt should work', () => {
|
|
const blinding = 3
|
|
const amount = 5
|
|
const keypair = new Keypair()
|
|
|
|
const cyphertext = keypair.encrypt({ blinding, amount })
|
|
|
|
const packedMessage = packEncryptedMessage(cyphertext)
|
|
|
|
const unpackedMessage = unpackEncryptedMessage(packedMessage)
|
|
|
|
const result = keypair.decrypt(unpackedMessage)
|
|
|
|
expect(result.blinding).to.be.equal(blinding)
|
|
expect(result.amount).to.be.equal(amount)
|
|
})
|
|
|
|
it('should deposit, transact and withdraw', async function () {
|
|
/// deposit phase
|
|
// Alice deposits into tornado pool
|
|
const amount = BigNumber.from('10000000')
|
|
const alicePrivateKey = ethers.Wallet.createRandom().privateKey // the private key we use for snarks and encryption, not for transactions
|
|
const aliceKeypair = new Keypair(alicePrivateKey)
|
|
|
|
const depositInput = new Utxo({ amount, keypair: aliceKeypair })
|
|
await deposit({ tornadoPool, utxo: depositInput })
|
|
|
|
// getting account data from chain to verify that Alice has an Input to spend now
|
|
const filter = tornadoPool.filters.NewCommitment()
|
|
let events = await tornadoPool.queryFilter(filter)
|
|
let unpackedMessage = unpackEncryptedMessage(events[0].args.encryptedOutput)
|
|
let decryptedMessage = aliceKeypair.decrypt(unpackedMessage)
|
|
let aliceInputIndex = events[0].args.index
|
|
expect(decryptedMessage.amount).to.be.equal(amount)
|
|
expect(decryptedMessage.blinding).to.be.equal(depositInput.blinding)
|
|
|
|
/// transact phase.
|
|
// Bob gives Alice address to send some eth inside pool
|
|
const bobPrivateKey = ethers.Wallet.createRandom().privateKey
|
|
const bobKeypair = new Keypair(bobPrivateKey)
|
|
const bobAddress = bobKeypair.address()
|
|
|
|
// but alice does not have Bob's privkey so let's build keypair without it
|
|
const bobKeypairForEncryption = Keypair.fromString(bobAddress)
|
|
|
|
// let's build input for the shielded transaction
|
|
const aliceInput = new Utxo({
|
|
amount,
|
|
blinding: depositInput.blinding,
|
|
index: aliceInputIndex,
|
|
keypair: aliceKeypair,
|
|
})
|
|
const bobInput = new Utxo({ amount, keypair: bobKeypairForEncryption })
|
|
|
|
await transact({ tornadoPool, input: aliceInput, output: bobInput })
|
|
|
|
// getting account data from chain to verify that Bob has an Input to spend now
|
|
const fromBlock = await ethers.provider.getBlock()
|
|
events = await tornadoPool.queryFilter(filter, fromBlock.number)
|
|
const bobInputIndex = events[0].args.index
|
|
unpackedMessage = unpackEncryptedMessage(events[0].args.encryptedOutput)
|
|
decryptedMessage = bobKeypair.decrypt(unpackedMessage)
|
|
expect(decryptedMessage.amount).to.be.equal(amount)
|
|
expect(decryptedMessage.blinding).to.be.equal(bobInput.blinding)
|
|
|
|
/// withdraw phase
|
|
// now Bob wants to exit the pool using a half of its funds
|
|
const bobInputForWithdraw = new Utxo({
|
|
amount,
|
|
blinding: bobInput.blinding,
|
|
index: bobInputIndex,
|
|
keypair: bobKeypair,
|
|
})
|
|
const bobChange = new Utxo({ amount: amount.div(2), keypair: bobKeypair })
|
|
const recipient = '0xc2Ba33d4c0d2A92fb4f1a07C273c5d21E688Eb48'
|
|
await withdraw({ tornadoPool, input: bobInputForWithdraw, change: bobChange, recipient })
|
|
|
|
const bal = await ethers.provider.getBalance(recipient)
|
|
expect(bal).to.be.gt(0)
|
|
})
|
|
|
|
it('should work with 16 inputs', async function () {
|
|
const utxo1 = await merge({ tornadoPool })
|
|
})
|
|
|
|
afterEach(async () => {
|
|
await revertSnapshot(snapshotId)
|
|
snapshotId = await takeSnapshot()
|
|
})
|
|
})
|