master #1
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ node_modules
|
|||||||
backup-tornado-*
|
backup-tornado-*
|
||||||
backup-tornadoInvoice-*
|
backup-tornadoInvoice-*
|
||||||
test
|
test
|
||||||
|
parseTool.js
|
||||||
|
|||||||
@ -5,8 +5,8 @@ RUN apt update && apt install --yes --no-install-recommends wget git apt-transpo
|
|||||||
|
|
||||||
WORKDIR /home/root/tornado-cli
|
WORKDIR /home/root/tornado-cli
|
||||||
|
|
||||||
ENV GIT_REPOSITORY=https://git.tornado.ws/tornadocash/tornado-cli
|
ENV GIT_REPOSITORY=https://git.tornado.ws/tornadosto/tornado-cli.git
|
||||||
ENV GIT_COMMIT_HASH=7e0d8d9183f1f29409e1ec0b3c94a44354ae30fa
|
ENV GIT_COMMIT_HASH=5efae744be6c1d3269d697a032fae389f8ddf0cb
|
||||||
|
|
||||||
RUN git init && \
|
RUN git init && \
|
||||||
git remote add origin $GIT_REPOSITORY && \
|
git remote add origin $GIT_REPOSITORY && \
|
||||||
@ -18,3 +18,7 @@ RUN npm ci
|
|||||||
RUN npm install -g pkg@5.8.1
|
RUN npm install -g pkg@5.8.1
|
||||||
|
|
||||||
RUN node scripts/createDeterministicExecutable.js
|
RUN node scripts/createDeterministicExecutable.js
|
||||||
|
|
||||||
|
RUN printf '#!/bin/sh\ncp /home/root/tornado-cli/tornado-cli.exe /output/' > /copy_out.sh && chmod +x /copy_out.sh
|
||||||
|
|
||||||
|
CMD ["/bin/bash"]
|
||||||
25
README.md
25
README.md
@ -53,12 +53,7 @@ Also, you can use VPN for CLI without Tor or even combine it.
|
|||||||
|
|
||||||
All code logic located in `cli.js`, other files is just testing scripts or static files. You can check or change any part of the code and at next `node cli.js` run changes will apply.
|
All code logic located in `cli.js`, other files is just testing scripts or static files. You can check or change any part of the code and at next `node cli.js` run changes will apply.
|
||||||
|
|
||||||
Any user can check that the precompiled `tornado-cli.exe` matches the source code. To verify **tornado-cli.exe**:
|
Any user can check that the precompiled `tornado-cli.exe` matches the source code. To build `tornado-cli.exe`, [pkg](https://www.npmjs.com/package/pkg) package is used, which allows creating deterministic and reproducible executable from source. Creating script is located at `./scripts/createDeterministicExecutable.js`, and you can rebuild executable with command `npm run createExe`, or you can verify that sha1 hash of existing executable matches new executable, verification script located at `./scripts/verifyExecutable` and you can call it with command `npm run verifyExe` and compare hashes.
|
||||||
|
|
||||||
1. Build docker image from latest commit: `docker build -t tornado-cli .`
|
|
||||||
2. Create container`docker create --name tornado-cli tornado-cli:latest`
|
|
||||||
3. Copy executable from container `docker cp tornado-cli:/home/root/tornado-cli/tornado-cli.exe tornado-cli-verify.exe`
|
|
||||||
4. Compare hashes of original tornado-cli.exe and freshly generated executable with two commands: on Windows use `CertUtil -hashfile tornado-cli.exe SHA256` and `CertUtil -hashfile tornado-cli-verify.exe SHA256`, on Linux - `sha256sum tornado-cli.exe` and `sha256sum tornado-cli-verify.exe`. Hashes should be identical.
|
|
||||||
|
|
||||||
### Commands and usage
|
### Commands and usage
|
||||||
|
|
||||||
@ -168,3 +163,21 @@ View transaction on block explorer https://goerli.etherscan.io/tx/0x6ded443caed8
|
|||||||
Tornado contract balance is xxx.x ETH
|
Tornado contract balance is xxx.x ETH
|
||||||
Sender account balance is x.xxxxxxx ETH
|
Sender account balance is x.xxxxxxx ETH
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### To verify:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker build -t tornado-cli:latest .
|
||||||
|
```
|
||||||
|
wait for docker to build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker run --rm -v %cd%/output:/output tornado-cli:latest /copy_out.sh
|
||||||
|
```
|
||||||
|
copy exe to current folder in windows
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CertUtil -hashfile output/tornado-cli.exe SHA256
|
||||||
|
CertUtil -hashfile tornado-cli.exe SHA256
|
||||||
|
```
|
||||||
|
compare with the exe in git
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,290 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "governanceAddress",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "tornAddress",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "_relayerRegistry",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "constructor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "account",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "rewardsClaimed",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "RewardsClaimed",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anonymous": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"indexed": true,
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "account",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"indexed": false,
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "rewards",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "RewardsUpdated",
|
|
||||||
"type": "event"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "Governance",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "contract ITornadoGovernance",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "accumulatedRewardPerTorn",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "accumulatedRewardRateOnLastUpdate",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "accumulatedRewards",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "addBurnRewards",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "bytes32[]",
|
|
||||||
"name": "domains",
|
|
||||||
"type": "bytes32[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "bulkResolve",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address[]",
|
|
||||||
"name": "result",
|
|
||||||
"type": "address[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "account",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "checkReward",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "rewards",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "getReward",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "ratioConstant",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "relayerRegistry",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "bytes32",
|
|
||||||
"name": "node",
|
|
||||||
"type": "bytes32"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "resolve",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "account",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "setReward",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [],
|
|
||||||
"name": "torn",
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"internalType": "contract IERC20",
|
|
||||||
"name": "",
|
|
||||||
"type": "address"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stateMutability": "view",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "address",
|
|
||||||
"name": "account",
|
|
||||||
"type": "address"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amountLockedBeforehand",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "updateRewardsOnLockedBalanceChange",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"internalType": "uint256",
|
|
||||||
"name": "amount",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "withdrawTorn",
|
|
||||||
"outputs": [],
|
|
||||||
"stateMutability": "nonpayable",
|
|
||||||
"type": "function"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
110
cache/ethereumclassic/deposits_etc_1.json
vendored
Normal file
110
cache/ethereumclassic/deposits_etc_1.json
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"blockNumber": 22385840,
|
||||||
|
"transactionHash": "0x63fa83cf4127ef4147d507b23501179cfc6c037731e8dfb4fd2cc49c09b9eae8",
|
||||||
|
"commitment": "0x03f8ca1f7d166d11531313ef8b15acb22b19ae5dd98ceea6886b16a320a517cd",
|
||||||
|
"leafIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22385872,
|
||||||
|
"transactionHash": "0xf55784219dc9d71c142b42f4099e6b791ef5fb2035ee9d14c8e82879a37eae2c",
|
||||||
|
"commitment": "0x1be521b0899780c2dbc5ce84dfcf90b5635692b23f6ea1042c9312d742e990d8",
|
||||||
|
"leafIndex": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22392807,
|
||||||
|
"transactionHash": "0x9c7c0202da743a351aafc60c5e62f46c920b7ef8ab0fbd9a437ee5df2f273a52",
|
||||||
|
"commitment": "0x2c6e62f51b8251c9ebdeccbcdd58efe15b35326cb3f1e0ddd4b99eed3c9fccb0",
|
||||||
|
"leafIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22392987,
|
||||||
|
"transactionHash": "0x81505022469948ef6d700738463cbfa30aab567897a7bcd7c5b9ac34c25f9b14",
|
||||||
|
"commitment": "0x1fc417281a28562a41f921786f147ac95e77323304c5cdb9a9359d2dd971056f",
|
||||||
|
"leafIndex": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393172,
|
||||||
|
"transactionHash": "0x764550f81da7ba82bb609bd45bba1f0e61deb14fa1a30a320ac8fa7042f6f383",
|
||||||
|
"commitment": "0x29b11c7da6fcaeb3c6248472677a65fb55daec2a110b90ff0d5c7ad95d4bd05e",
|
||||||
|
"leafIndex": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393172,
|
||||||
|
"transactionHash": "0x207a4a95a0bd67e8d7bfb35f81a02d80465b467467fd3097bcf9877a5d1dd712",
|
||||||
|
"commitment": "0x0a29115a2af3acbb0820056604fd123ed365a3b8e856901430b0c5609ed03897",
|
||||||
|
"leafIndex": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393172,
|
||||||
|
"transactionHash": "0x6afd92cf8f9f0afec38179f6c223e49b69fd414354f382c87a0f3e23b596dab3",
|
||||||
|
"commitment": "0x167ece4de25842f445e5005a525f20f86f7edc8b2a65a923184b052f43a894d5",
|
||||||
|
"leafIndex": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393172,
|
||||||
|
"transactionHash": "0xd4c4bae2a66fb7aa192d81144459f1e9030a5211f68a644919fbad722a644b0c",
|
||||||
|
"commitment": "0x15902671ae98cbd40887e395eeef6e9d66972c671fdd688cdecbc6b7c89b3bc0",
|
||||||
|
"leafIndex": 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393172,
|
||||||
|
"transactionHash": "0x84fb0853a93fb412f3570a115e56f97677df99762f741c6c281df411703ea14b",
|
||||||
|
"commitment": "0x146518004a7639391f39833de66bce38ccb23f7d24ae072f2ea7e3ad349fbcb0",
|
||||||
|
"leafIndex": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393287,
|
||||||
|
"transactionHash": "0x9c9d005fb758fdc3810d26923573e27c6149cec3d3f0e219ea7182010f8279a0",
|
||||||
|
"commitment": "0x1c7e098f281b291f47ffdbe734bd7762638692765aa10ae79d00296c683b4f64",
|
||||||
|
"leafIndex": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393298,
|
||||||
|
"transactionHash": "0xa145a95807fb52c42dcaa478f5784755feedbc06948871066f2c4b63a674e583",
|
||||||
|
"commitment": "0x0e874573d767d81c8e04427b38ef7ee88732c9c92c9534f3b42965091d244d95",
|
||||||
|
"leafIndex": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393384,
|
||||||
|
"transactionHash": "0xaefad2d9200f27c1ff2dc6731563753fd87ffd5abb16f2610f9d8408e5173643",
|
||||||
|
"commitment": "0x109040cd8b4f5073949d62c7923cc8030fcc92e3675cc35932a4cbbacb8ce6be",
|
||||||
|
"leafIndex": 11
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22396258,
|
||||||
|
"transactionHash": "0x6135e90e4c74bf5b3271a44850a10f5556bb3ca57d8f2850c0eddfb1375a1280",
|
||||||
|
"commitment": "0x034e30e5e1c21deaa71cfedea0fa153c25d3ff380bed56f83a78ed5a307a0c36",
|
||||||
|
"leafIndex": 12
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22396797,
|
||||||
|
"transactionHash": "0x82dd8478501366f3d7bc82694af2bdbeb5fd3878baf4ddb9d02f1eaf7d31ce63",
|
||||||
|
"commitment": "0x1469fb2b9bed134e8cff2ada483a8f416b2a44629c7a388dd713b9dc05b87d02",
|
||||||
|
"leafIndex": 13
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22396930,
|
||||||
|
"transactionHash": "0x56d1744e17e907f0a33ac774eed8dcf1ddb003e14d1e52bf37fdbcf41b0a8cb2",
|
||||||
|
"commitment": "0x10199e8b32f29fdc6410cac40d9db40302e0902afd71e7a86f94a33af9a6c6d0",
|
||||||
|
"leafIndex": 14
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22396986,
|
||||||
|
"transactionHash": "0xd3f697cbe6384d33e3751e222e75ed868adc2175bacd1f3bf91cdd9fa2332a5e",
|
||||||
|
"commitment": "0x0e13899823c0e21680f21de2e1ffd74d899ebfebbd767c8dd3a9b665fb9a2ed4",
|
||||||
|
"leafIndex": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22399955,
|
||||||
|
"transactionHash": "0xbe98adfe86b0492cd85da8c684e53a4adc2b0b62eae2495c7a5962da635c80e9",
|
||||||
|
"commitment": "0x227deb325a01d3d83b36b03f2c31b761cf8c20e6f722c2f7c2ea8be02284fce1",
|
||||||
|
"leafIndex": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22410370,
|
||||||
|
"transactionHash": "0x99194cba56f82b27b6928cb37a72a441d83a990e9f8072b12d0c31cce79eb6af",
|
||||||
|
"commitment": "0x143e37303e307f5367ba3fc59a066fca1be31cdb714d622ab8ffa4246faafc05",
|
||||||
|
"leafIndex": 17
|
||||||
|
}
|
||||||
|
]
|
||||||
79
cache/ethereumclassic/withdrawals_etc_1.json
vendored
Normal file
79
cache/ethereumclassic/withdrawals_etc_1.json
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"blockNumber": 22385858,
|
||||||
|
"transactionHash": "0x1a8cb44a9d03d2e1248deed7c65d86b30e2ae0f6ccd1e26dfcdd026e6e7ba7e2",
|
||||||
|
"nullifierHash": "0x01de4b0b2bee6944f771806e61dcb8f223f77ebcb86140040e4b18532dcfa642",
|
||||||
|
"to": "0xc2f667db796e82913160c1e01030aabbd5ead47e",
|
||||||
|
"fee": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22385878,
|
||||||
|
"transactionHash": "0xef83a1582639c13b2ccf90d10305d2c873eedc04346563988d0175cb2e9cf876",
|
||||||
|
"nullifierHash": "0x0466c43a2ba160630a9929a1e9ef956610ab9fd8038fadd0d80dd6dab498ee37",
|
||||||
|
"to": "0xc2f667db796e82913160c1e01030aabbd5ead47e",
|
||||||
|
"fee": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393007,
|
||||||
|
"transactionHash": "0x397d7d92ca3aaa571bb10f8f8cb1dc272ecb7be35bc4e8131ce086d36c2b5f5f",
|
||||||
|
"nullifierHash": "0x11e974a721874186ce971f36873c013bc93c464ed26a6a82ed96319573f9c673",
|
||||||
|
"to": "0xb4ef209ccee95de23a8e1f7627ac7e676ff0739d",
|
||||||
|
"fee": "7182616000000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393369,
|
||||||
|
"transactionHash": "0x8d5d7de4fcd014b050b9feff398fafd88112c04b0fccd420944ecabfe339dd44",
|
||||||
|
"nullifierHash": "0x22af5c5cd73087a65567b25a3da887d3dc192806691a3694fa868f9ea63ef7d2",
|
||||||
|
"to": "0xc0f12799b8d3fa8810dfe1616095170c72117f8f",
|
||||||
|
"fee": "1986919520000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393391,
|
||||||
|
"transactionHash": "0xfdcb3c4521394b1871243e1a6ad3ee1c5c0a18e118c571f4206e6a7b48e96a34",
|
||||||
|
"nullifierHash": "0x0add34f677a5e2faccda12a32698418222f07075983b205bd990e68c0b96255e",
|
||||||
|
"to": "0xc0f12799b8d3fa8810dfe1616095170c72117f8f",
|
||||||
|
"fee": "4974722720000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22393496,
|
||||||
|
"transactionHash": "0x840dcdc3982c47ca46b088bd9d63977682a6eb2461df832ee1a85d41d5e8475b",
|
||||||
|
"nullifierHash": "0x1fca9aec5973b7cefbd632df53224c32a5bdb7e0c5516b1bfbcf7819f3f1c1b3",
|
||||||
|
"to": "0xc2f667db796e82913160c1e01030aabbd5ead47e",
|
||||||
|
"fee": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22396800,
|
||||||
|
"transactionHash": "0x306a40c939450320a433399435e93b99f6de9c835196cb5aef94e97829e7a165",
|
||||||
|
"nullifierHash": "0x1664ce55a6e2520b562b8d2a9e4a965b4e72478bb423bdcd671e89ca9083b515",
|
||||||
|
"to": "0xb4ef209ccee95de23a8e1f7627ac7e676ff0739d",
|
||||||
|
"fee": "1574701600000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22396811,
|
||||||
|
"transactionHash": "0x9728fab8b35a5a4fd0e6a67bb0e90963ade1262f5bb49a80a736253c27c3017e",
|
||||||
|
"nullifierHash": "0x19aa705bf1b01bf5a304b46f5f4f960766f8191068750373b4585ebb0d5f0dee",
|
||||||
|
"to": "0x9b5fbedaa0c2474b43e4f96f58e62f702614c8b8",
|
||||||
|
"fee": "1575916000000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22397057,
|
||||||
|
"transactionHash": "0x45a369f482fc98f39eb55c4bd2e113ebf8436f93a01211609881acdab5a87d06",
|
||||||
|
"nullifierHash": "0x1f9d9874d23cbd163d31b8f2b936ba18d5b3a42991519970bdea29712e1f0ff0",
|
||||||
|
"to": "0xc0f12799b8d3fa8810dfe1616095170c72117f8f",
|
||||||
|
"fee": "4986919520000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22397185,
|
||||||
|
"transactionHash": "0x55ece3a9554848a6042ce8cbd4ff22ddd64d51d4b63347d15c661ba8345a68ff",
|
||||||
|
"nullifierHash": "0x1934703fb8829f2e2764b8621e208a9c0a51396a338ea1d098591c7b9a30c991",
|
||||||
|
"to": "0x9b5fbedaa0c2474b43e4f96f58e62f702614c8b8",
|
||||||
|
"fee": "4975916000000000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"blockNumber": 22399965,
|
||||||
|
"transactionHash": "0xd881c6f30fc6486559dc7bfd870b753895a7bab0d101bec8ecb3c1d60a4bd68e",
|
||||||
|
"nullifierHash": "0x21edacf1834d5506c88be35371f7b328f89f3ed3947b58df5ce34a741adc96f2",
|
||||||
|
"to": "0x754e3d0f4473d2bd7b6bcb62a4c61706d1be9545",
|
||||||
|
"fee": "0"
|
||||||
|
}
|
||||||
|
]
|
||||||
2894
cache/sepolia/deposits_eth_0.1.json
vendored
Normal file
2894
cache/sepolia/deposits_eth_0.1.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
cache/sepolia/deposits_eth_1.json
vendored
18
cache/sepolia/deposits_eth_1.json
vendored
@ -550,23 +550,5 @@
|
|||||||
"transactionHash": "0xf810858c8d70168efa0c4db912ed7caf191b1379612c6e4ec0adc7272d48e599",
|
"transactionHash": "0xf810858c8d70168efa0c4db912ed7caf191b1379612c6e4ec0adc7272d48e599",
|
||||||
"commitment": "0x05cef42e5d479a19a6d6dfc3e2a59efee92ab350875aa77c84bec4b5d7f04546",
|
"commitment": "0x05cef42e5d479a19a6d6dfc3e2a59efee92ab350875aa77c84bec4b5d7f04546",
|
||||||
"leafIndex": 91
|
"leafIndex": 91
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8548903,
|
|
||||||
"transactionHash": "0xd00051d1b3d58e8abdf2e333b84a80e48722342e2e60371d4ca5fc74b4812968",
|
|
||||||
"commitment": "0x2820eab529e832cb5550001ffbb336b11000cbaf7d7e444283858df83ec752e7",
|
|
||||||
"leafIndex": 92
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8554220,
|
|
||||||
"transactionHash": "0xe9d72cb832e7e45fb43d3c3f5f4485b759dd298e1488e37bcf7f0f2e14340cf1",
|
|
||||||
"commitment": "0x1bc58d9aa06b54578c59cf5503bf5f9824a46463976cdcc750bcc789d1f17827",
|
|
||||||
"leafIndex": 93
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8582499,
|
|
||||||
"transactionHash": "0xb5b3bf519294917588501dedeaff90f75274a34e38c02dd93640847cee3a2a61",
|
|
||||||
"commitment": "0x305c2a56eb349ca8910cdce13ac0ff86a607521423481a315a40c9b80e30c484",
|
|
||||||
"leafIndex": 94
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
86
cache/sepolia/deposits_eth_10.json
vendored
86
cache/sepolia/deposits_eth_10.json
vendored
@ -1,86 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"blockNumber": 6808552,
|
|
||||||
"transactionHash": "0x7d7f9d83dc671ddac7f68fbd1643f35ee388f74c049339a40c92bca9120f303b",
|
|
||||||
"commitment": "0x1fabbaf0879a9691cf5d7d0cfab8411ac18b59cde8aa6336647c55b5b0364756",
|
|
||||||
"leafIndex": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6841965,
|
|
||||||
"transactionHash": "0x894a12cdc48d3c2f1c0e41403014c750eee232fc0942aa6a1b7b45e8ffe01c25",
|
|
||||||
"commitment": "0x28554b45d48c8b4defc13874c0bed9a3a2508947de91664be901b747985b8c66",
|
|
||||||
"leafIndex": 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6841972,
|
|
||||||
"transactionHash": "0x13f1e212b49d814066afa79a7ec9c0ebfdb19cd49ab1a4f54753d2bea0707eba",
|
|
||||||
"commitment": "0x1c3378f8e955fe66f5d6f2621ddb812bbbfd53d25f2a1efc3aaaf7539639109b",
|
|
||||||
"leafIndex": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6841977,
|
|
||||||
"transactionHash": "0x128193940812eee01b874336378215c02446b9022671c19b516a5a47c4943094",
|
|
||||||
"commitment": "0x11dd59ccfcf8b8f95a8d488b6b92dfef7271426b2d8a80724aa458a949d2d616",
|
|
||||||
"leafIndex": 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6841996,
|
|
||||||
"transactionHash": "0x91abeea9495392b3e86fad1de78a02ab98c7ec7309f764de513cc5da27c6fb7b",
|
|
||||||
"commitment": "0x1ebe8c66bb44d730e96a0c3030deaf099eadeb7c49f3fc558e66484d5a59e479",
|
|
||||||
"leafIndex": 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6842009,
|
|
||||||
"transactionHash": "0x643c36ca6a6770c0838bd03da4424f41eba4ae0010bbfe6c2db3fc82e8ee3f77",
|
|
||||||
"commitment": "0x09b3231821f0cc8b957051feafa73796a43567c16802a59b8d355abad013d302",
|
|
||||||
"leafIndex": 5
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6842010,
|
|
||||||
"transactionHash": "0x7e3bd713be872432cf0fd25aad30f5607b7346754a4d55040811b3ed24623a97",
|
|
||||||
"commitment": "0x1a63b64f8687b587c159aede8bcf1baf34a4bf9aa4d5d10d6bc5959a62a61f8e",
|
|
||||||
"leafIndex": 6
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6859777,
|
|
||||||
"transactionHash": "0xa7e5cd6440fb27401c2065562ad003e27f56bf5e3deb1113c11f91e9a5fe5a14",
|
|
||||||
"commitment": "0x2ec46d07c14093a5b59061e647b2780d7b7d43495ae175c414a40e3bf3434aef",
|
|
||||||
"leafIndex": 7
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6859779,
|
|
||||||
"transactionHash": "0xcc0f337ac271d595cfac1e5f2ad3b5e12983dbbff945929a32e1f964c12ba8d4",
|
|
||||||
"commitment": "0x2e6f47a8e1ccd23af268fb5d2ef8739b74cd486b480963e76493f73d3eca8ae7",
|
|
||||||
"leafIndex": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6859781,
|
|
||||||
"transactionHash": "0x9384d9be1508d30b76d97fe1f83b29f91948ad6aae886c107bd8cc620b3c28d7",
|
|
||||||
"commitment": "0x2827191f0a60a6867114fe38db2adbf96543e23d821979f5825a07de76f06edd",
|
|
||||||
"leafIndex": 9
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8142964,
|
|
||||||
"transactionHash": "0x3637a59d43ded88e11a1e33a47e9ac25d588f1a645d73ce463d32c8f5ee20c41",
|
|
||||||
"commitment": "0x25e1e0db5f9fee5f34a6bf177bb102ae3bb55ddbb850a1394bb788a0f83402e7",
|
|
||||||
"leafIndex": 10
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8414361,
|
|
||||||
"transactionHash": "0x9db998ec88fc6569d8707a09d9b556bd3332b84037ed05b0ce73e97e37dc637d",
|
|
||||||
"commitment": "0x030d556c506fac8d8420e8583c8683af885761e08c68647c51300836c5d061c3",
|
|
||||||
"leafIndex": 11
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8415769,
|
|
||||||
"transactionHash": "0xae54c08901cc31f66e5f2aa559b65b4ad41d335e2247f4fdd71bc99b3588e7e4",
|
|
||||||
"commitment": "0x1cdc8de34b0a461e6486770f97bc623b1f34ea10f79b6e98f8f47ef33dc02a20",
|
|
||||||
"leafIndex": 12
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8589745,
|
|
||||||
"transactionHash": "0xdabfe58e8c2beb13e636b751c36efde634f62f38ac65ad05e52ab2cc5009b8bf",
|
|
||||||
"commitment": "0x0cbe58b8e9002532253174ff8f0e4574d968760f4fb35c948a9a947850739639",
|
|
||||||
"leafIndex": 13
|
|
||||||
}
|
|
||||||
]
|
|
||||||
1626
cache/sepolia/withdrawals_eth_0.1.json
vendored
Normal file
1626
cache/sepolia/withdrawals_eth_0.1.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
cache/sepolia/withdrawals_eth_1.json
vendored
21
cache/sepolia/withdrawals_eth_1.json
vendored
@ -446,26 +446,5 @@
|
|||||||
"nullifierHash": "0x00fac88aeaaf4cdfe15e4f0e246ccf7e5b64adca4a0699989f9eaeb47d0a32bd",
|
"nullifierHash": "0x00fac88aeaaf4cdfe15e4f0e246ccf7e5b64adca4a0699989f9eaeb47d0a32bd",
|
||||||
"to": "0xc53c51af207c224a865d8bb5e1948ac5c2cb8442",
|
"to": "0xc53c51af207c224a865d8bb5e1948ac5c2cb8442",
|
||||||
"fee": "0"
|
"fee": "0"
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8554223,
|
|
||||||
"transactionHash": "0x2a134c9ecacc558184d74b65b60fad388985de493e8542a43c24288f160c04c5",
|
|
||||||
"nullifierHash": "0x2d5e889a9d3b27af4578e4df48e620de2673e551a444bd005c61692d93fd890c",
|
|
||||||
"to": "0xb66596d2eab0204494dedaeffe0f86fc74714a0f",
|
|
||||||
"fee": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8583310,
|
|
||||||
"transactionHash": "0xf30b1b4064f561b103d2d54f4dfd8fd6c6b27e11d049b57ef128f02a0a77e67a",
|
|
||||||
"nullifierHash": "0x27b4bc29a518df33ad035be4d580528bbf5447da01c1cd3619fafc0ffa8497bd",
|
|
||||||
"to": "0xb67af20093837ab2d4fc826a729f30612c47ef2e",
|
|
||||||
"fee": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8589727,
|
|
||||||
"transactionHash": "0xaa1da6d30393434b4e7500e946129343676c954526864a890d0a6760c70cd67a",
|
|
||||||
"nullifierHash": "0x2bccfd39f219e8acade8908e35e48711eef76edf24c221aa850bd1f8b07812f7",
|
|
||||||
"to": "0x9ff3c1bea9ffb56a78824fe29f457f066257dd58",
|
|
||||||
"fee": "0"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
44
cache/sepolia/withdrawals_eth_10.json
vendored
44
cache/sepolia/withdrawals_eth_10.json
vendored
@ -1,44 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"blockNumber": 6852128,
|
|
||||||
"transactionHash": "0x1207bb7e71881f0585069c3d5460481bdd0b06b89769ecee6a4ea2721a458c66",
|
|
||||||
"nullifierHash": "0x1f048c38e166e09fec79454a2b6d4169051ab640e26a28571036bffad9afd0f8",
|
|
||||||
"to": "0x40c3d1656a26c9266f4a10fed0d87eff79f54e64",
|
|
||||||
"fee": "88446881087520000"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6895895,
|
|
||||||
"transactionHash": "0x73bab36402644d065a6ff5bb805416538c302c2460f186302b27bb23f6e0cde1",
|
|
||||||
"nullifierHash": "0x1e3df17b5fb58f51aa17b247c4ef4e201b8017e4633908f97cb8e885ba447657",
|
|
||||||
"to": "0x7d98a740517586b3f2b369015585c21d02db117e",
|
|
||||||
"fee": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6895899,
|
|
||||||
"transactionHash": "0x6cbec76fc1d86a3d9a5ff9d72dcd09a117fc814d66867d35751c5f4a3bc6136e",
|
|
||||||
"nullifierHash": "0x01044fd0ffb372aa0ce7b91c0b8d41a68142621f76653d0d466c69fa49f95658",
|
|
||||||
"to": "0x7d98a740517586b3f2b369015585c21d02db117e",
|
|
||||||
"fee": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 6895903,
|
|
||||||
"transactionHash": "0xd8693cb67c6f668008b4887736b638903b7fe3debed3f38b900424d1456230d4",
|
|
||||||
"nullifierHash": "0x1998975018dfb4c3b946685aaf9557faea15152d4cade2255d4127c1aa0a614c",
|
|
||||||
"to": "0x7d98a740517586b3f2b369015585c21d02db117e",
|
|
||||||
"fee": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8414382,
|
|
||||||
"transactionHash": "0x06fc1138e6bc20ec3d41fb35785810fdfd5160ab05b04b38a752158938431c62",
|
|
||||||
"nullifierHash": "0x22b9b8581092ee88e8cf1d8c214403ba3008383e86f6425f780b562e11f5b236",
|
|
||||||
"to": "0xa382e9af881ea84010847922cad4307a83fbfcc7",
|
|
||||||
"fee": "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"blockNumber": 8415797,
|
|
||||||
"transactionHash": "0x10e1e7d474ec670dc05e040ab1a9349116d3faf2425c68a98eff6ccf8386fb21",
|
|
||||||
"nullifierHash": "0x00763202337be87dc9e606012b3aa9a2dac9f210f54db613a91c75d89183426d",
|
|
||||||
"to": "0x68356fd2f92a96040c312fed8ffd4569d1fcde59",
|
|
||||||
"fee": "0"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
433
cli.js
433
cli.js
@ -29,16 +29,11 @@ const tornadoProxyAbi = require('./abis/TornadoProxy.abi.json');
|
|||||||
const tornadoInstanceAbi = require('./abis/Instance.abi.json');
|
const tornadoInstanceAbi = require('./abis/Instance.abi.json');
|
||||||
const relayerRegistryAbi = require("./abis/RelayerRegistry.abi.json");
|
const relayerRegistryAbi = require("./abis/RelayerRegistry.abi.json");
|
||||||
const relayerAggregatorAbi = require('./abis/Aggregator.abi');
|
const relayerAggregatorAbi = require('./abis/Aggregator.abi');
|
||||||
const tornadoGovernanceAbi = require("./abis/Governance.abi.json");
|
|
||||||
const stakingRewardsAbi = require("./abis/StakingRewards.abi.json");
|
|
||||||
|
|
||||||
const relayerAggregatorAddress = config.deployments[`netId1`].relayerAggregator;
|
const relayerAggregatorAddress = config.deployments[`netId1`].relayerAggregator;
|
||||||
const relayerRegistryAddress = config.deployments[`netId1`].relayerRegistry;
|
const relayerRegistryAddress = config.deployments[`netId1`].relayerRegistry;
|
||||||
const relayerRegistryDeployedBlockNumber = config.deployments["netId1"].relayerRegistryDeployedBlockNumber;
|
const relayerRegistryDeployedBlockNumber = config.deployments["netId1"].relayerRegistryDeployedBlockNumber;
|
||||||
const relayerSubdomains = Object.values(config.deployments).map(({ ensSubdomainKey }) => ensSubdomainKey);
|
const relayerSubdomains = Object.values(config.deployments).map(({ ensSubdomainKey }) => ensSubdomainKey);
|
||||||
const tornTokenAddress = "0x77777FeDdddFfC19Ff86DB637967013e6C6A116C";
|
|
||||||
const governanceAddress = "0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce";
|
|
||||||
const stakingRewardsAddress = "0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29";
|
|
||||||
|
|
||||||
/** @typedef {import ("web3-eth-contract").Contract} Web3Contract */
|
/** @typedef {import ("web3-eth-contract").Contract} Web3Contract */
|
||||||
/** @typedef {import ("web3-eth").Eth} Web3Eth */
|
/** @typedef {import ("web3-eth").Eth} Web3Eth */
|
||||||
@ -73,9 +68,6 @@ const stakingRewardsAddress = "0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29";
|
|||||||
* @property {Web3Contract} [tornadoInstanceContract] Tornado cash instance contract for selected pool (chain/currency/value)
|
* @property {Web3Contract} [tornadoInstanceContract] Tornado cash instance contract for selected pool (chain/currency/value)
|
||||||
* @property {Web3Contract} [tornadoProxyContract] Tornado cash proxy contract for selected chain
|
* @property {Web3Contract} [tornadoProxyContract] Tornado cash proxy contract for selected chain
|
||||||
* @property {Web3Contract} [tornadoTokenInstanceContract] Tornado Cash instance contract for selected token pool (for ERC20 token mixing pools, e.g. DAI)
|
* @property {Web3Contract} [tornadoTokenInstanceContract] Tornado Cash instance contract for selected token pool (for ERC20 token mixing pools, e.g. DAI)
|
||||||
* @property {Web3Contract} [governanceContract] Tornado Cash Governance contract instance to access staking/voting functionality
|
|
||||||
* @property {Web3Contract} [tornTokenContract] TORN token contract instance to approve/send tokens
|
|
||||||
* @property {Web3Contract} [stakingRewardsContract] Staking rewards contract to distribute TORN tokens earned by Tornado protocol between TORN stakers
|
|
||||||
* @property {string} netName Network (chain) human-readable name
|
* @property {string} netName Network (chain) human-readable name
|
||||||
* @property {string} netSymbol Network main token symbol (ETH for Ethereum mainnet and so on)
|
* @property {string} netSymbol Network main token symbol (ETH for Ethereum mainnet and so on)
|
||||||
* @property {string} netId Network (chain) ID
|
* @property {string} netId Network (chain) ID
|
||||||
@ -101,9 +93,6 @@ const globals =
|
|||||||
feeOracle: undefined,
|
feeOracle: undefined,
|
||||||
tornadoInstanceContract: undefined,
|
tornadoInstanceContract: undefined,
|
||||||
tornadoProxyContract: undefined,
|
tornadoProxyContract: undefined,
|
||||||
governanceContract: undefined,
|
|
||||||
tornTokenContract: undefined,
|
|
||||||
stakingRewardsContract: undefined,
|
|
||||||
netName: "Ethereum",
|
netName: "Ethereum",
|
||||||
netSymbol: "ETH",
|
netSymbol: "ETH",
|
||||||
netId: 1
|
netId: 1
|
||||||
@ -300,7 +289,8 @@ async function generateTransaction(to, encodedData, value = 0, txType = 'other')
|
|||||||
/**
|
/**
|
||||||
* Create deposit object from secret and nullifier
|
* Create deposit object from secret and nullifier
|
||||||
*/
|
*/
|
||||||
function createDeposit({ nullifier, secret }) {
|
function createDeposit({ nullifier, secret })
|
||||||
|
{
|
||||||
let deposit = { nullifier, secret };
|
let deposit = { nullifier, secret };
|
||||||
deposit.preimage = Buffer.concat([deposit.nullifier.leInt2Buff(31), deposit.secret.leInt2Buff(31)]);
|
deposit.preimage = Buffer.concat([deposit.nullifier.leInt2Buff(31), deposit.secret.leInt2Buff(31)]);
|
||||||
deposit.commitment = pedersenHash(deposit.preimage);
|
deposit.commitment = pedersenHash(deposit.preimage);
|
||||||
@ -340,7 +330,8 @@ async function backupInvoice({ currency, amount, netId, commitmentNote, invoiceS
|
|||||||
* @param currency Сurrency
|
* @param currency Сurrency
|
||||||
* @param amount Deposit amount
|
* @param amount Deposit amount
|
||||||
*/
|
*/
|
||||||
async function createInvoice({ currency, amount, chainId }) {
|
async function createInvoice({ currency, amount, chainId })
|
||||||
|
{
|
||||||
const deposit = createDeposit({
|
const deposit = createDeposit({
|
||||||
nullifier: rbigint(31),
|
nullifier: rbigint(31),
|
||||||
secret: rbigint(31)
|
secret: rbigint(31)
|
||||||
@ -404,7 +395,7 @@ async function deposit({ currency, amount, commitmentNote }) {
|
|||||||
console.log('Current allowance is', fromWei(allowance));
|
console.log('Current allowance is', fromWei(allowance));
|
||||||
if (toBN(allowance).lt(toBN(tokenAmount))) {
|
if (toBN(allowance).lt(toBN(tokenAmount))) {
|
||||||
console.log('Approving tokens for deposit');
|
console.log('Approving tokens for deposit');
|
||||||
await generateTransaction(tornTokenAddress, tornadoTokenInstanceContract.methods.approve(tornadoProxyAddress, tokenAmount).call(), 0, 'send')
|
await generateTransaction(instanceTokenAddress, tornadoTokenInstanceContract.methods.approve(tornadoProxyAddress, tokenAmount).encodeABI());
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Submitting deposit transaction');
|
console.log('Submitting deposit transaction');
|
||||||
@ -434,7 +425,8 @@ async function deposit({ currency, amount, commitmentNote }) {
|
|||||||
* @param {number} amount Tornado instance amount, like 0.1 (ETH or BNB) or 10
|
* @param {number} amount Tornado instance amount, like 0.1 (ETH or BNB) or 10
|
||||||
* @return {Promise<MerkleProof>} Calculated valid merkle tree (proof)
|
* @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;
|
const { web3Instance, multiCallAddress, tornadoInstanceContract } = globals;
|
||||||
|
|
||||||
// Get all deposit events from smart contract and assemble merkle tree from them
|
// Get all deposit events from smart contract and assemble merkle tree from them
|
||||||
@ -481,7 +473,8 @@ async function generateMerkleProof(deposit, currency, amount) {
|
|||||||
* @param {MerkleProof} [args.merkleProof] Valid merkle tree proof
|
* @param {MerkleProof} [args.merkleProof] Valid merkle tree proof
|
||||||
* @returns {Promise<ProofData>} Proof data
|
* @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
|
// Compute merkle proof of our commitment
|
||||||
if (merkleProof === undefined)
|
if (merkleProof === undefined)
|
||||||
merkleProof = await generateMerkleProof(deposit, currency, amount);
|
merkleProof = await generateMerkleProof(deposit, currency, amount);
|
||||||
@ -532,9 +525,11 @@ async function generateProof({ deposit, currency, amount, recipient, relayerAddr
|
|||||||
* @param noteString Note to withdraw
|
* @param noteString Note to withdraw
|
||||||
* @param recipient Recipient address
|
* @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;
|
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');
|
throw new Error('The ETH purchase is supposed to be 0 for ETH withdrawals');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,25 +538,29 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
|||||||
else
|
else
|
||||||
refund = toBN(await feeOracle.fetchRefundInETH(currency.toLowerCase()));
|
refund = toBN(await feeOracle.fetchRefundInETH(currency.toLowerCase()));
|
||||||
|
|
||||||
if (!web3Utils.isAddress(recipient)) {
|
if (!web3Utils.isAddress(recipient))
|
||||||
|
{
|
||||||
throw new Error('Recipient address is not valid');
|
throw new Error('Recipient address is not valid');
|
||||||
}
|
}
|
||||||
|
|
||||||
const depositInfo = await loadDepositData({ amount, currency, deposit });
|
const depositInfo = await loadDepositData({ amount, currency, deposit });
|
||||||
const allDeposits = loadCachedEvents({ type: "deposit", currency, amount });
|
const allDeposits = loadCachedEvents({ type: "deposit", currency, amount });
|
||||||
if ((depositInfo.leafIndex > allDeposits[allDeposits.length - 1].leafIndex - 10)
|
if ((depositInfo.leafIndex > allDeposits[allDeposits.length - 1].leafIndex - 10)
|
||||||
&& allDeposits.length > 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");
|
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)
|
if (shouldPromptConfirmation)
|
||||||
await promptConfirmation("Continue withdrawal with risks to anonymity? [Y/n]: ")
|
await promptConfirmation("Continue withdrawal with risks to anonymity? [Y/n]: ")
|
||||||
}
|
}
|
||||||
const withdrawInfo = await loadWithdrawalData({ amount, currency, deposit });
|
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");
|
console.error("\nError: note has already been withdrawn. Use `compliance` command to check deposit and withdrawal info.\n");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (privateKey || globals.privateKey) {
|
if (privateKey || globals.privateKey)
|
||||||
|
{
|
||||||
// using private key
|
// 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.
|
// 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.
|
||||||
@ -588,21 +587,26 @@ async function withdraw({ deposit, currency, amount, recipient, relayerURL, refu
|
|||||||
'user_withdrawal'
|
'user_withdrawal'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
let relayerInfo;
|
let relayerInfo;
|
||||||
if (relayerURL) {
|
if (relayerURL)
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
relayerURL = new URL(relayerURL).origin;
|
relayerURL = new URL(relayerURL).origin;
|
||||||
res = await axios.get(relayerURL + '/status', requestOptions);
|
res = await axios.get(relayerURL + '/status', requestOptions);
|
||||||
relayerInfo = res.data;
|
relayerInfo = res.data;
|
||||||
} catch (err) {
|
} catch (err)
|
||||||
|
{
|
||||||
console.error(err);
|
console.error(err);
|
||||||
throw new Error('Cannot get relayer status');
|
throw new Error('Cannot get relayer status');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
const availableRelayers = await getRelayers(netId);
|
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")
|
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);
|
relayerInfo = pickWeightedRandomRelayer(availableRelayers);
|
||||||
relayerURL = "https://" + relayerInfo.hostname
|
relayerURL = "https://" + relayerInfo.hostname
|
||||||
console.log(`Selected relayer: ${relayerURL}`)
|
console.log(`Selected relayer: ${relayerURL}`)
|
||||||
@ -691,10 +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' });
|
await printETHBalance({ address: recipient, name: 'Recipient' });
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
await printERC20Balance({ address: recipient, name: 'Recipient' });
|
await printERC20Balance({ address: recipient, name: 'Recipient' });
|
||||||
}
|
}
|
||||||
console.log('Done withdrawal from Tornado Cash');
|
console.log('Done withdrawal from Tornado Cash');
|
||||||
@ -976,9 +982,9 @@ function getCurrentNetworkSymbol(chainId) {
|
|||||||
*/
|
*/
|
||||||
async function waitForTxReceipt({ txHash, attempts = 60, delay = 1000 }) {
|
async function waitForTxReceipt({ txHash, attempts = 60, delay = 1000 }) {
|
||||||
let retryAttempt = 0;
|
let retryAttempt = 0;
|
||||||
while (retryAttempt < attempts) {
|
while(retryAttempt < attempts){
|
||||||
const result = await globals.web3Instance.getTransactionReceipt(txHash);
|
const result = await globals.web3Instance.getTransactionReceipt(txHash);
|
||||||
if (!result?.blockNumber) {
|
if(!result?.blockNumber){
|
||||||
retryAttempt++;
|
retryAttempt++;
|
||||||
await sleep(delay);
|
await sleep(delay);
|
||||||
continue;
|
continue;
|
||||||
@ -997,20 +1003,20 @@ async function waitForTxReceipt({ txHash, attempts = 60, delay = 1000 }) {
|
|||||||
* if we can fetch all deposit events from subgraph, we shouldn't require archive node)
|
* if we can fetch all deposit events from subgraph, we shouldn't require archive node)
|
||||||
* @returns {Promise<string>} Full RPC link
|
* @returns {Promise<string>} Full RPC link
|
||||||
*/
|
*/
|
||||||
async function selectDefaultRpc(chainId, eventType, isSubgraphAvailable = false) {
|
async function selectDefaultRpc(chainId, eventType, isSubgraphAvailable = false){
|
||||||
const candidates = config.deployments[`netId${chainId}`].defaultRpcs;
|
const candidates = config.deployments[`netId${chainId}`].defaultRpcs;
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
for(const candidate of candidates){
|
||||||
const localWeb3 = await createWeb3Instance(candidate);
|
const localWeb3 = await createWeb3Instance(candidate);
|
||||||
|
|
||||||
try {
|
try{
|
||||||
if (!(await localWeb3.net.isListening())) throw new Error('Cannot connect to websocket provider');
|
if (!(await localWeb3.net.isListening())) throw new Error('Cannot connect to websocket provider');
|
||||||
|
|
||||||
if (eventType === "relayer") {
|
if (eventType === "relayer"){
|
||||||
const relayerRegistryContract = new localWeb3.Contract(relayerRegistryAbi, relayerRegistryAddress);
|
const relayerRegistryContract = new localWeb3.Contract(relayerRegistryAbi, relayerRegistryAddress);
|
||||||
const registeredRelayers = loadCachedEvents({ type: "relayer" });
|
const registeredRelayers = loadCachedEvents({type: "relayer"});
|
||||||
|
|
||||||
if (registeredRelayers.length > 0) {
|
if(registeredRelayers.length > 0){
|
||||||
const relayerAggregatorContract = new localWeb3.Contract(relayerAggregatorAbi, relayerAggregatorAddress);
|
const relayerAggregatorContract = new localWeb3.Contract(relayerAggregatorAbi, relayerAggregatorAddress);
|
||||||
const relayerNameHashes = registeredRelayers.map(r => r.ensHash);
|
const relayerNameHashes = registeredRelayers.map(r => r.ensHash);
|
||||||
// Here it checks RPC returndata size limit: when getRelayer function aggregates onchain data for all relayers, returndata size will be big
|
// Here it checks RPC returndata size limit: when getRelayer function aggregates onchain data for all relayers, returndata size will be big
|
||||||
@ -1042,7 +1048,7 @@ async function selectDefaultRpc(chainId, eventType, isSubgraphAvailable = false)
|
|||||||
|
|
||||||
console.log("Selected RPC: " + candidate);
|
console.log("Selected RPC: " + candidate);
|
||||||
return candidate;
|
return candidate;
|
||||||
} catch (e) {
|
} catch(e){
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1056,9 +1062,9 @@ async function selectDefaultRpc(chainId, eventType, isSubgraphAvailable = false)
|
|||||||
* @param {EventType} eventType Possible type of events in Tornado: deposit, withdrawal or fetch relayers
|
* @param {EventType} eventType Possible type of events in Tornado: deposit, withdrawal or fetch relayers
|
||||||
* @returns {Promise<string>} Full subgraph link
|
* @returns {Promise<string>} Full subgraph link
|
||||||
*/
|
*/
|
||||||
async function selectDefaultGraph(chainId, eventType) {
|
async function selectDefaultGraph(chainId, eventType){
|
||||||
let candidates = config.deployments[`netId${chainId}`].subgraphs;
|
let candidates = config.deployments[`netId${chainId}`].subgraphs;
|
||||||
if (eventType === "relayer") {
|
if (eventType === "relayer"){
|
||||||
if (chainId != 1) throw new Error("Relayer subgraph is available only for mainnet");
|
if (chainId != 1) throw new Error("Relayer subgraph is available only for mainnet");
|
||||||
candidates = config.deployments[`netId${chainId}`].relayerSubgraphs;
|
candidates = config.deployments[`netId${chainId}`].relayerSubgraphs;
|
||||||
query = '{ relayers(first: 10) { address, ensName, ensHash, blockRegistration } }'
|
query = '{ relayers(first: 10) { address, ensName, ensHash, blockRegistration } }'
|
||||||
@ -1066,14 +1072,14 @@ async function selectDefaultGraph(chainId, eventType) {
|
|||||||
else if (eventType === "deposit") query = `{ deposits(first: 1, orderBy: timestamp) { blockNumber, index } }`;
|
else if (eventType === "deposit") query = `{ deposits(first: 1, orderBy: timestamp) { blockNumber, index } }`;
|
||||||
else query = `{ withdrawals(first: 1, orderBy: timestamp) { timestamp } }`
|
else query = `{ withdrawals(first: 1, orderBy: timestamp) { timestamp } }`
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
for(const candidate of candidates) {
|
||||||
try {
|
try{
|
||||||
const response = await axios.post(candidate, { query }, globals.requestOptions);
|
const response = await axios.post(candidate, {query}, globals.requestOptions);
|
||||||
const result = response.data.data[`${eventType}s`];
|
const result = response.data.data[`${eventType}s`];
|
||||||
if (!result) throw new Error("Invalid response from subgraph");
|
if (!result) throw new Error("Invalid response from subgraph");
|
||||||
console.log(`Selected subgraph for ${eventType}s - ${candidate}`);
|
console.log(`Selected subgraph for ${eventType}s - ${candidate}`);
|
||||||
return candidate;
|
return candidate;
|
||||||
} catch (e) {
|
} catch(e){
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1087,7 +1093,7 @@ async function selectDefaultGraph(chainId, eventType) {
|
|||||||
* @param {string | number} chainId
|
* @param {string | number} chainId
|
||||||
* @returns {Promise<Array<Object>>} List of available relayers
|
* @returns {Promise<Array<Object>>} List of available relayers
|
||||||
*/
|
*/
|
||||||
async function getRelayers(chainId) {
|
async function getRelayers(chainId){
|
||||||
console.log("Fetching relayers...");
|
console.log("Fetching relayers...");
|
||||||
|
|
||||||
const MIN_STAKE_LISTED_BALANCE = '0X1B1AE4D6E2EF500000'; // 500 TORN
|
const MIN_STAKE_LISTED_BALANCE = '0X1B1AE4D6E2EF500000'; // 500 TORN
|
||||||
@ -1131,7 +1137,7 @@ async function getRelayers(chainId) {
|
|||||||
return validRelayers;
|
return validRelayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAvailableRelayersData(relayers) {
|
async function getAvailableRelayersData(relayers){
|
||||||
let statuses = [];
|
let statuses = [];
|
||||||
for (const relayer of relayers) {
|
for (const relayer of relayers) {
|
||||||
try {
|
try {
|
||||||
@ -1151,7 +1157,7 @@ async function getRelayers(chainId) {
|
|||||||
return statuses;
|
return statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
const registeredRelayers = await fetchEvents({ type: "relayer" });
|
const registeredRelayers = await fetchEvents({type: "relayer"});
|
||||||
// Some relayers can be unregistered and then registrered again
|
// Some relayers can be unregistered and then registrered again
|
||||||
const deduplicatedRelayers = registeredRelayers.filter((relayer, index, relayers) => index === relayers.findIndex(r => relayer.ensName === r.ensName));
|
const deduplicatedRelayers = registeredRelayers.filter((relayer, index, relayers) => index === relayers.findIndex(r => relayer.ensName === r.ensName));
|
||||||
const validRelayers = await getValidRelayers(deduplicatedRelayers, ensSubdomainKey);
|
const validRelayers = await getValidRelayers(deduplicatedRelayers, ensSubdomainKey);
|
||||||
@ -1223,12 +1229,12 @@ const sleep = ms => new Promise(r => setTimeout(r, ms));
|
|||||||
*/
|
*/
|
||||||
async function retryPostRequest(url, data, requestOptions, retryAttempts, waitingTimeIncrease = 2000) {
|
async function retryPostRequest(url, data, requestOptions, retryAttempts, waitingTimeIncrease = 2000) {
|
||||||
let retryAttempt = 0;
|
let retryAttempt = 0;
|
||||||
while (1) {
|
while (1){
|
||||||
await sleep(waitingTimeIncrease * retryAttempt);
|
await sleep(waitingTimeIncrease * retryAttempt);
|
||||||
try {
|
try{
|
||||||
return await axios.post(url, data, requestOptions);
|
return await axios.post(url, data, requestOptions);
|
||||||
} catch (e) {
|
} catch(e){
|
||||||
if (retryAttempt === retryAttempts) throw e;
|
if(retryAttempt === retryAttempts) throw e;
|
||||||
retryAttempt++;
|
retryAttempt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1241,7 +1247,7 @@ async function retryPostRequest(url, data, requestOptions, retryAttempts, waitin
|
|||||||
* @param {number | string} amount Tornado instance currency amount
|
* @param {number | string} amount Tornado instance currency amount
|
||||||
* @returns {string} Path to cache file
|
* @returns {string} Path to cache file
|
||||||
*/
|
*/
|
||||||
function getEventsFilePath(eventType, currency, amount) {
|
function getEventsFilePath(eventType, currency, amount){
|
||||||
return eventType === "relayer" ? "./cache/relayer/register.json" : `./cache/${globals.netName.toLowerCase()}/${eventType}s_${currency.toLowerCase()}_${amount}.json`;
|
return eventType === "relayer" ? "./cache/relayer/register.json" : `./cache/${globals.netName.toLowerCase()}/${eventType}s_${currency.toLowerCase()}_${amount}.json`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1274,7 +1280,7 @@ function loadCachedEvents({ type, currency, amount }) {
|
|||||||
* @returns {Promise<Array<Object>>} All events (cached and newly fetched)
|
* @returns {Promise<Array<Object>>} All events (cached and newly fetched)
|
||||||
*/
|
*/
|
||||||
async function fetchEvents({ type, currency, amount }) {
|
async function fetchEvents({ type, currency, amount }) {
|
||||||
if (currency) currency = currency.toLowerCase();
|
if(currency) currency = currency.toLowerCase();
|
||||||
if (type === 'withdraw') {
|
if (type === 'withdraw') {
|
||||||
type = 'withdrawal';
|
type = 'withdrawal';
|
||||||
}
|
}
|
||||||
@ -1286,7 +1292,7 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
const cachedEvents = loadCachedEvents({ type, currency, amount });
|
const cachedEvents = loadCachedEvents({ type, currency, amount });
|
||||||
const startBlock = cachedEvents.length ? cachedEvents[cachedEvents.length - 1].blockNumber + 1 : (type === "relayer" ? relayerRegistryDeployedBlockNumber : instanceDeployedBlockNumber);
|
const startBlock = cachedEvents.length ? cachedEvents[cachedEvents.length - 1].blockNumber + 1 : (type === "relayer" ? relayerRegistryDeployedBlockNumber : instanceDeployedBlockNumber);
|
||||||
|
|
||||||
if (type !== "relayer") {
|
if(type !== "relayer"){
|
||||||
console.log('Loaded cached', amount, currency.toUpperCase(), type, 'events for', startBlock, 'block');
|
console.log('Loaded cached', amount, currency.toUpperCase(), type, 'events for', startBlock, 'block');
|
||||||
console.log('Fetching', amount, currency.toUpperCase(), type, 'events for', netName, 'network');
|
console.log('Fetching', amount, currency.toUpperCase(), type, 'events for', netName, 'network');
|
||||||
}
|
}
|
||||||
@ -1300,9 +1306,9 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
if (type === 'relayer') fetchedEvents.sort((first, second) => first.blockRegistration - second.blockRegistration);
|
if (type === 'relayer') fetchedEvents.sort((first, second) => first.blockRegistration - second.blockRegistration);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const cachedEvents = loadCachedEvents({ type, currency, amount });
|
const cachedEvents = loadCachedEvents({type, currency, amount});
|
||||||
const events = cachedEvents.concat(fetchedEvents);
|
const events = cachedEvents.concat(fetchedEvents);
|
||||||
fs.writeFileSync(getEventsFilePath(type, currency, amount), JSON.stringify(events, null, 2), { flag: 'w+', encoding: 'utf-8' });
|
fs.writeFileSync(getEventsFilePath(type, currency, amount), JSON.stringify(events, null, 2), 'utf8');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
throw new Error('Writing cache file failed:', error);
|
throw new Error('Writing cache file failed:', error);
|
||||||
@ -1320,19 +1326,19 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
for (let i = startBlock; i < targetBlock; i += chunks) {
|
for (let i = startBlock; i < targetBlock; i += chunks) {
|
||||||
let mapFunction;
|
let mapFunction;
|
||||||
if (type === "relayer")
|
if (type === "relayer")
|
||||||
mapFunction = ({ blockNumber, returnValues: { relayer, relayerAddress, ensName } }) => ({ blockNumber, ensHash: relayer, ensName, address: relayerAddress });
|
mapFunction = ({ blockNumber, returnValues: {relayer, relayerAddress, ensName} }) => ({blockNumber, ensHash: relayer, ensName, address: relayerAddress});
|
||||||
else if (type === "deposit")
|
else if (type === "deposit")
|
||||||
mapFunction = ({ blockNumber, transactionHash, returnValues: { commitment, leafIndex, timestamp } }) =>
|
mapFunction = ({ blockNumber, transactionHash, returnValues: { commitment, leafIndex, timestamp } }) =>
|
||||||
({ blockNumber, transactionHash, commitment, leafIndex: Number(leafIndex), timestamp: Number(timestamp) });
|
({blockNumber, transactionHash, commitment, leafIndex: Number(leafIndex), timestamp: Number(timestamp)});
|
||||||
else mapFunction = ({ blockNumber, transactionHash, returnValues: { nullifierHash, to, fee } }) => ({ blockNumber, transactionHash, nullifierHash, to, fee });
|
else mapFunction = ({ blockNumber, transactionHash, returnValues: {nullifierHash, to, fee} }) => ({blockNumber, transactionHash, nullifierHash, to, fee});
|
||||||
|
|
||||||
const finalBlock = Math.min(i + chunks - 1, targetBlock);
|
const finalBlock = Math.min(i + chunks - 1, targetBlock);
|
||||||
try {
|
try{
|
||||||
const fetchedEvents = await contract.getPastEvents(eventNameInContract, { fromBlock: i, toBlock: finalBlock });
|
const fetchedEvents = await contract.getPastEvents(eventNameInContract, {fromBlock: i, toBlock: finalBlock});
|
||||||
console.log('Fetched', type === "relayer" ? type : `${amount} ${currency.toUpperCase()} ${type}`, 'events to block:', finalBlock);
|
console.log('Fetched', type === "relayer" ? type : `${amount} ${currency.toUpperCase()} ${type}`, 'events to block:', finalBlock);
|
||||||
if (fetchedEvents.length === 0) continue;
|
if(fetchedEvents.length === 0) continue;
|
||||||
await updateCache(fetchedEvents.map(mapFunction));
|
await updateCache(fetchedEvents.map(mapFunction));
|
||||||
} catch (err) {
|
} catch(err){
|
||||||
console.error(`Failed fetching ${type} events from node on block ${i}: `, err)
|
console.error(`Failed fetching ${type} events from node on block ${i}: `, err)
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@ -1367,7 +1373,7 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
address, ensName, ensHash, blockRegistration
|
address, ensName, ensHash, blockRegistration
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
mapFunction = ({ blockRegistration, address, ensName, ensHash }) => ({ address, ensHash, ensName, blockNumber: Number(blockRegistration) });
|
mapFunction = ({blockRegistration, address, ensName, ensHash}) => ({address, ensHash, ensName, blockNumber: Number(blockRegistration)});
|
||||||
}
|
}
|
||||||
else if (type === 'deposit') {
|
else if (type === 'deposit') {
|
||||||
query = `
|
query = `
|
||||||
@ -1376,7 +1382,7 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
blockNumber, transactionHash, commitment, index
|
blockNumber, transactionHash, commitment, index
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
mapFunction = ({ blockNumber, transactionHash, commitment, index }) => ({ blockNumber: Number(blockNumber), transactionHash, commitment, leafIndex: Number(index) });
|
mapFunction = ({ blockNumber, transactionHash, commitment, index }) => ({blockNumber: Number(blockNumber), transactionHash, commitment, leafIndex: Number(index)});
|
||||||
}
|
}
|
||||||
else if (type === "withdrawal") {
|
else if (type === "withdrawal") {
|
||||||
query = `
|
query = `
|
||||||
@ -1385,10 +1391,10 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
blockNumber, transactionHash, nullifier, to, fee
|
blockNumber, transactionHash, nullifier, to, fee
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
mapFunction = ({ blockNumber, transactionHash, nullifier, to, fee }) => ({ blockNumber: Number(blockNumber), transactionHash, nullifierHash: nullifier, to, fee });
|
mapFunction = ({ blockNumber, transactionHash, nullifier, to, fee }) => ({blockNumber: Number(blockNumber), transactionHash, nullifierHash: nullifier, to, fee});
|
||||||
}
|
}
|
||||||
|
|
||||||
const querySubgraph = await retryPostRequest(subgraph, { query, variables }, globals.requestOptions, 3);
|
const querySubgraph = await retryPostRequest(subgraph, {query, variables}, globals.requestOptions, 3);
|
||||||
const queryResult = querySubgraph.data.data[`${type}s`];
|
const queryResult = querySubgraph.data.data[`${type}s`];
|
||||||
return queryResult.map(mapFunction);
|
return queryResult.map(mapFunction);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -1400,11 +1406,11 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
console.log('Querying latest events from subgraph');
|
console.log('Querying latest events from subgraph');
|
||||||
const latestBlock = await web3Instance.getBlockNumber();
|
const latestBlock = await web3Instance.getBlockNumber();
|
||||||
try {
|
try {
|
||||||
for (let i = startBlock; i < latestBlock;) {
|
for (let i = startBlock; i < latestBlock; ) {
|
||||||
let result = await queryFromGraph(i);
|
let result = await queryFromGraph(i);
|
||||||
if (Object.keys(result).length === 0) break;
|
if (Object.keys(result).length === 0) break;
|
||||||
const resultBlockNumber = result[result.length - 1].blockNumber;
|
const resultBlockNumber = result[result.length - 1].blockNumber;
|
||||||
while (result.length > 0 && result[result.length - 1].blockNumber === resultBlockNumber) result.pop();
|
while(result.length > 0 && result[result.length - 1].blockNumber === resultBlockNumber) result.pop();
|
||||||
result = result.concat(await queryFromGraph(resultBlockNumber, ""));
|
result = result.concat(await queryFromGraph(resultBlockNumber, ""));
|
||||||
await updateCache(result);
|
await updateCache(result);
|
||||||
i = resultBlockNumber;
|
i = resultBlockNumber;
|
||||||
@ -1423,7 +1429,7 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
await syncEvents();
|
await syncEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedEvents = loadCachedEvents({ type, currency, amount })
|
const updatedEvents = loadCachedEvents({type, currency, amount})
|
||||||
const updatedBlock = updatedEvents[updatedEvents.length - 1].blockNumber;
|
const updatedBlock = updatedEvents[updatedEvents.length - 1].blockNumber;
|
||||||
console.log('Cache updated for Tornado', type === 'relayer' ? type : `${amount} ${currency.toUpperCase()} instance to block`, updatedBlock, 'successfully');
|
console.log('Cache updated for Tornado', type === 'relayer' ? type : `${amount} ${currency.toUpperCase()} instance to block`, updatedBlock, 'successfully');
|
||||||
console.log(`Total ${type}s:`, updatedEvents.length - 1);
|
console.log(`Total ${type}s:`, updatedEvents.length - 1);
|
||||||
@ -1434,10 +1440,12 @@ async function fetchEvents({ type, currency, amount }) {
|
|||||||
* Parses Tornado Cash note
|
* Parses Tornado Cash note
|
||||||
* @param {string} noteString the 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 noteRegex = /tornado-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<note>[0-9a-fA-F]{124})/g;
|
||||||
const match = noteRegex.exec(noteString);
|
const match = noteRegex.exec(noteString);
|
||||||
if (!match) {
|
if (!match)
|
||||||
|
{
|
||||||
throw new Error('The note has invalid format');
|
throw new Error('The note has invalid format');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1480,7 +1488,7 @@ function parseInvoice(invoiceString) {
|
|||||||
|
|
||||||
async function loadDepositData({ amount, currency, deposit }) {
|
async function loadDepositData({ amount, currency, deposit }) {
|
||||||
const { web3Instance, tornadoInstanceContract } = globals;
|
const { web3Instance, tornadoInstanceContract } = globals;
|
||||||
const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount });
|
const cachedEvents = await fetchEvents({ type: 'deposit', currency, amount});
|
||||||
const depositEvent = cachedEvents.find(event => event.commitment === deposit.commitmentHex);
|
const depositEvent = cachedEvents.find(event => event.commitment === deposit.commitmentHex);
|
||||||
if (!depositEvent) throw new Error('There is no related deposit, the note is invalid');
|
if (!depositEvent) throw new Error('There is no related deposit, the note is invalid');
|
||||||
|
|
||||||
@ -1537,119 +1545,13 @@ async function promptConfirmation(query) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Stake TORN tokens in Governance contract to earn rewards from withdrawals and perticate in Governance with voting
|
|
||||||
* @param {number | string} amount Amount of tokens. Can be fractional, for example stake 100.8432 TORN
|
|
||||||
*/
|
|
||||||
async function stakeTorn(amount) {
|
|
||||||
const { tornTokenContract, governanceContract, signerAddress } = globals;
|
|
||||||
const tokenAmount = fromDecimals({ amount, decimals: 18 });
|
|
||||||
const allowance = await tornTokenContract.methods.allowance(signerAddress, governanceAddress).call();
|
|
||||||
console.log('Current TORN allowance is', fromWei(allowance));
|
|
||||||
if (toBN(allowance).lt(toBN(tokenAmount))) {
|
|
||||||
console.log('Approving tokens for stake');
|
|
||||||
await generateTransaction(tornTokenAddress, tornTokenContract.methods.approve(governanceAddress, tokenAmount).encodeABI(), 0, 'send');
|
|
||||||
}
|
|
||||||
console.log("Sending stake transaction...");
|
|
||||||
await generateTransaction(governanceAddress, governanceContract.methods.lockWithApproval(tokenAmount).encodeABI(), 0, 'send');
|
|
||||||
|
|
||||||
const stakedAmount = await governanceContract.methods.lockedBalance(signerAddress).call();
|
|
||||||
console.log("Staked successfull: your current stake balance is", fromWei(stakedAmount), "TORN");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Withdraw TORN tokens from Governance staking (without rewards)
|
|
||||||
* @param {number | string} amount Amount of TORn tokens to withdraw, can be fractional
|
|
||||||
*/
|
|
||||||
async function unstakeTorn(amount) {
|
|
||||||
const { governanceContract, signerAddress } = globals;
|
|
||||||
const tokenAmount = fromDecimals({ amount, decimals: 18 });
|
|
||||||
const stakedAmount = await governanceContract.methods.lockedBalance(signerAddress).call();
|
|
||||||
if (toBN(stakedAmount).lt(toBN(tokenAmount))) throw new Error(`Not enough tokens in stake. You have ${fromWei(stakedAmount)} tokens, but you're trying to withdraw ${amount}.`);
|
|
||||||
|
|
||||||
console.log("Sending unstake transaction...");
|
|
||||||
await generateTransaction(governanceAddress, governanceContract.methods.unlock(tokenAmount).encodeABI(), 0, 'send');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delegate voting power in Tornado Cash governance to another address: delegatee can vote and create proposals on your behalf
|
|
||||||
* @param {string} address Delegatee address
|
|
||||||
*/
|
|
||||||
async function delegate(address) {
|
|
||||||
if (!web3Utils.isAddress(address)) throw new Error("Cannot delegate: invalid delegatee address provided");
|
|
||||||
|
|
||||||
await generateTransaction(governanceAddress, globals.governanceContract.methods.delegate(address).encodeABI(), 0, 'send');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove Tornado Cash governance delegation. After doing it, nobody can vote or create proposals on your behalf
|
|
||||||
*/
|
|
||||||
async function undelegate() {
|
|
||||||
const { governanceContract, signerAddress } = globals;
|
|
||||||
const currentDelegatee = await governanceContract.methods.delegatedTo(signerAddress).call();
|
|
||||||
if (currentDelegatee.toLowerCase() === "0x0000000000000000000000000000000000000000") {
|
|
||||||
console.log("No actual delegatee: already undelegated");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await generateTransaction(governanceAddress, governanceContract.methods.undelegate().encodeABI(), 0, 'send');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads actual data from contract and prints information about Tornado Cash staking for specified address: stake amount, unclaimed staking rewards and voting power delegation
|
|
||||||
* @param {string} address
|
|
||||||
*/
|
|
||||||
async function printStakeInfo(address) {
|
|
||||||
if (!web3Utils.isAddress(address)) throw new Error("Cannot check stake info: invalid address provided");
|
|
||||||
|
|
||||||
const { governanceContract, stakingRewardsContract } = globals;
|
|
||||||
|
|
||||||
const stakedAmount = await governanceContract.methods.lockedBalance(address).call();
|
|
||||||
const rewardsAmount = await stakingRewardsContract.methods.checkReward(address).call();
|
|
||||||
const delegatee = await governanceContract.methods.delegatedTo(address).call();
|
|
||||||
|
|
||||||
console.log('\n====================Staking info====================');
|
|
||||||
console.log('Account :', address);
|
|
||||||
console.log('Staked balance :', `${fromWei(stakedAmount)} TORN`);
|
|
||||||
console.log('Unclaimed rewards :', `${fromWei(rewardsAmount)} TORN`);
|
|
||||||
console.log('Delegation status :', delegatee.toLowerCase() === "0x0000000000000000000000000000000000000000" ? "not delegated" : `voting power delegated to ${delegatee}`);
|
|
||||||
console.log('====================================================', '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Vote in governance from signer address with all staked tokens for or against specified proposal by ID
|
|
||||||
* @param {string | number} proposalId Proposal ID
|
|
||||||
* @param {string} decision For or against proposal ("yes" is for, "no" is against, true is for, false is against)
|
|
||||||
*/
|
|
||||||
async function vote(proposalId, decision){
|
|
||||||
const { governanceContract, signerAddress } = globals;
|
|
||||||
|
|
||||||
const signerStakedBalance = await governanceContract.methods.lockedBalance(signerAddress).call();
|
|
||||||
if (signerStakedBalance.lte(0)) throw new Error("You have no staked balance, therefore you cannot vote.");
|
|
||||||
|
|
||||||
let support;
|
|
||||||
if (decision === "yes" || decision === "for") support = true;
|
|
||||||
else if (decision === "no" || decision === "against") support = false;
|
|
||||||
else throw new Error("Invalid user decision: cannot vote for or against proposal");
|
|
||||||
|
|
||||||
|
|
||||||
await generateTransaction(governanceAddress, governanceContract.methods.castVote(Number(proposalId), support).encodeABI(), 0, 'send');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiate transaction to claim staking rewards from Tornado Cash staking
|
|
||||||
*/
|
|
||||||
async function claimStakingRewards(){
|
|
||||||
await generateTransaction(stakingRewardsAddress, globals.stakingRewardsContract.methods.getReward().encodeABI(), 0, 'send');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create web3 eth instance with provider using RPC link
|
* Create web3 eth instance with provider using RPC link
|
||||||
* @param {string} rpc Full RPC link
|
* @param {string} rpc Full RPC link
|
||||||
* @returns {Promise<Web3Eth>} Initialized Web3 instance object
|
* @returns {Promise<Web3Eth>} Initialized Web3 instance object
|
||||||
*/
|
*/
|
||||||
async function createWeb3Instance(rpc) {
|
async function createWeb3Instance(rpc){
|
||||||
const { torPort } = globals;
|
const { torPort }= globals;
|
||||||
|
|
||||||
let web3;
|
let web3;
|
||||||
if (torPort && rpc.startsWith('https')) {
|
if (torPort && rpc.startsWith('https')) {
|
||||||
@ -1670,26 +1572,12 @@ async function createWeb3Instance(rpc) {
|
|||||||
web3 = new Web3(new Web3.providers.WebsocketProvider(rpc, web3Options), null, { transactionConfirmationBlocks: 1 });
|
web3 = new Web3(new Web3.providers.WebsocketProvider(rpc, web3Options), null, { transactionConfirmationBlocks: 1 });
|
||||||
} else {
|
} else {
|
||||||
console.log(`Connecting to remote node ${rpc}`);
|
console.log(`Connecting to remote node ${rpc}`);
|
||||||
web3 = new Web3(new Web3.providers.HttpProvider(rpc, { timeout: 10000, keepAlive: true }), null, { transactionConfirmationBlocks: 1 });
|
web3 = new Web3(new Web3.providers.HttpProvider(rpc, {timeout: 10000, keepAlive: true}), null, { transactionConfirmationBlocks: 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
return web3.eth;
|
return web3.eth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize TORN contracts and then call initNetwork
|
|
||||||
* @param {Object} args Arguments to pass to initNetwork function
|
|
||||||
*/
|
|
||||||
async function initTorn(args) {
|
|
||||||
initPreferences(args);
|
|
||||||
await initNetwork({ ...args, chainId: 1, onlyRpc: true });
|
|
||||||
const { web3Instance } = globals;
|
|
||||||
|
|
||||||
globals.governanceContract = new web3Instance.Contract(tornadoGovernanceAbi, governanceAddress);
|
|
||||||
globals.tornTokenContract = new web3Instance.Contract(erc20Abi, tornTokenAddress);
|
|
||||||
globals.stakingRewardsContract = new web3Instance.Contract(stakingRewardsAbi, stakingRewardsAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init web3 network from user parameters for all program
|
* Init web3 network from user parameters for all program
|
||||||
* @param {Object} args Arguments
|
* @param {Object} args Arguments
|
||||||
@ -1701,7 +1589,7 @@ async function initTorn(args) {
|
|||||||
* @param {EventType} [args.eventType] Applicable event type for user actions
|
* @param {EventType} [args.eventType] Applicable event type for user actions
|
||||||
* @param {string} [relayer] User-provided relayer link
|
* @param {string} [relayer] User-provided relayer link
|
||||||
*/
|
*/
|
||||||
async function initNetwork({ rpc, chainId, privateKey, torPort, onlyRpc, eventType, relayer }) {
|
async function initNetwork({rpc, chainId, privateKey, torPort, onlyRpc, eventType, relayer}) {
|
||||||
|
|
||||||
if (torPort) {
|
if (torPort) {
|
||||||
globals.torPort = torPort;
|
globals.torPort = torPort;
|
||||||
@ -1714,7 +1602,7 @@ async function initNetwork({ rpc, chainId, privateKey, torPort, onlyRpc, eventTy
|
|||||||
|
|
||||||
if (chainId && !rpc) {
|
if (chainId && !rpc) {
|
||||||
const subgraphUrl = onlyRpc ? null : await selectDefaultGraph(chainId, eventType)
|
const subgraphUrl = onlyRpc ? null : await selectDefaultGraph(chainId, eventType)
|
||||||
rpc = await selectDefaultRpc(chainId, eventType, !!subgraphUrl)
|
rpc = await selectDefaultRpc(chainId, eventType, subgraphUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
globals.web3Instance = await createWeb3Instance(rpc)
|
globals.web3Instance = await createWeb3Instance(rpc)
|
||||||
@ -1725,7 +1613,7 @@ async function initNetwork({ rpc, chainId, privateKey, torPort, onlyRpc, eventTy
|
|||||||
globals.feeOracle = Number(globals.netId) === 1 ? new TornadoFeeOracleV4(globals.netId, rpc) : new TornadoFeeOracleV5(globals.netId, rpc);
|
globals.feeOracle = Number(globals.netId) === 1 ? new TornadoFeeOracleV4(globals.netId, rpc) : new TornadoFeeOracleV5(globals.netId, rpc);
|
||||||
|
|
||||||
// Create web3 instance to fetch relayer on mainnet, if user want to get relayers list or withdraw, but he didn't provide relayer link
|
// Create web3 instance to fetch relayer on mainnet, if user want to get relayers list or withdraw, but he didn't provide relayer link
|
||||||
if (!relayer && !privateKey && (eventType === 'relayer' || eventType === 'withdrawal')) {
|
if (!relayer && !privateKey && (eventType === 'relayer' || eventType === 'withdrawal')){
|
||||||
if (globals.netId === 1) globals.relayerWeb3Instance = globals.web3Instance;
|
if (globals.netId === 1) globals.relayerWeb3Instance = globals.web3Instance;
|
||||||
else {
|
else {
|
||||||
const subgraphUrl = onlyRpc ? null : await selectDefaultGraph(1, 'relayer');
|
const subgraphUrl = onlyRpc ? null : await selectDefaultGraph(1, 'relayer');
|
||||||
@ -1769,7 +1657,7 @@ async function initNetwork({ rpc, chainId, privateKey, torPort, onlyRpc, eventTy
|
|||||||
* @param {boolean} [userPreferences.nonconfirmation] Don't ask for confirmation for crucial actions
|
* @param {boolean} [userPreferences.nonconfirmation] Don't ask for confirmation for crucial actions
|
||||||
* @param {boolean} [userPreferences.localMode] Don't submit signed transactions to blockchain (remote nodes)
|
* @param {boolean} [userPreferences.localMode] Don't submit signed transactions to blockchain (remote nodes)
|
||||||
*/
|
*/
|
||||||
function initPreferences({ nonconfirmation, localMode }) {
|
function initPreferences({nonconfirmation, localMode}){
|
||||||
if (nonconfirmation) {
|
if (nonconfirmation) {
|
||||||
console.log("Non-confirmation mode detected: program won't ask confirmation for crucial actions")
|
console.log("Non-confirmation mode detected: program won't ask confirmation for crucial actions")
|
||||||
globals.shouldPromptConfirmation = false;
|
globals.shouldPromptConfirmation = false;
|
||||||
@ -1783,11 +1671,11 @@ function initPreferences({ nonconfirmation, localMode }) {
|
|||||||
/**
|
/**
|
||||||
* Init web3, all Tornado contracts, and snark
|
* Init web3, all Tornado contracts, and snark
|
||||||
*/
|
*/
|
||||||
async function init({ rpc, chainId, currency = 'dai', amount = '100', privateKey, torPort, onlyRpc, nonconfirmation, localMode, eventType, relayer }) {
|
async function init({ rpc, chainId, currency = 'dai', amount = '100', privateKey, torPort, onlyRpc, nonconfirmation, localMode, eventType, relayer}) {
|
||||||
currency = currency.toLowerCase()
|
currency = currency.toLowerCase()
|
||||||
|
|
||||||
initPreferences({ nonconfirmation, localMode });
|
initPreferences({nonconfirmation, localMode});
|
||||||
await initNetwork({ rpc, chainId, privateKey, torPort, onlyRpc, eventType, relayer });
|
await initNetwork({rpc, chainId, privateKey, torPort, onlyRpc, eventType, relayer});
|
||||||
|
|
||||||
const { netId, web3Instance } = globals;
|
const { netId, web3Instance } = globals;
|
||||||
// console.log(netId, chainId);
|
// console.log(netId, chainId);
|
||||||
@ -1841,7 +1729,7 @@ async function main() {
|
|||||||
.action(async (noteString, recipient, refund) => {
|
.action(async (noteString, recipient, refund) => {
|
||||||
const { currency, amount, netId, deposit } = parseNote(noteString);
|
const { currency, amount, netId, deposit } = parseNote(noteString);
|
||||||
|
|
||||||
await init({ ...program, chainId: netId, currency, amount, eventType: 'withdrawal' });
|
await init({...program, chainId: netId, currency, amount, eventType: 'withdrawal'});
|
||||||
|
|
||||||
await withdraw({
|
await withdraw({
|
||||||
deposit,
|
deposit,
|
||||||
@ -1853,94 +1741,6 @@ async function main() {
|
|||||||
relayerURL: program.relayer
|
relayerURL: program.relayer
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
program
|
|
||||||
.command('compliance <note>')
|
|
||||||
.description(
|
|
||||||
'Shows the deposit and withdrawal of the provided note. This might be necessary to show the origin of assets held in your withdrawal address.'
|
|
||||||
)
|
|
||||||
.action(async (noteString) => {
|
|
||||||
|
|
||||||
const { currency, amount, netId, deposit } = parseNote(noteString);
|
|
||||||
|
|
||||||
await init({ ...program, chainId: netId, currency, amount, eventType: 'withdrawal', relayer: "dummy" });
|
|
||||||
|
|
||||||
const depositInfo = await loadDepositData({ amount, currency, deposit });
|
|
||||||
const withdrawInfo = await loadWithdrawalData({ amount, currency, deposit });
|
|
||||||
|
|
||||||
const depositDate = new Date(depositInfo.timestamp * 1000);
|
|
||||||
console.log('\n=============Deposit=================');
|
|
||||||
console.log('Deposit :', amount, currency.toUpperCase());
|
|
||||||
console.log('Date :', depositDate.toLocaleDateString(), depositDate.toLocaleTimeString());
|
|
||||||
console.log('From :', `https://${getExplorerLink()}/address/${depositInfo.from}`);
|
|
||||||
console.log('Transaction :', `https://${getExplorerLink()}/tx/${depositInfo.txHash}`);
|
|
||||||
console.log('Commitment :', depositInfo.commitment);
|
|
||||||
console.log('Spent :', depositInfo.isSpent);
|
|
||||||
console.log('=====================================', '\n');
|
|
||||||
|
|
||||||
if (!depositInfo.isSpent) {
|
|
||||||
console.log('The note was not spent!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const withdrawalDate = new Date(withdrawInfo.timestamp * 1000);
|
|
||||||
console.log('\n=============Withdrawal==============');
|
|
||||||
console.log('Withdrawal :', withdrawInfo.amount, currency);
|
|
||||||
console.log('Relayer Fee :', withdrawInfo.fee, currency);
|
|
||||||
console.log('Date :', withdrawalDate.toLocaleDateString(), withdrawalDate.toLocaleTimeString());
|
|
||||||
console.log('To :', `https://${getExplorerLink()}/address/${withdrawInfo.to}`);
|
|
||||||
console.log('Transaction :', `https://${getExplorerLink()}/tx/${withdrawInfo.txHash}`);
|
|
||||||
console.log('Nullifier :', withdrawInfo.nullifier);
|
|
||||||
console.log('=====================================', '\n');
|
|
||||||
});
|
|
||||||
program
|
|
||||||
.command("stake <amount>")
|
|
||||||
.description("Stake TORN tokens in Governance contract to earn rewards and vote. Requires private key")
|
|
||||||
.action(async (amount) => {
|
|
||||||
await initTorn(program);
|
|
||||||
await stakeTorn(Number(amount));
|
|
||||||
})
|
|
||||||
program
|
|
||||||
.command("unstake <amount>")
|
|
||||||
.description("Unstake TORN tokens (withdraw from Governance staking). Requires private key")
|
|
||||||
.action(async (amount) => {
|
|
||||||
await initTorn(program);
|
|
||||||
await unstakeTorn(amount);
|
|
||||||
})
|
|
||||||
program
|
|
||||||
.command("checkStake <address>")
|
|
||||||
.description("Check Tornado Cash staking information about provided address: stake amount, unclaimed staking rewards and voting power delegation")
|
|
||||||
.action(async (address) => {
|
|
||||||
await initTorn(program);
|
|
||||||
await printStakeInfo(address);
|
|
||||||
});
|
|
||||||
program
|
|
||||||
.command("claim")
|
|
||||||
.description("Claim staking rewards. Requires private key")
|
|
||||||
.action(async () => {
|
|
||||||
await initTorn(program);
|
|
||||||
await claimStakingRewards();
|
|
||||||
})
|
|
||||||
program
|
|
||||||
.command("vote <decision> <proposal_id>")
|
|
||||||
.description("Vote for or against Tornado Cash governance proposal with all staked tokens. Decision can be `yes/for` or `no/against`. To change your vote, just use this function again with different decision")
|
|
||||||
.action(async (decision, proposalId) => {
|
|
||||||
await initTorn(program);
|
|
||||||
await vote(proposalId, decision.toLowerCase())
|
|
||||||
})
|
|
||||||
program
|
|
||||||
.command("delegate <address>")
|
|
||||||
.description("Delegate voting power to another address. Requires private key")
|
|
||||||
.action(async (address) => {
|
|
||||||
await initTorn(program);
|
|
||||||
await delegate(address);
|
|
||||||
});
|
|
||||||
program
|
|
||||||
.command("undelegate")
|
|
||||||
.description("Remove current delegatee (nobody can vote or create proposals on your behalf after it). Requires private key")
|
|
||||||
.action(async () => {
|
|
||||||
await initTorn(program);
|
|
||||||
await undelegate();
|
|
||||||
});
|
|
||||||
program
|
program
|
||||||
.command('createNote <currency> <amount> <chainId>')
|
.command('createNote <currency> <amount> <chainId>')
|
||||||
.description(
|
.description(
|
||||||
@ -1970,15 +1770,15 @@ async function main() {
|
|||||||
.command("listRelayers <chain_id>")
|
.command("listRelayers <chain_id>")
|
||||||
.description("Check available relayers on selected chain. If you wantue non-default RPC, you should provide ONLY mainnet RPC urls")
|
.description("Check available relayers on selected chain. If you wantue non-default RPC, you should provide ONLY mainnet RPC urls")
|
||||||
.action(async (chainId) => {
|
.action(async (chainId) => {
|
||||||
await initNetwork({ ...program, chainId: 1, eventType: 'relayer' })
|
await initNetwork({...program, chainId: 1, eventType: 'relayer'})
|
||||||
const availableRelayers = await getRelayers(chainId);
|
const availableRelayers = await getRelayers(chainId);
|
||||||
console.log("There are " + availableRelayers.length + " available relayers")
|
console.log("There are " + availableRelayers.length + " available relayers")
|
||||||
|
|
||||||
for (const relayer of availableRelayers) {
|
for(const relayer of availableRelayers){
|
||||||
console.log({
|
console.log({
|
||||||
'hostname': 'https://' + relayer.hostname + '/',
|
'hostname': 'https://' + relayer.hostname + '/',
|
||||||
'ensName': relayer.ensName,
|
'ensName': relayer.ensName,
|
||||||
'stakeBalance': Number(web3Utils.fromWei(relayer.stakeBalance, 'ether')).toFixed(2) + " TORN",
|
'stakeBalance': Number(web3Utils.fromWei(relayer.stakeBalance, 'ether')).toFixed(2)+" TORN",
|
||||||
'tornadoServiceFee': relayer.tornadoServiceFee + "%"
|
'tornadoServiceFee': relayer.tornadoServiceFee + "%"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2014,13 +1814,52 @@ async function main() {
|
|||||||
await initNetwork(program);
|
await initNetwork(program);
|
||||||
await submitTransaction(signedTX);
|
await submitTransaction(signedTX);
|
||||||
});
|
});
|
||||||
|
program
|
||||||
|
.command('compliance <note>')
|
||||||
|
.description(
|
||||||
|
'Shows the deposit and withdrawal of the provided note. This might be necessary to show the origin of assets held in your withdrawal address.'
|
||||||
|
)
|
||||||
|
.action(async (noteString) => {
|
||||||
|
|
||||||
|
const { currency, amount, netId, deposit } = parseNote(noteString);
|
||||||
|
|
||||||
|
await init({ ...program, chainId: netId, currency, amount, eventType: 'withdrawal', relayer: "dummy"});
|
||||||
|
|
||||||
|
const depositInfo = await loadDepositData({ amount, currency, deposit });
|
||||||
|
const withdrawInfo = await loadWithdrawalData({ amount, currency, deposit });
|
||||||
|
|
||||||
|
const depositDate = new Date(depositInfo.timestamp * 1000);
|
||||||
|
console.log('\n=============Deposit=================');
|
||||||
|
console.log('Deposit :', amount, currency.toUpperCase());
|
||||||
|
console.log('Date :', depositDate.toLocaleDateString(), depositDate.toLocaleTimeString());
|
||||||
|
console.log('From :', `https://${getExplorerLink()}/address/${depositInfo.from}`);
|
||||||
|
console.log('Transaction :', `https://${getExplorerLink()}/tx/${depositInfo.txHash}`);
|
||||||
|
console.log('Commitment :', depositInfo.commitment);
|
||||||
|
console.log('Spent :', depositInfo.isSpent);
|
||||||
|
console.log('=====================================', '\n');
|
||||||
|
|
||||||
|
if (!depositInfo.isSpent) {
|
||||||
|
console.log('The note was not spent!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const withdrawalDate = new Date(withdrawInfo.timestamp * 1000);
|
||||||
|
console.log('\n=============Withdrawal==============');
|
||||||
|
console.log('Withdrawal :', withdrawInfo.amount, currency);
|
||||||
|
console.log('Relayer Fee :', withdrawInfo.fee, currency);
|
||||||
|
console.log('Date :', withdrawalDate.toLocaleDateString(), withdrawalDate.toLocaleTimeString());
|
||||||
|
console.log('To :', `https://${getExplorerLink()}/address/${withdrawInfo.to}`);
|
||||||
|
console.log('Transaction :', `https://${getExplorerLink()}/tx/${withdrawInfo.txHash}`);
|
||||||
|
console.log('Nullifier :', withdrawInfo.nullifier);
|
||||||
|
console.log('=====================================', '\n');
|
||||||
|
});
|
||||||
program
|
program
|
||||||
.command('syncEvents <type> <currency> <amount> [chain_id]')
|
.command('syncEvents <type> <currency> <amount> [chain_id]')
|
||||||
.description('Sync the local cache file of deposit / withdrawal events for specific currency.')
|
.description('Sync the local cache file of deposit / withdrawal events for specific currency.')
|
||||||
.action(async (type, currency, amount, chainId) => {
|
.action(async (type, currency, amount, chainId) => {
|
||||||
console.log('Starting event sync command');
|
console.log('Starting event sync command');
|
||||||
|
|
||||||
await init({ ...program, currency, amount, chainId });
|
await init({ ...program, currency, amount, chainId});
|
||||||
if (type === "withdraw") type === "withdrawal";
|
if (type === "withdraw") type === "withdrawal";
|
||||||
|
|
||||||
const cachedEvents = await fetchEvents({ type, currency, amount });
|
const cachedEvents = await fetchEvents({ type, currency, amount });
|
||||||
|
|||||||
BIN
output/tornado-cli.exe
Normal file
BIN
output/tornado-cli.exe
Normal file
Binary file not shown.
BIN
tornado-cli.exe
BIN
tornado-cli.exe
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user