master #2

Closed
tornadosto wants to merge 13 commits from (deleted):master into master
8 changed files with 2501 additions and 4329 deletions
Showing only changes of commit 68530df4ae - Show all commits

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ node_modules
backup-tornado-*
backup-tornadoInvoice-*
test
parseTool.js

View File

@ -100,5 +100,11 @@
"transactionHash": "0xbe98adfe86b0492cd85da8c684e53a4adc2b0b62eae2495c7a5962da635c80e9",
"commitment": "0x227deb325a01d3d83b36b03f2c31b761cf8c20e6f722c2f7c2ea8be02284fce1",
"leafIndex": 16
},
{
"blockNumber": 22410370,
"transactionHash": "0x99194cba56f82b27b6928cb37a72a441d83a990e9f8072b12d0c31cce79eb6af",
"commitment": "0x143e37303e307f5367ba3fc59a066fca1be31cdb714d622ab8ffa4246faafc05",
"leafIndex": 17
}
]

View File

@ -68,5 +68,12 @@
"nullifierHash": "0x1934703fb8829f2e2764b8621e208a9c0a51396a338ea1d098591c7b9a30c991",
"to": "0x9b5fbedaa0c2474b43e4f96f58e62f702614c8b8",
"fee": "4975916000000000"
},
{
"blockNumber": 22399965,
"transactionHash": "0xd881c6f30fc6486559dc7bfd870b753895a7bab0d101bec8ecb3c1d60a4bd68e",
"nullifierHash": "0x21edacf1834d5506c88be35371f7b328f89f3ed3947b58df5ce34a741adc96f2",
"to": "0x754e3d0f4473d2bd7b6bcb62a4c61706d1be9545",
"fee": "0"
}
]

View File

@ -2806,5 +2806,71 @@
"transactionHash": "0x6355fb983a6ef3a8fdc56c6bdd922e245aa7b5d540a16e3e77fc809caa69cb05",
"commitment": "0x090c378073347983a61faba04bceac833faf850b7f741e055fe0dff4d5f0f60c",
"leafIndex": 467
},
{
"blockNumber": 8512790,
"transactionHash": "0x48b4986220e5fac7f66882463b36b2fa8c2b835c864c6d4ef69f82c34d791989",
"commitment": "0x0d95cc4a4734bc1b38f88969833be59f4d00e873c050aef46904d44a45bf0c99",
"leafIndex": 468
},
{
"blockNumber": 8517336,
"transactionHash": "0xc05ca5ee41f898ac707028bf1aa8bd0cbdcdaa9b6da829d78f62e8d38f49eeca",
"commitment": "0x265c7af436102c72b356c4c591c0cfae7739d747c374c471207fe5013e3780f7",
"leafIndex": 469
},
{
"blockNumber": 8517338,
"transactionHash": "0xf94646fa0c296494297310cf5a3c5d5645b20d0aa6a2bf8a624895242721aa7e",
"commitment": "0x0f50f7eb3d29a5a8dd10040f1959244559500784814d6f0ed6bc06a73713d1ba",
"leafIndex": 470
},
{
"blockNumber": 8517340,
"transactionHash": "0x5d68f7d60d0dd9b3ead958937505d117b8bd330c7d66dd6045f9abc2fb5b7fe0",
"commitment": "0x0b1f7df788da3bc79af6045375f33526bea9875069f0d4c0b08e4a4deb119943",
"leafIndex": 471
},
{
"blockNumber": 8517340,
"transactionHash": "0x2dc823227381ef26d751fb0cbd52c9e3d7243652c2eb10194bc162be65b5d5c4",
"commitment": "0x300fbce94d9c67201fadab50642d94e3177b3f0c36b5f4eabaabc842e3a2220c",
"leafIndex": 472
},
{
"blockNumber": 8517341,
"transactionHash": "0x53496c24b74efad5f3525194131e108cab41a07bb660c27503754b04ecc93186",
"commitment": "0x02ab6d5b02df472aea2bf0aa0e636e544df3d548e65cadf701942a98ea6f575f",
"leafIndex": 473
},
{
"blockNumber": 8523780,
"transactionHash": "0x7bf42733334e476ef82f55315e061b91b6a5a6bbf5b63609b7dc7393ff6b213f",
"commitment": "0x0a5689d7eaa5d7b96b9b6f57a9c5a24ac4e501963c846f497d1141f860b37d76",
"leafIndex": 474
},
{
"blockNumber": 8523898,
"transactionHash": "0x93f0f2ce4ad1f7e17a0fe572a390e6ad10debbfa0f25d790a507f8d5dfe4dfe3",
"commitment": "0x304dc8e29bb9872d935cf078e1c18a6b51bc00dba68280db6dd84032c543300c",
"leafIndex": 475
},
{
"blockNumber": 8523944,
"transactionHash": "0xa0a16f1a347865e65c2ab6d6a0bb9973c31685ac8314ccabb02f77442e9f602c",
"commitment": "0x1614394331ebb2a4e78d334aabbf8cc4e0e9e8cdd027a2e763e936ee1fcbaa1f",
"leafIndex": 476
},
{
"blockNumber": 8524049,
"transactionHash": "0xbdf89d3a7cc41685055924a1441819897fa91a37da6c03f58708ba5b3e839ee5",
"commitment": "0x1c097afa86aecd1c3d80470198d905996b6acd681775865f5701649e4e5c886e",
"leafIndex": 477
},
{
"blockNumber": 8524562,
"transactionHash": "0x103d30f6cf0298bcf9d1d9eb131139c894483de53f0d8818228f1b89970bfae5",
"commitment": "0x11d2312bdd0fd600e424a471ae967101ee3df376c57e8ef0e846fb0d66b01574",
"leafIndex": 478
}
]

