master #2
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ node_modules
|
||||
backup-tornado-*
|
||||
backup-tornadoInvoice-*
|
||||
test
|
||||
parseTool.js
|
||||
|
||||
6
cache/ethereumclassic/deposits_etc_1.json
vendored
6
cache/ethereumclassic/deposits_etc_1.json
vendored
@ -100,5 +100,11 @@
|
||||
"transactionHash": "0xbe98adfe86b0492cd85da8c684e53a4adc2b0b62eae2495c7a5962da635c80e9",
|
||||
"commitment": "0x227deb325a01d3d83b36b03f2c31b761cf8c20e6f722c2f7c2ea8be02284fce1",
|
||||
"leafIndex": 16
|
||||
},
|
||||
{
|
||||
"blockNumber": 22410370,
|
||||
"transactionHash": "0x99194cba56f82b27b6928cb37a72a441d83a990e9f8072b12d0c31cce79eb6af",
|
||||
"commitment": "0x143e37303e307f5367ba3fc59a066fca1be31cdb714d622ab8ffa4246faafc05",
|
||||
"leafIndex": 17
|
||||
}
|
||||
]
|
||||
7
cache/ethereumclassic/withdrawals_etc_1.json
vendored
7
cache/ethereumclassic/withdrawals_etc_1.json
vendored
@ -68,5 +68,12 @@
|
||||
"nullifierHash": "0x1934703fb8829f2e2764b8621e208a9c0a51396a338ea1d098591c7b9a30c991",
|
||||
"to": "0x9b5fbedaa0c2474b43e4f96f58e62f702614c8b8",
|
||||
"fee": "4975916000000000"
|
||||
},
|
||||
{
|
||||
"blockNumber": 22399965,
|
||||
"transactionHash": "0xd881c6f30fc6486559dc7bfd870b753895a7bab0d101bec8ecb3c1d60a4bd68e",
|
||||
"nullifierHash": "0x21edacf1834d5506c88be35371f7b328f89f3ed3947b58df5ce34a741adc96f2",
|
||||
"to": "0x754e3d0f4473d2bd7b6bcb62a4c61706d1be9545",
|
||||
"fee": "0"
|
||||
}
|
||||
]
|
||||
66
cache/sepolia/deposits_eth_0.1.json
vendored
66
cache/sepolia/deposits_eth_0.1.json
vendored
@ -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
|
||||
}
|
||||
]
|
||||
14
cache/sepolia/withdrawals_eth_0.1.json
vendored
14
cache/sepolia/withdrawals_eth_0.1.json
vendored
@ -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
108
cli.js
@ -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
|
||||
};
|
||||
|
||||
@ -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
6626
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user