@@ -3,8 +3,10 @@ import { ethers } from 'hardhat'
33import {
44 generateDeposit ,
55 generateProof ,
6+ packBackupData ,
67 randomBigInt ,
78 toSolidityInput ,
9+ unpackBackupData ,
810 verifyProof ,
911} from '../utils/PrivateBank.utils'
1012import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'
@@ -21,6 +23,7 @@ import {
2123} from '../utils/types.utils'
2224import { poseidon } from '@iden3/js-crypto'
2325import { FIELD_P } from '../utils/keccak.utils'
26+ import { decrypt , encrypt , generateEncryptionKey } from '../utils/aes256.utils'
2427
2528describe ( 'ETHPrivateBank' , function ( ) {
2629 const ZERO = '0x29319238daf40223d6021718c846ac2a0c0ef028ecc765972e999a8ac79662a8'
@@ -291,6 +294,77 @@ describe('ETHPrivateBank', function () {
291294 expect ( isSpent ) . to . be . true
292295 } )
293296
297+ it ( 'backup(): should backup note and emit event, be able to withdraw using the note' , async ( ) => {
298+ // generate deposit
299+ const deposit = generateDeposit ( )
300+
301+ // encrypt backup data
302+ const plainText = packBackupData ( deposit . secret , deposit . nullifier )
303+ const encryptionKey = generateEncryptionKey ( )
304+ const encryptedData = encrypt ( encryptionKey , plainText )
305+
306+ // setup tree
307+ const hashMiMCSponge = await getMiMCSpongeHasher ( )
308+ const tree = new FixedMerkleTree ( HEIGHT , [ ] , {
309+ hashFunction : hashMiMCSponge ,
310+ zeroElement : ZERO ,
311+ } )
312+ tree . insert ( deposit . commitment )
313+
314+ // deposit to contract
315+ await expect ( privateBank . connect ( sender ) . deposit ( deposit . commitment , { value : DEPOSIT_AMOUNT } ) )
316+ . to . not . be . reverted
317+
318+ // backup note
319+ const tx = await privateBank . connect ( sender ) . backup ( encryptedData )
320+ const receipt = await tx . wait ( )
321+ const backupEvt = receipt . events [ 0 ]
322+ expect ( backupEvt . event ) . to . equal ( 'Backup' )
323+ expect ( backupEvt . args . user ) . to . equal ( sender . address )
324+ expect ( backupEvt . args . encryptedData ) . to . equal ( encryptedData )
325+
326+ // calculate relayer fee
327+ const gasPrice = await ethers . provider . getGasPrice ( )
328+ const gasFee = relayerFeeGasUsed . mul ( gasPrice )
329+ const relayerFee = DEPOSIT_AMOUNT . mul ( relayerFeePct )
330+ . div ( relayerFeePctBase )
331+ . add ( gasFee )
332+ . toBigInt ( )
333+
334+ // retrieve backed up data
335+ const decrypted = decrypt ( backupEvt . args . encryptedData , encryptionKey )
336+ const { secret : retrievedSecret , nullifier : retrievedNullifier } = unpackBackupData ( decrypted )
337+
338+ // generate proof
339+ const rawInput = {
340+ root : tree . root ,
341+ nullifierHash : poseidon . hash ( [ retrievedNullifier ] ) ,
342+ nullifier : retrievedNullifier ,
343+ relayer : relayer . address ,
344+ recipient : recipient . address ,
345+ relayerFee,
346+ gasRefund,
347+ secret : retrievedSecret ,
348+ pathElements : tree . path ( 0 ) . pathElements ,
349+ pathIndices : tree . path ( 0 ) . pathIndices ,
350+ }
351+ const input = utils . stringifyBigInts ( rawInput )
352+ const proofData = await generateProof ( input )
353+ const proof = toSolidityInput ( proofData )
354+
355+ // withdraw
356+ const inputs = {
357+ root : padHex ( rawInput . root as string ) ,
358+ nullifierHash : bigintToHex ( rawInput . nullifierHash ) ,
359+ nullifier : bigintToHex ( rawInput . nullifier ) ,
360+ recipient : recipient . address ,
361+ relayer : relayer . address ,
362+ relayerFee : bigintToHex ( rawInput . relayerFee ) ,
363+ gasRefund : bigintToHex ( rawInput . gasRefund ) ,
364+ }
365+ await expect ( privateBank . connect ( relayer ) . withdraw ( proof . proof , inputs ) ) . to . not . be . reverted
366+ } )
367+
294368 it ( 'withdraw(): should prevent double spend' , async ( ) => {
295369 // generate deposit
296370 const deposit = generateDeposit ( )
0 commit comments