View File

@ -1608,5 +1608,19 @@
"nullifierHash": "0x24f34cd5f883150ca0ccc6a3aa4d3666d7b0e956eed33fd857dc71e6e0c0ffaf",
"to": "0x6cdd5ed4d414addf4edaf8d4c2d255873aba6886",
"fee": "0"
},
{
"blockNumber": 8512709,
"transactionHash": "0x0539dd7bc1adec05f79df57e34d1adbf4aa46e4f3c02e690e8b18620c33dad58",
"nullifierHash": "0x29b02580a5269d29e1d33f591cc0888fa831ea48aa29aff211655dbbb62cc879",
"to": "0x754e3d0f4473d2bd7b6bcb62a4c61706d1be9545",
"fee": "0"
},
{
"blockNumber": 8512833,
"transactionHash": "0xf1988e6f9732c4ddd636716808d7f4abb56c255d39e1c9f3cf19e64ee798cbc7",
"nullifierHash": "0x2e35d5dcb197d9282608faeff1188ebc216bd793e3401436e3bae46a5bb4b1e7",
"to": "0xd00de10817a1e2861712059b3d3a1db22c833a69",
"fee": "0"
}
]

108
cli.js
View File

@ -74,7 +74,8 @@ const relayerSubdomains = Object.values(config.deployments).map(({ ensSubdomainK
*/
/** @type {ProgramGlobals} */
const globals = {
const globals =
{
privateKey: undefined,
web3Instance: undefined,
relayerWeb3Instance: undefined,
@ -288,7 +289,8 @@ async function generateTransaction(to, encodedData, value = 0, txType = 'other')
/**
* Create deposit object from secret and nullifier
*/
function createDeposit({ nullifier, secret }) {
function createDeposit({ nullifier, secret })
{
let deposit = { nullifier, secret };
deposit.preimage = Buffer.concat([deposit.nullifier.leInt2Buff(31), deposit.secret.leInt2Buff(31)]);
deposit.commitment = pedersenHash(deposit.preimage);
@ -328,7 +330,8 @@ async function backupInvoice({ currency, amount, netId, commitmentNote, invoiceS
* @param currency Сurrency
* @param amount Deposit amount
*/
async function createInvoice({ currency, amount, chainId }) {
async function createInvoice({ currency, amount, chainId })
{
const deposit = createDeposit({
nullifier: rbigint(31),
secret: rbigint(31)
@ -422,7 +425,8 @@ async function deposit({ currency, amount, commitmentNote }) {
* @param {number} amount Tornado instance amount, like 0.1 (ETH or BNB) or 10
* @return {Promise<MerkleProof>} Calculated valid merkle tree (proof)
*/
async function generateMerkleProof(deposit, currency, amount) {
async function generateMerkleProof(deposit, currency, amount)
{
const { web3Instance, multiCallAddress, tornadoInstanceContract } = globals;
// Get all deposit events from smart contract and assemble merkle tree from them
@ -469,13 +473,16 @@ async function generateMerkleProof(deposit, currency, amount) {
* @param {MerkleProof} [args.merkleProof] Valid merkle tree proof
* @returns {Promise<ProofData>} Proof data
*/
async function generateProof({ deposit, currency, amount, recipient, relayerAddress = 0, fee = 0, refund = 0, merkleProof }) {
async function generateProof({ deposit, currency, amount, recipient, relayerAddress = 0, fee = 0, refund = 0, merkleProof })
{
// Compute merkle proof of our commitment
if (merkleProof === undefined) merkleProof = await generateMerkleProof(deposit, currency, amount);
if (merkleProof === undefined)
merkleProof = await generateMerkleProof(deposit, currency, amount);
const { root, pathElements, pathIndices } = merkleProof;
// Prepare circuit input
const input = {
const input =
{
// Public snark inputs
root: root,
nullifierHash: deposit.nullifierHash,
@ -518,65 +525,86 @@ async function generateProof({ deposit, currency, amount, recipient, relayerAddr
* @param noteString Note to withdraw
* @param recipient Recipient address
*/
async function withdraw({ deposit, currency, amount, recipient, relayerURL, refund, privateKey }) {
async function withdraw({ deposit, currency, amount, recipient, relayerURL, refund, privateKey })
{
const { web3Instance, signerAddress, tornadoProxyAddress, requestOptions, feeOracle, tornadoInstanceAddress, tornadoProxyContract, netSymbol, netId, shouldPromptConfirmation } = globals;
if (currency === netSymbol.toLowerCase() && refund && refund !== '0') {
if (currency === netSymbol.toLowerCase() && refund && refund !== '0')
{
throw new Error('The ETH purchase is supposed to be 0 for ETH withdrawals');
}
if (!isNaN(Number(refund))) refund = toWei(refund, 'ether');
else refund = toBN(await feeOracle.fetchRefundInETH(currency.toLowerCase()));
if (!isNaN(Number(refund)))
refund = toWei(refund, 'ether');
else
refund = toBN(await feeOracle.fetchRefundInETH(currency.toLowerCase()));
if (!web3Utils.isAddress(recipient)) {
if (!web3Utils.isAddress(recipient))
{
throw new Error('Recipient address is not valid');
}
const depositInfo = await loadDepositData({ amount, currency, deposit });
const allDeposits = loadCachedEvents({ type: "deposit", currency, amount });
if ((depositInfo.leafIndex > allDeposits[allDeposits.length - 1].leafIndex - 10) && allDeposits.length > 10){
if ((depositInfo.leafIndex > allDeposits[allDeposits.length - 1].leafIndex - 10)
&& allDeposits.length > 10)
{
console.log("\nWARNING: you're trying to withdraw your deposit too early, there are not enough subsequent deposits to ensure good anonymity level. Read: https://docs.tornado.ws/general/guides/opsec.html");
if (shouldPromptConfirmation) await promptConfirmation("Continue withdrawal with risks to anonymity? [Y/n]: ")
if (shouldPromptConfirmation)
await promptConfirmation("Continue withdrawal with risks to anonymity? [Y/n]: ")
}
const withdrawInfo = await loadWithdrawalData({ amount, currency, deposit });
if(withdrawInfo) {
if(withdrawInfo)
{
console.error("\nError: note has already been withdrawn. Use `compliance` command to check deposit and withdrawal info.\n");
process.exit(1);
}
if (privateKey || globals.privateKey) {
if (privateKey || globals.privateKey)
{
// using private key
// check if the address of recepient matches with the account of provided private key from environment to prevent accidental use of deposit address for withdrawal transaction.
assert(
assert
(
recipient.toLowerCase() == signerAddress.toLowerCase(),
'Withdrawal recepient mismatches with the account of provided private key from environment file'
);
const checkBalance = await web3Instance.getBalance(signerAddress);
assert(checkBalance !== 0, 'You have 0 balance, make sure to fund account by withdrawing from tornado using relayer first');
assert
(
checkBalance !== 0,
'You have 0 balance, make sure to fund account by withdrawing from tornado using relayer first'
);
const { proof, args } = await generateProof({ deposit, currency, amount, recipient, refund });
console.log('Submitting withdraw transaction');
await generateTransaction(
await generateTransaction
(
tornadoProxyAddress,
tornadoProxyContract.methods.withdraw(tornadoInstanceAddress, proof, ...args).encodeABI(),
toBN(args[5]),
'user_withdrawal'
);
}
else {
else
{
let relayerInfo;
if (relayerURL) {
try {
if (relayerURL)
{
try
{
relayerURL = new URL(relayerURL).origin;
res = await axios.get(relayerURL + '/status', requestOptions);
relayerInfo = res.data;
} catch (err) {
} catch (err)
{
console.error(err);
throw new Error('Cannot get relayer status');
}
}
else {
else
{
const availableRelayers = await getRelayers(netId);
if(availableRelayers.length === 0) throw new Error("Cannot automatically pick a relayer to withdraw your note. Provide relayer manually with `--relayer` cmd option or use private key withdrawal")
relayerInfo = pickWeightedRandomRelayer(availableRelayers);
@ -667,9 +695,12 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
}
}
if (currency === netSymbol.toLowerCase()) {
if (currency === netSymbol.toLowerCase())
{
await printETHBalance({ address: recipient, name: 'Recipient' });
} else {
}
else
{
await printERC20Balance({ address: recipient, name: 'Recipient' });
}
console.log('Done withdrawal from Tornado Cash');
@ -1409,10 +1440,12 @@ async function fetchEvents({ type, currency, amount }) {
* Parses Tornado Cash note
* @param {string} noteString the note
*/
function parseNote(noteString) {
function parseNote(noteString)
{
const noteRegex = /tornado-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<note>[0-9a-fA-F]{124})/g;
const match = noteRegex.exec(noteString);
if (!match) {
if (!match)
{
throw new Error('The note has invalid format');
}
@ -1573,11 +1606,7 @@ async function initNetwork({rpc, chainId, privateKey, torPort, onlyRpc, eventTyp
}
globals.web3Instance = await createWeb3Instance(rpc)
globals.netId = await globals.web3Instance.net.getId();
if(chainId == 61)
{
globals.netId = 61;
}
globals.netId = await globals.web3Instance.getChainId()
globals.netName = getCurrentNetworkName();
globals.netSymbol = getCurrentNetworkSymbol(globals.netId);
@ -1885,4 +1914,15 @@ async function main() {
}
}
main();
if (require.main === module)
{
main();
}
module.exports = {
parseNote,
init,
generateMerkleProof,
generateProof,
globals
};

View File

@ -304,7 +304,7 @@ module.exports = {
proxy: '0x1572AFE6949fdF51Cb3E0856216670ae9Ee160Ee',
multicall: '0x53c43764255c17bd724f74c4ef150724ac50a3ed',
subgraphs: ['https://gateway.thegraph.com/api/6a217817dd87d33db10beed79b044a91/subgraphs/id/8kJGz92AYUm72wfyUoze1as3E11ynDSTZM8emiRWrRPy'],
defaultRpcs: ['https://ethereum-sepolia-rpc.publicnode.com', 'https://mainnet.chainnodes.org/61b7de01-6cc4-40dc-a6c2-b6e4a61bb042']
defaultRpcs: ['https://ethereum-sepolia-rpc.publicnode.com', 'https://sepolia.chainnodes.org/61b7de01-6cc4-40dc-a6c2-b6e4a61bb042']
},
netId61:

6626
package-lock.json generated

File diff suppressed because it is too large Load Diff