Improve EncryptedNotes
This commit is contained in:
parent
b9fa95f5be
commit
68f2e006ce
@ -60,6 +60,7 @@ module.exports = {
|
|||||||
"error",
|
"error",
|
||||||
"always"
|
"always"
|
||||||
],
|
],
|
||||||
"@typescript-eslint/no-unused-vars": ["warn"]
|
"@typescript-eslint/no-unused-vars": ["warn"],
|
||||||
|
"@typescript-eslint/no-unused-expressions": ["off"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,7 +1,7 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.env
|
.env
|
||||||
/events
|
|
||||||
/trees
|
# coverage files
|
||||||
backup-tornado-*
|
/coverage
|
||||||
backup-tornadoInvoice-*
|
/coverage.json
|
||||||
backup-note-account-*
|
.nyc_output
|
13
.nycrc
Normal file
13
.nycrc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"all": true,
|
||||||
|
"extension": [".ts"],
|
||||||
|
"report-dir": "coverage",
|
||||||
|
"reporter": [
|
||||||
|
"html",
|
||||||
|
"lcov",
|
||||||
|
"text",
|
||||||
|
"text-summary"
|
||||||
|
],
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["src/typechain/**/*"]
|
||||||
|
}
|
11
dist/encryptedNotes.d.ts
vendored
11
dist/encryptedNotes.d.ts
vendored
@ -1,6 +1,5 @@
|
|||||||
import { EthEncryptedData } from '@metamask/eth-sig-util';
|
import { EthEncryptedData } from '@metamask/eth-sig-util';
|
||||||
import { Echoer } from '@tornado/contracts';
|
import { Signer, Wallet } from 'ethers';
|
||||||
import { Wallet } from 'ethers';
|
|
||||||
import { EchoEvents, EncryptedNotesEvents } from './events';
|
import { EchoEvents, EncryptedNotesEvents } from './events';
|
||||||
import type { NetIdType } from './networkConfig';
|
import type { NetIdType } from './networkConfig';
|
||||||
export interface NoteToEncrypt {
|
export interface NoteToEncrypt {
|
||||||
@ -20,7 +19,6 @@ export interface NoteAccountConstructor {
|
|||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
blockNumber?: number;
|
blockNumber?: number;
|
||||||
recoveryKey?: string;
|
recoveryKey?: string;
|
||||||
Echoer: Echoer;
|
|
||||||
}
|
}
|
||||||
export declare class NoteAccount {
|
export declare class NoteAccount {
|
||||||
netId: NetIdType;
|
netId: NetIdType;
|
||||||
@ -28,13 +26,12 @@ export declare class NoteAccount {
|
|||||||
recoveryKey: string;
|
recoveryKey: string;
|
||||||
recoveryAddress: string;
|
recoveryAddress: string;
|
||||||
recoveryPublicKey: string;
|
recoveryPublicKey: string;
|
||||||
Echoer: Echoer;
|
constructor({ netId, blockNumber, recoveryKey }: NoteAccountConstructor);
|
||||||
constructor({ netId, blockNumber, recoveryKey, Echoer }: NoteAccountConstructor);
|
|
||||||
/**
|
/**
|
||||||
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
|
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
|
||||||
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
|
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
|
||||||
*/
|
*/
|
||||||
static getWalletPublicKey(wallet: Wallet): string;
|
static getSignerPublicKey(signer: Signer | Wallet): Promise<string>;
|
||||||
getEncryptedAccount(walletPublicKey: string): {
|
getEncryptedAccount(walletPublicKey: string): {
|
||||||
encryptedData: EthEncryptedData;
|
encryptedData: EthEncryptedData;
|
||||||
data: string;
|
data: string;
|
||||||
@ -42,7 +39,7 @@ export declare class NoteAccount {
|
|||||||
/**
|
/**
|
||||||
* Decrypt Echoer backuped note encryption account with private keys
|
* Decrypt Echoer backuped note encryption account with private keys
|
||||||
*/
|
*/
|
||||||
decryptAccountsWithWallet(wallet: Wallet, events: EchoEvents[]): NoteAccount[];
|
decryptSignerNoteAccounts(signer: Signer | Wallet, events: EchoEvents[]): Promise<NoteAccount[]>;
|
||||||
decryptNotes(events: EncryptedNotesEvents[]): DecryptedNotes[];
|
decryptNotes(events: EncryptedNotesEvents[]): DecryptedNotes[];
|
||||||
encryptNote({ address, noteHex }: NoteToEncrypt): string;
|
encryptNote({ address, noteHex }: NoteToEncrypt): string;
|
||||||
}
|
}
|
||||||
|
3
dist/hasher.d.ts
vendored
Normal file
3
dist/hasher.d.ts
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/index.d.ts
vendored
1
dist/index.d.ts
vendored
@ -8,6 +8,7 @@ export * from './encryptedNotes';
|
|||||||
export * from './ens';
|
export * from './ens';
|
||||||
export * from './fees';
|
export * from './fees';
|
||||||
export * from './gaszip';
|
export * from './gaszip';
|
||||||
|
export * from './hasher';
|
||||||
export * from './idb';
|
export * from './idb';
|
||||||
export * from './ip';
|
export * from './ip';
|
||||||
export * from './merkleTree';
|
export * from './merkleTree';
|
||||||
|
79
dist/index.js
vendored
79
dist/index.js
vendored
File diff suppressed because one or more lines are too long
78
dist/index.mjs
vendored
78
dist/index.mjs
vendored
File diff suppressed because one or more lines are too long
9
dist/merkleTreeWorker.umd.js
vendored
9
dist/merkleTreeWorker.umd.js
vendored
@ -102049,7 +102049,7 @@ function bytesToHex(bytes) {
|
|||||||
}
|
}
|
||||||
function hexToBytes(hexString) {
|
function hexToBytes(hexString) {
|
||||||
if (hexString.slice(0, 2) === "0x") {
|
if (hexString.slice(0, 2) === "0x") {
|
||||||
hexString = hexString.replace("0x", "");
|
hexString = hexString.slice(2);
|
||||||
}
|
}
|
||||||
if (hexString.length % 2 !== 0) {
|
if (hexString.length % 2 !== 0) {
|
||||||
hexString = "0" + hexString;
|
hexString = "0" + hexString;
|
||||||
@ -102061,8 +102061,8 @@ function bytesToBN(bytes) {
|
|||||||
}
|
}
|
||||||
function bnToBytes(bigint) {
|
function bnToBytes(bigint) {
|
||||||
let hexString = typeof bigint === "bigint" ? bigint.toString(16) : bigint;
|
let hexString = typeof bigint === "bigint" ? bigint.toString(16) : bigint;
|
||||||
if (hexString.startsWith("0x")) {
|
if (hexString.slice(0, 2) === "0x") {
|
||||||
hexString = hexString.replace("0x", "");
|
hexString = hexString.slice(2);
|
||||||
}
|
}
|
||||||
if (hexString.length % 2 !== 0) {
|
if (hexString.length % 2 !== 0) {
|
||||||
hexString = "0" + hexString;
|
hexString = "0" + hexString;
|
||||||
@ -102085,6 +102085,9 @@ function toFixedLength(string, length = 32) {
|
|||||||
function rBigInt(nbytes = 31) {
|
function rBigInt(nbytes = 31) {
|
||||||
return bytesToBN(utils_crypto.getRandomValues(new Uint8Array(nbytes)));
|
return bytesToBN(utils_crypto.getRandomValues(new Uint8Array(nbytes)));
|
||||||
}
|
}
|
||||||
|
function rHex(nbytes = 32) {
|
||||||
|
return bytesToHex(utils_crypto.getRandomValues(new Uint8Array(nbytes)));
|
||||||
|
}
|
||||||
function bigIntReplacer(key, value) {
|
function bigIntReplacer(key, value) {
|
||||||
return typeof value === "bigint" ? value.toString() : value;
|
return typeof value === "bigint" ? value.toString() : value;
|
||||||
}
|
}
|
||||||
|
10254
dist/tornado.umd.js
vendored
10254
dist/tornado.umd.js
vendored
File diff suppressed because one or more lines are too long
4
dist/tornado.umd.min.js
vendored
4
dist/tornado.umd.min.js
vendored
File diff suppressed because one or more lines are too long
1
dist/utils.d.ts
vendored
1
dist/utils.d.ts
vendored
@ -20,6 +20,7 @@ export declare function leInt2Buff(bigint: bnInput | bigint): Uint8Array;
|
|||||||
export declare function toFixedHex(numberish: BigNumberish, length?: number): string;
|
export declare function toFixedHex(numberish: BigNumberish, length?: number): string;
|
||||||
export declare function toFixedLength(string: string, length?: number): string;
|
export declare function toFixedLength(string: string, length?: number): string;
|
||||||
export declare function rBigInt(nbytes?: number): bigint;
|
export declare function rBigInt(nbytes?: number): bigint;
|
||||||
|
export declare function rHex(nbytes?: number): string;
|
||||||
export declare function bigIntReplacer(key: any, value: any): any;
|
export declare function bigIntReplacer(key: any, value: any): any;
|
||||||
export declare function substring(str: string, length?: number): string;
|
export declare function substring(str: string, length?: number): string;
|
||||||
export declare function digest(bytes: Uint8Array, algo?: string): Promise<Uint8Array>;
|
export declare function digest(bytes: Uint8Array, algo?: string): Promise<Uint8Array>;
|
||||||
|
9
hardhat.config.ts
Normal file
9
hardhat.config.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import type { HardhatUserConfig } from 'hardhat/types';
|
||||||
|
import '@nomicfoundation/hardhat-toolbox';
|
||||||
|
import '@nomicfoundation/hardhat-ethers';
|
||||||
|
|
||||||
|
const config: HardhatUserConfig = {
|
||||||
|
solidity: '0.8.28',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
24
package.json
24
package.json
@ -9,11 +9,12 @@
|
|||||||
"jsdelivr": "./dist/tornado.umd.min.js",
|
"jsdelivr": "./dist/tornado.umd.min.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
|
"typechain": "typechain --target ethers-v6 --out-dir src/typechain src/abi/*.json",
|
||||||
"types": "tsc --declaration --emitDeclarationOnly",
|
"types": "tsc --declaration --emitDeclarationOnly -p tsconfig.build.json",
|
||||||
"lint": "eslint src/**/*.ts --ext .ts --ignore-pattern src/typechain",
|
"lint": "eslint src/**/*.ts test/**/*.ts --ext .ts --ignore-pattern src/typechain",
|
||||||
"build:node": "rollup -c",
|
"build:node": "rollup -c",
|
||||||
"build:web": "webpack",
|
"build:web": "webpack",
|
||||||
"build": "yarn types && yarn build:node && yarn build:web"
|
"build": "yarn types && yarn build:node && yarn build:web",
|
||||||
|
"test": "nyc mocha --require ts-node/register --require source-map-support/register --recursive 'test/**/*.ts' --timeout '300000'"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -46,12 +47,23 @@
|
|||||||
"idb": "^8.0.0"
|
"idb": "^8.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@nomicfoundation/hardhat-chai-matchers": "^2.0.7",
|
||||||
|
"@nomicfoundation/hardhat-ethers": "^3.0.8",
|
||||||
|
"@nomicfoundation/hardhat-ignition": "^0.15.5",
|
||||||
|
"@nomicfoundation/hardhat-ignition-ethers": "^0.15.5",
|
||||||
|
"@nomicfoundation/hardhat-network-helpers": "^1.0.11",
|
||||||
|
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
||||||
|
"@nomicfoundation/hardhat-verify": "^2.0.10",
|
||||||
|
"@nomicfoundation/ignition-core": "^0.15.5",
|
||||||
"@rollup/plugin-commonjs": "^28.0.1",
|
"@rollup/plugin-commonjs": "^28.0.1",
|
||||||
"@rollup/plugin-json": "^6.1.0",
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
"@typechain/ethers-v6": "^0.5.1",
|
"@typechain/ethers-v6": "^0.5.1",
|
||||||
|
"@typechain/hardhat": "^9.1.0",
|
||||||
"@types/bn.js": "^5.1.6",
|
"@types/bn.js": "^5.1.6",
|
||||||
|
"@types/chai": "^4.2.0",
|
||||||
"@types/circomlibjs": "^0.1.6",
|
"@types/circomlibjs": "^0.1.6",
|
||||||
|
"@types/mocha": "^10.0.9",
|
||||||
"@types/node": "^22.8.0",
|
"@types/node": "^22.8.0",
|
||||||
"@types/node-fetch": "^2.6.11",
|
"@types/node-fetch": "^2.6.11",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.11.0",
|
"@typescript-eslint/eslint-plugin": "^8.11.0",
|
||||||
@ -62,10 +74,16 @@
|
|||||||
"eslint-import-resolver-typescript": "^3.6.3",
|
"eslint-import-resolver-typescript": "^3.6.3",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
|
"hardhat": "^2.22.10",
|
||||||
|
"hardhat-gas-reporter": "^2.2.1",
|
||||||
|
"mocha": "^10.7.3",
|
||||||
"node-polyfill-webpack-plugin": "^4.0.0",
|
"node-polyfill-webpack-plugin": "^4.0.0",
|
||||||
|
"nyc": "^17.1.0",
|
||||||
"prettier": "^3.3.3",
|
"prettier": "^3.3.3",
|
||||||
"rollup": "^4.24.0",
|
"rollup": "^4.24.0",
|
||||||
"rollup-plugin-esbuild": "^6.1.1",
|
"rollup-plugin-esbuild": "^6.1.1",
|
||||||
|
"solidity-coverage": "^0.8.13",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
"tsc": "^2.0.4",
|
"tsc": "^2.0.4",
|
||||||
"typechain": "^8.3.2",
|
"typechain": "^8.3.2",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { getEncryptionPublicKey, encrypt, decrypt, EthEncryptedData } from '@metamask/eth-sig-util';
|
import { getEncryptionPublicKey, encrypt, decrypt, EthEncryptedData } from '@metamask/eth-sig-util';
|
||||||
import { Echoer } from '@tornado/contracts';
|
import { JsonRpcApiProvider, Signer, Wallet, computeAddress, getAddress } from 'ethers';
|
||||||
import { Wallet, computeAddress, getAddress } from 'ethers';
|
import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes, toFixedHex, concatBytes, rHex } from './utils';
|
||||||
import { crypto, base64ToBytes, bytesToBase64, bytesToHex, hexToBytes, toFixedHex, concatBytes } from './utils';
|
|
||||||
import { EchoEvents, EncryptedNotesEvents } from './events';
|
import { EchoEvents, EncryptedNotesEvents } from './events';
|
||||||
import type { NetIdType } from './networkConfig';
|
import type { NetIdType } from './networkConfig';
|
||||||
|
|
||||||
@ -48,7 +47,6 @@ export interface NoteAccountConstructor {
|
|||||||
blockNumber?: number;
|
blockNumber?: number;
|
||||||
// hex
|
// hex
|
||||||
recoveryKey?: string;
|
recoveryKey?: string;
|
||||||
Echoer: Echoer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NoteAccount {
|
export class NoteAccount {
|
||||||
@ -61,11 +59,10 @@ export class NoteAccount {
|
|||||||
recoveryAddress: string;
|
recoveryAddress: string;
|
||||||
// Note encryption public key derived from recoveryKey
|
// Note encryption public key derived from recoveryKey
|
||||||
recoveryPublicKey: string;
|
recoveryPublicKey: string;
|
||||||
Echoer: Echoer;
|
|
||||||
|
|
||||||
constructor({ netId, blockNumber, recoveryKey, Echoer }: NoteAccountConstructor) {
|
constructor({ netId, blockNumber, recoveryKey }: NoteAccountConstructor) {
|
||||||
if (!recoveryKey) {
|
if (!recoveryKey) {
|
||||||
recoveryKey = bytesToHex(crypto.getRandomValues(new Uint8Array(32))).slice(2);
|
recoveryKey = rHex(32).slice(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.netId = Math.floor(Number(netId));
|
this.netId = Math.floor(Number(netId));
|
||||||
@ -73,22 +70,26 @@ export class NoteAccount {
|
|||||||
this.recoveryKey = recoveryKey;
|
this.recoveryKey = recoveryKey;
|
||||||
this.recoveryAddress = computeAddress('0x' + recoveryKey);
|
this.recoveryAddress = computeAddress('0x' + recoveryKey);
|
||||||
this.recoveryPublicKey = getEncryptionPublicKey(recoveryKey);
|
this.recoveryPublicKey = getEncryptionPublicKey(recoveryKey);
|
||||||
this.Echoer = Echoer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
|
* Intends to mock eth_getEncryptionPublicKey behavior from MetaMask
|
||||||
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
|
* In order to make the recoveryKey retrival from Echoer possible from the bare private key
|
||||||
*/
|
*/
|
||||||
static getWalletPublicKey(wallet: Wallet) {
|
static async getSignerPublicKey(signer: Signer | Wallet) {
|
||||||
let { privateKey } = wallet;
|
if ((signer as Wallet).privateKey) {
|
||||||
|
const wallet = signer as Wallet;
|
||||||
|
const privateKey = wallet.privateKey.slice(0, 2) === '0x' ? wallet.privateKey.slice(2) : wallet.privateKey;
|
||||||
|
|
||||||
if (privateKey.startsWith('0x')) {
|
// Should return base64 encoded public key
|
||||||
privateKey = privateKey.replace('0x', '');
|
return getEncryptionPublicKey(privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should return base64 encoded public key
|
const provider = signer.provider as JsonRpcApiProvider;
|
||||||
return getEncryptionPublicKey(privateKey);
|
|
||||||
|
return (await provider.send('eth_getEncryptionPublicKey', [
|
||||||
|
(signer as Signer & { address: string }).address,
|
||||||
|
])) as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function intends to provide an encrypted value of recoveryKey for an on-chain Echoer backup purpose
|
// This function intends to provide an encrypted value of recoveryKey for an on-chain Echoer backup purpose
|
||||||
@ -116,30 +117,53 @@ export class NoteAccount {
|
|||||||
/**
|
/**
|
||||||
* Decrypt Echoer backuped note encryption account with private keys
|
* Decrypt Echoer backuped note encryption account with private keys
|
||||||
*/
|
*/
|
||||||
decryptAccountsWithWallet(wallet: Wallet, events: EchoEvents[]): NoteAccount[] {
|
async decryptSignerNoteAccounts(signer: Signer | Wallet, events: EchoEvents[]): Promise<NoteAccount[]> {
|
||||||
let { privateKey } = wallet;
|
const signerAddress = (signer as (Signer & { address: string }) | Wallet).address;
|
||||||
|
|
||||||
if (privateKey.startsWith('0x')) {
|
|
||||||
privateKey = privateKey.replace('0x', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
const decryptedEvents = [];
|
const decryptedEvents = [];
|
||||||
|
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
|
if (event.address !== signerAddress) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const unpackedMessage = unpackEncryptedMessage(event.encryptedAccount);
|
const unpackedMessage = unpackEncryptedMessage(event.encryptedAccount);
|
||||||
|
|
||||||
const recoveryKey = decrypt({
|
let recoveryKey;
|
||||||
encryptedData: unpackedMessage,
|
|
||||||
privateKey,
|
if ((signer as Wallet).privateKey) {
|
||||||
});
|
const wallet = signer as Wallet;
|
||||||
|
const privateKey = wallet.privateKey.slice(0, 2) === '0x' ? wallet.privateKey.slice(2) : wallet.privateKey;
|
||||||
|
|
||||||
|
recoveryKey = decrypt({
|
||||||
|
encryptedData: unpackedMessage,
|
||||||
|
privateKey,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const { version, nonce, ephemPublicKey, ciphertext } = unpackedMessage;
|
||||||
|
|
||||||
|
const unpackedBuffer = bytesToHex(
|
||||||
|
new TextEncoder().encode(
|
||||||
|
JSON.stringify({
|
||||||
|
version,
|
||||||
|
nonce,
|
||||||
|
ephemPublicKey,
|
||||||
|
ciphertext,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const provider = signer.provider as JsonRpcApiProvider;
|
||||||
|
|
||||||
|
recoveryKey = await provider.send('eth_decrypt', [unpackedBuffer, signerAddress]);
|
||||||
|
}
|
||||||
|
|
||||||
decryptedEvents.push(
|
decryptedEvents.push(
|
||||||
new NoteAccount({
|
new NoteAccount({
|
||||||
netId: this.netId,
|
netId: this.netId,
|
||||||
blockNumber: event.blockNumber,
|
blockNumber: event.blockNumber,
|
||||||
recoveryKey,
|
recoveryKey,
|
||||||
Echoer: this.Echoer,
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch {
|
} catch {
|
||||||
|
8
src/hasher.ts
Normal file
8
src/hasher.ts
Normal file
File diff suppressed because one or more lines are too long
@ -8,6 +8,7 @@ export * from './encryptedNotes';
|
|||||||
export * from './ens';
|
export * from './ens';
|
||||||
export * from './fees';
|
export * from './fees';
|
||||||
export * from './gaszip';
|
export * from './gaszip';
|
||||||
|
export * from './hasher';
|
||||||
export * from './idb';
|
export * from './idb';
|
||||||
export * from './ip';
|
export * from './ip';
|
||||||
export * from './merkleTree';
|
export * from './merkleTree';
|
||||||
|
@ -586,7 +586,7 @@ export const defaultConfig: networkConfig = {
|
|||||||
stablecoin: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
stablecoin: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
||||||
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
multicallContract: '0xcA11bde05977b3631167028862bE2a173976CA11',
|
||||||
routerContract: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee',
|
routerContract: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee',
|
||||||
echoContract: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
echoContract: '0xcDD1fc3F5ac2782D83449d3AbE80D6b7B273B0e5',
|
||||||
offchainOracleContract: '0x1f89EAF03E5b260Bc6D4Ae3c3334b1B750F3e127',
|
offchainOracleContract: '0x1f89EAF03E5b260Bc6D4Ae3c3334b1B750F3e127',
|
||||||
tornContract: '0x3AE6667167C0f44394106E197904519D808323cA',
|
tornContract: '0x3AE6667167C0f44394106E197904519D808323cA',
|
||||||
governanceContract: '0xe5324cD7602eeb387418e594B87aCADee08aeCAD',
|
governanceContract: '0xe5324cD7602eeb387418e594B87aCADee08aeCAD',
|
||||||
|
10
src/utils.ts
10
src/utils.ts
@ -72,7 +72,7 @@ export function bytesToHex(bytes: Uint8Array) {
|
|||||||
|
|
||||||
export function hexToBytes(hexString: string) {
|
export function hexToBytes(hexString: string) {
|
||||||
if (hexString.slice(0, 2) === '0x') {
|
if (hexString.slice(0, 2) === '0x') {
|
||||||
hexString = hexString.replace('0x', '');
|
hexString = hexString.slice(2);
|
||||||
}
|
}
|
||||||
if (hexString.length % 2 !== 0) {
|
if (hexString.length % 2 !== 0) {
|
||||||
hexString = '0' + hexString;
|
hexString = '0' + hexString;
|
||||||
@ -90,8 +90,8 @@ export function bnToBytes(bigint: bigint | string) {
|
|||||||
// Parse bigint to hex string
|
// Parse bigint to hex string
|
||||||
let hexString: string = typeof bigint === 'bigint' ? bigint.toString(16) : bigint;
|
let hexString: string = typeof bigint === 'bigint' ? bigint.toString(16) : bigint;
|
||||||
// Remove hex string prefix if exists
|
// Remove hex string prefix if exists
|
||||||
if (hexString.startsWith('0x')) {
|
if (hexString.slice(0, 2) === '0x') {
|
||||||
hexString = hexString.replace('0x', '');
|
hexString = hexString.slice(2);
|
||||||
}
|
}
|
||||||
// Hex string length should be a multiplier of two (To make correct bytes)
|
// Hex string length should be a multiplier of two (To make correct bytes)
|
||||||
if (hexString.length % 2 !== 0) {
|
if (hexString.length % 2 !== 0) {
|
||||||
@ -130,6 +130,10 @@ export function rBigInt(nbytes: number = 31) {
|
|||||||
return bytesToBN(crypto.getRandomValues(new Uint8Array(nbytes)));
|
return bytesToBN(crypto.getRandomValues(new Uint8Array(nbytes)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function rHex(nbytes: number = 32) {
|
||||||
|
return bytesToHex(crypto.getRandomValues(new Uint8Array(nbytes)));
|
||||||
|
}
|
||||||
|
|
||||||
// Used for JSON.stringify(value, bigIntReplacer, space)
|
// Used for JSON.stringify(value, bigIntReplacer, space)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export function bigIntReplacer(key: any, value: any) {
|
export function bigIntReplacer(key: any, value: any) {
|
||||||
|
58
test/deposit.ts
Normal file
58
test/deposit.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { loadFixture } from '@nomicfoundation/hardhat-toolbox/network-helpers';
|
||||||
|
import { anyValue } from '@nomicfoundation/hardhat-chai-matchers/withArgs';
|
||||||
|
import { ethers } from 'hardhat';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { formatEther } from 'ethers';
|
||||||
|
|
||||||
|
import { ETHTornado__factory, Verifier__factory } from '@tornado/contracts';
|
||||||
|
import { Deposit, deployHasher } from '../src';
|
||||||
|
|
||||||
|
const { getSigners } = ethers;
|
||||||
|
|
||||||
|
const NOTES_COUNT = 100;
|
||||||
|
|
||||||
|
describe('./src/deposit.ts', function () {
|
||||||
|
const instanceFixture = async () => {
|
||||||
|
const [owner] = await getSigners();
|
||||||
|
|
||||||
|
const Hasher = (await (await deployHasher(owner)).wait())?.contractAddress as string;
|
||||||
|
|
||||||
|
const Verifier = await new Verifier__factory(owner).deploy();
|
||||||
|
|
||||||
|
const Instance = await new ETHTornado__factory(owner).deploy(Verifier.target, Hasher, 1n, 20);
|
||||||
|
|
||||||
|
return { Instance };
|
||||||
|
};
|
||||||
|
|
||||||
|
it('Deposit New Note', async function () {
|
||||||
|
const { Instance } = await loadFixture(instanceFixture);
|
||||||
|
|
||||||
|
const [owner] = await getSigners();
|
||||||
|
|
||||||
|
const netId = Number((await owner.provider.getNetwork()).chainId);
|
||||||
|
|
||||||
|
const deposit = await Deposit.createNote({ currency: 'eth', amount: formatEther(1), netId });
|
||||||
|
|
||||||
|
const resp = await Instance.deposit(deposit.commitmentHex, { value: 1n });
|
||||||
|
|
||||||
|
await expect(resp).to.emit(Instance, 'Deposit').withArgs(deposit.commitmentHex, 0, anyValue);
|
||||||
|
|
||||||
|
expect(await Instance.commitments(deposit.commitmentHex)).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
xit(`Creating ${NOTES_COUNT} random notes`, async function () {
|
||||||
|
const notes = (await Promise.all(
|
||||||
|
// eslint-disable-next-line prefer-spread
|
||||||
|
Array.apply(null, Array(NOTES_COUNT)).map(() =>
|
||||||
|
Deposit.createNote({ currency: 'eth', amount: '0.1', netId: 31337 }),
|
||||||
|
),
|
||||||
|
)) as Deposit[];
|
||||||
|
|
||||||
|
notes.forEach(({ noteHex, commitmentHex, nullifierHex }) => {
|
||||||
|
// ((secret.length: 31) + (nullifier.length: 31)) * 2 + (prefix: 2) = 126
|
||||||
|
expect(noteHex.length === 126).to.be.true;
|
||||||
|
expect(commitmentHex.length === 66).to.be.true;
|
||||||
|
expect(nullifierHex.length === 66).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
14
test/index.ts
Normal file
14
test/index.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { describe } from 'mocha';
|
||||||
|
import { ethers } from 'hardhat';
|
||||||
|
|
||||||
|
describe('Tornado Core', function () {
|
||||||
|
it('Get Provider', async function () {
|
||||||
|
const [owner] = await ethers.getSigners();
|
||||||
|
|
||||||
|
console.log(owner);
|
||||||
|
|
||||||
|
const { provider } = owner;
|
||||||
|
|
||||||
|
console.log(await provider.getBlock('latest'));
|
||||||
|
});
|
||||||
|
});
|
7
tsconfig.build.json
Normal file
7
tsconfig.build.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src"
|
||||||
|
},
|
||||||
|
"files": []
|
||||||
|
}
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
/* Modules */
|
/* Modules */
|
||||||
"module": "commonjs", /* Specify what module code is generated. */
|
"module": "commonjs", /* Specify what module code is generated. */
|
||||||
"rootDir": "./src", /* Specify the root folder within your source files. */
|
"rootDir": ".", /* Specify the root folder within your source files. */
|
||||||
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
// "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||||
@ -59,7 +59,7 @@
|
|||||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||||
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
||||||
// "removeComments": true, /* Disable emitting comments. */
|
// "removeComments": true, /* Disable emitting comments. */
|
||||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||||
@ -110,5 +110,6 @@
|
|||||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
},
|
},
|
||||||
"include": ["./src/**/*"]
|
"include": ["./src/**/*"],
|
||||||
|
"files": ["./hardhat.config.ts"]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user