tornado-withdraw/index.html

1676 lines
82 KiB
HTML
Raw Normal View History

2024-10-08 03:21:59 +03:00
<!doctype html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Tornado Withdraw</title>
<link rel="icon" type="image/png" href="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/torn2.png">
<meta name="description" content="Tornado Withdraw - Open Source Withdrawal UI for Tornado Cash">
<meta property="og:title" content="Tornado Withdraw">
<meta property="og:description" content="Tornado Withdraw - Open Source Withdrawal UI for Tornado Cash">
<meta property="og:image" content="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/tw.png">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/bootstrap.css" integrity="sha384-fFdbKP4R+XqHQe6s9a3iwvJNSdnss6J7lrJrXGOUQiVdgax4hQruz6q/ay6OVpte" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" integrity="sha384-XGjxtQfXaH2tnPFa9x+ruJTuLE3Aa6LhHSWRr1XeTyhezb4abCG4ccI5AkVDxqC+" crossorigin="anonymous">
<script>
window.process = {
browser: true,
env: {},
};
</script>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js" integrity="sha384-1H217gwSVyLSIfaLxHbE7dRb3v4mYCKbpQvzx0cegeju1MVsGrX5xXxAvs/HgeFs" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/ethers@6.13.2/dist/ethers.umd.min.js" integrity="sha384-gpR0Q6Hx/O+uevlbpbANbS0LWjbejPV1sqD/8w422l/fW8whGY0EPmKw3uG7ACYP" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.30.1/moment.min.js" integrity="sha384-aQgnUSsW4D+imRFZ/dILN0wXp3MGO6RE3ccC/gZHr6BQzvhwzD+Bzon5C+kO3NHQ" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/tornado.umd.js" integrity="sha384-+3lhzvvDsVKE0kaNPlTbaY7VzjhrETPfBpvSeUEmYpuwZSJPMjk0z9JEU8FTF/tn" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/tornadoContracts.umd.js" integrity="sha384-iCyap5fZX6deuZ5dxb52Aa5j3/rJ/lqfIU9LGr8ZF0nKBmEqCkvJMdS79pPM2X1u" crossorigin="anonymous"></script>
<style>
@media (min-width: 1100px) {
.container {
width: 1100px;
}
}
@media (min-width: 768px) {
.navbar-mobile {
display: none !important;
}
}
.navbar-mobile {
flex-basis: 100%;
flex-grow: 1;
align-items: center;
}
.mb-5-super {
margin-bottom: 0.5rem !important;
}
.logo {
max-width: 40px;
max-height: 40px;
}
.loader {
animation: rotation 2s infinite linear;
}
.status {
display: block;
margin-top: 20px;
margin-bottom: 10px;
margin-left: auto;
margin-right: auto;
width: 100px;
}
@keyframes rotation {
from {
transform: rotate(359deg);
}
to {
transform: rotate(0deg);
}
}
</style>
<script>
/*global $, bootstrap, ethers, Tornado, TornadoContracts, moment*/
const VERSION = '1.0.0';
const DONATION_ADDRESS = '0x40c3d1656a26C9266f4A10fed0D87EFf79F54E64';
const DEFAULT_GAS_LIMIT = 600_000;
2024-10-08 17:42:36 +03:00
const JSDELIVR = `https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1`;
2024-10-08 03:21:59 +03:00
const hashes = {
'static/bootstrap.css': 'sha384-fFdbKP4R+XqHQe6s9a3iwvJNSdnss6J7lrJrXGOUQiVdgax4hQruz6q/ay6OVpte',
'static/bootstrap.css.map': 'sha384-j26wcRYDZq3IKjEVNqnOwbDwbzbuyl21J7osOB66qzfGSQTHCDo6/7ucE8tZL6jL',
'static/bootstrap.scss': 'sha384-lKTG095qkOEok4Z+wqVgOMJs+nCLs1IEhOSiK1E8zi6aKy9e05b5n4o1KZZG5klW',
'static/merkleTreeWorker.umd.js': 'sha384-F5/gcKEEQ841NRn1gbkDgXcrnt4lLnCam8UmmQWtaIaBn2R5XtaQOx2LQM7jWxXN',
'static/merkleTreeWorker.umd.min.js': 'sha384-R1iZHWmgD+tXHbxE2kNtnd9EwtKDwo0CUcZHJ5w/7Sy7sCGkRNVAwqIe7fDyAJYw',
'static/package.json': 'sha384-wPfgMO8ps3ecW6HCi27ySuYwrDZmsrlnzxO1QRBFMD+mpWCqpXIY3wr5risW5MHH',
'static/torn.png': 'sha384-JHO0kpKduyooWMLR9QZ35GSU1/B0cpbQ6wLvVAg91KkVEFLQz9XBwBD9FCFJVL9R',
'static/torn2.png': 'sha384-4wuwoWrwrSCoVr3jtQLAFoj09ukL6JJ0/MJ/5qCoN5oEv6CwPe5Xu2VP5wKiHsbS',
'static/tornado.json.zip': 'sha384-XmKBnm5OYS4kGyw52NNSOmSQ4uvN7w/ZNQIgqfSSSSJ1MJw9dfCE5OLQHHDvqP0F',
'static/tornado.umd.js': 'sha384-+3lhzvvDsVKE0kaNPlTbaY7VzjhrETPfBpvSeUEmYpuwZSJPMjk0z9JEU8FTF/tn',
'static/tornado.umd.min.js': 'sha384-L1dK994fW26N0QZ7pVqTqTgVvNfJfIJFt+G9qsQvQQPkVoOOvMv+oqRp1tW+N4FX',
'static/tornadoContracts.umd.js': 'sha384-iCyap5fZX6deuZ5dxb52Aa5j3/rJ/lqfIU9LGr8ZF0nKBmEqCkvJMdS79pPM2X1u',
'static/tornadoContracts.umd.min.js': 'sha384-OhaFa/s/nR6yUbwP+grwKnX0wBZu+SaBV7eSY7QYM1r5GGLQhL604xCKp4CtKDXv',
'static/tornadoProvingKey.bin.zip': 'sha384-O+ICo/CmIvnFmeaSfvRc6CUlde24XWL2Bp2hgKRPZTO1LLlVW0GS8gHIzMtcKRa2',
'static/tw.png': 'sha384-DZz1nbDiTbg7RYMRjqvM6sD549Hzr83KzWXIH9x5S+9vEjm67MGbc9pjZoaVOWvT',
'static/events/deposits_100_xdai_100.json.zip': 'sha384-saavn+sR0uZd9suSw3HfnhRAsTX5VP5fUH9nI5/KHmIvDRtEBrjyPlmUAxOD/oft',
'static/events/deposits_100_xdai_1000.json.zip': 'sha384-FU2sF62dSNe3b1nONeIfYcNMIrn11CvlK0zFGkpqkBo+KUO0dnZuMXoWIX7dUPAK',
'static/events/deposits_100_xdai_10000.json.zip': 'sha384-qUHmU0fVJ3iOuUHn0QErIU3IYesD2mO/CJ4JEvjkgtoKRjp24ZEf6a0wQHm+5tPr',
'static/events/deposits_100_xdai_100000.json.zip': 'sha384-ZlQJ8V8E+zTI7+9s2JMtHXr+CvoTULZ/AS94wzluRFYZS373eYr81yIor1a5Cdr8',
'static/events/deposits_10_eth_0.1.json.zip': 'sha384-/enSn2ftk0dnsuu3nCjhDenFEXuwGSiuigsx8P4umVf7a35DEeUuv87M1D3D0K+l',
'static/events/deposits_10_eth_1.json.zip': 'sha384-rQU7KBTVX9CC2VsZQ2czIV3s2E7rlI/QZBsrpqgxWOw7bMAOa7QUQOcxcqE9aS3T',
'static/events/deposits_10_eth_10.json.zip': 'sha384-sfnY/SbvXbGkxDJkGECps0ZpzhL7rvXemz8881Aj+LuUJGv2xKBQFhcwwKsYlD6F',
'static/events/deposits_10_eth_100.json.zip': 'sha384-plnh245VknBamQ+Y4248qyj+SA9tlaXt7yCP/gkaxvq2GAgv5Ujy3wVKuq+kC8cf',
'static/events/deposits_11155111_dai_100.json.zip': 'sha384-wX658+oUHQf3FmVic79SxGoE2aiqDmd/D7N0HtPEySvC12tf3+mUpIYotBSXcbth',
'static/events/deposits_11155111_dai_1000.json.zip': 'sha384-c2K073UqEy+/u9pZszv1wyuw9c606/sTVrpcBgrhyayIwVbQca90eaqHWj6J2sI/',
'static/events/deposits_11155111_dai_10000.json.zip': 'sha384-tHtc9Fj3QFiNWXyb/bHWN4M/2GVLh9tNJ5bMwxTAA1oXJb4BFdFGHv5evgPvsiNi',
'static/events/deposits_11155111_dai_100000.json.zip': 'sha384-nM/wwfrjfuVQRVA7VJwkLlWUh0WlA9rUvLlAtZEkoCNeYtgwmpUvEiN4H6/HOqT6',
'static/events/deposits_11155111_eth_0.1.json.zip': 'sha384-GCM7lgk/vUZKp5om0/u0Kang3Q0RQjejOifMskojg/MYusOpy/3ZjA0b2ivzbgHK',
'static/events/deposits_11155111_eth_1.json.zip': 'sha384-pMQm/swVdVlL0HRTLq6tOvabv2B01YJh9jVBuIwWsHY+4d2ezPQYuIn/NmrTjJHN',
'static/events/deposits_11155111_eth_10.json.zip': 'sha384-Vz9opUQVIkQP4PLHD5W+DEPWAzLU5pOj6u8utdH87deRmBuBcJKpj7Nj/CfiZMXi',
'static/events/deposits_11155111_eth_100.json.zip': 'sha384-Pcuy0YLekrcVjgVWq9mjxqrLY9BWmuL9ndP03/+VH+alcPEao75PnrRrSybcunwX',
'static/events/deposits_137_matic_100.json.zip': 'sha384-dqOvSPzykgjA5eOMiLbmAA8EkbDFLMnImDW/Lj7VJLDRDvLJPocFIvs7m+OQSafh',
'static/events/deposits_137_matic_1000.json.zip': 'sha384-K1WUYi3JVaY6lckGSM+SjKih39F4/Zml1UnwCOK37tHusRIB03xksEidzB+HeLsf',
'static/events/deposits_137_matic_10000.json.zip': 'sha384-8QBV+n3d7KstAwPAUtAGqWcxX7n7XyJNqq6DAJHvUrqNfhGCiikufN5jDjHOflCR',
'static/events/deposits_137_matic_100000.json.zip': 'sha384-gaeHrMxsg8ACD3n/nbl5BXAR5idodfFkPXjxy9uu2iTWdU63hvqKdXuTH7xzKRd7',
'static/events/deposits_1_cdai_5000.json.zip': 'sha384-IcIQWLBuV5Nr6wFADYKq4TAzoTti0k1O8FOertwHiTY7TzCbs+/T5OAZBdhpn34G',
'static/events/deposits_1_cdai_50000.json.zip': 'sha384-Jnex5SeDkvos730ZItsbuCcWdY9sruoeI5k3/m08wXW9O+dQ1DI0EQ0RLKOWndOo',
'static/events/deposits_1_cdai_500000.json.zip': 'sha384-PXZFPcBZuBIfOr8PqKHc4ytiUCOYt3NIHBWBoSRrmKgxYqu2l8MMy/hL9Iwi/rEk',
'static/events/deposits_1_cdai_5000000.json.zip': 'sha384-xrbjndEOH+P3MO0eyBQ6NEcj11GZ8ZXu3tijxbz8jay0R4U2CYleAxxtjXSrpFfk',
'static/events/deposits_1_dai_100.json.zip': 'sha384-EPC3ag8WjCyvUJ+33AXda6TCgR8X14yDfh8TbEu/3nvaXL+SZYmebq+X4J4fhorj',
'static/events/deposits_1_dai_1000.json.zip': 'sha384-BEnV9Zy2WrQTpVA3qiuDsLCZpl2Zn+WcaPkgKCAKvZfDn5J+Jsg+7tKY24VbuGaS',
'static/events/deposits_1_dai_10000.json.zip': 'sha384-3NI4Nso1Mw3oXnCXZFjRNLGva5zD4SclLm6hFMH1fhjJLF5o96SbiQlaBEVV1XZz',
'static/events/deposits_1_dai_100000.json.zip': 'sha384-zAJMb5MbyAy2oDFqMt4j2YY4NlOgbh8KS+jN5b1sv9yfWsJkMlRnyDKxzG9Vo8Tm',
'static/events/deposits_1_eth_0.1.json.zip': 'sha384-m4OIQKD9Wb95sCPXcVT50Q4HwP5wIO0u2fdPW7a2VXzZ2R8GqakhZOJWNdNByUPO',
'static/events/deposits_1_eth_1.json.zip': 'sha384-SkvUqenciTikzSpJDFIgIBNSOLmADa2fWbq20VE/aS265LpAMaNzMMzb8zanG59P',
'static/events/deposits_1_eth_10.json.zip': 'sha384-g9AhRjKehsJwPuUIXRKTUgpdQIoKc+VlhwLANzy9p759pM646fMAdQVOaxrh3TWx',
'static/events/deposits_1_eth_100.json.zip': 'sha384-GLNU/069uZt4E5QIj0kjfHZMJZr6j//1XFx91VKdDsY0tVtWEE4ZG73uZhNuQKcv',
'static/events/deposits_1_usdc_100.json.zip': 'sha384-vKySc3XblzRo+rHv/bF0CbQl2tLl2g+/0O4ZmDyPyJUh0KSPPRT/KfPYx14RD1Ru',
'static/events/deposits_1_usdc_1000.json.zip': 'sha384-hoRofVEOBRqLH3R3+dHl1MMJd5HAIOZNcfjFFH3pYE7+s48n53z8crg1+d/VkkQT',
'static/events/deposits_1_usdt_100.json.zip': 'sha384-IqMfcdMBJRp+Y9mG1e91NPuy84kszjL4Hpc6fhayouePQvrEu/j4Lhz+P/O6/kbW',
'static/events/deposits_1_usdt_1000.json.zip': 'sha384-j7uWvF1kdfG2aaqzKgU+vT2nzF4hY1JIFQpksHPOeSo3etAfyPSg7q7SSmlv85++',
'static/events/deposits_1_wbtc_0.1.json.zip': 'sha384-j/Q/Fz/S4pjbi9gCwVLc/p0BGrCpbeo5FmfYJ1y1Pp3Gf+eZRqQa8kBVMmJaP7qw',
'static/events/deposits_1_wbtc_1.json.zip': 'sha384-e/UcCulccgADPSvd+rATql0NUtHgx6G48d1FmpO7GAfn1DYG1PnUHhcbvi5Pp/qP',
'static/events/deposits_1_wbtc_10.json.zip': 'sha384-oueBOv7Vgk3fjImUOx7YfUVU5N3oAq+hmkZZr2v2U+XxpLiV2Z/jN5ezfHX/lqrU',
'static/events/deposits_42161_eth_0.1.json.zip': 'sha384-c1zl1Otj+y4sYiglPs+DIis/j18P72iVOReFNCoWMYvocLLe8gZXRXEjYC++lsaS',
'static/events/deposits_42161_eth_1.json.zip': 'sha384-M4mJr3wVvF93/Gb6vEds4g8sPMsXY/YAYStrghBCrd9GSq4NwzosMRFbUEUNXXTl',
'static/events/deposits_42161_eth_10.json.zip': 'sha384-QACaql15NdtWF55pv80yAh6O+D9Ba1a07vumThL1KC0KuQovq5H/9MgIVS1er1ih',
'static/events/deposits_42161_eth_100.json.zip': 'sha384-rsiaiKZ2rH+qlcevksbLhYvrstCWyxur6DvLQxb804hu0dFVHGz4XufkAghBjRek',
'static/events/deposits_43114_avax_10.json.zip': 'sha384-jpn/kbpHDF/Var46GyRkZKw67hOZWUfqZlf4aaWAVXZ96sxtXJXDMX8NtX92ODiJ',
'static/events/deposits_43114_avax_100.json.zip': 'sha384-PnL0dma4Wqma/zHUbuAS/cq+WHT5Oifh7fNO1C2mEZi6tib+gTN4OECD2Eua6xce',
'static/events/deposits_43114_avax_500.json.zip': 'sha384-xszbEh3nLB/Uh25KNHM9nBzmjyO/P7aD7CeyUt+dzUA8SqDgqQ1LYc5tWySc4AVt',
'static/events/deposits_56_bnb_0.1.json.zip': 'sha384-jI3zhrADAjWGYPCyn4Oc9JpxwUaMeYbxwUGcBJbaMcYXu5Llz0d7RvzPVbsjODz9',
'static/events/deposits_56_bnb_1.json.zip': 'sha384-A3LVQptEWs/lrFnFmkTorVS/yktfLBrmD/5GybDYyXwGPMD5fwl8np+Dr0zVQfQF',
'static/events/deposits_56_bnb_10.json.zip': 'sha384-EhV7PGtYJ2bF6mW6AUbyEP99R5zdyWGE2N04gaQhb9cE3IIpyIVDOXa7toEAO44R',
'static/events/deposits_56_bnb_100.json.zip': 'sha384-ZBoGR/qavAj3jiaTPhN5hRNf4mz/9ctAJmX12wdKGuRPR/3cyoXj4hpv7sZeZM8d',
'static/events/echo_1.json.zip': 'sha384-8f2mVn+RYYyEp2BATmpjI9ikHy1tqiiqlMFDEFqy3OUsIlvscePVveFaZNW4apCa',
'static/events/echo_10.json.zip': 'sha384-JpMvj21HSHJu5v5qN/gz8D1M3RFxWj74dS4Gb6zU5/RyPvqhI3Kx1+foyAfDHUxX',
'static/events/echo_100.json.zip': 'sha384-VY1XwuU+YeIveBDxPtOL7i+W3EqXGBtAaAEO1dopzf6J+0rk+BOrzSqAFO3CYjVl',
'static/events/echo_11155111.json.zip': 'sha384-dEfNoTSAozHY51BKRifvDtJiOJdeBUBaLXCuv4PybvmxAUApjr+O8ZZBfih0sfvP',
'static/events/echo_137.json.zip': 'sha384-dZQo5zA30Gd1KPxsAGgIAgkLmfBjYoGTTeN5kgQaTQJ5MxF0PF+MICQKsNdjGLYN',
'static/events/echo_42161.json.zip': 'sha384-cSbp3tSqjJfP6oYSUKVhkesMBdRIBeoxxhkIp+jk3tCXMqal5nETCYZw+WVw+G0L',
'static/events/echo_43114.json.zip': 'sha384-7Py5sljkmMAt0TCaBUxhoWOU++Kmnas5S8sJYKxT8f3q8h0KxeyB8DKiIQ3ym8kR',
'static/events/echo_56.json.zip': 'sha384-DNkAK5qxqtnnlm8Pbj1ZA2MYORb9mhLdgWzTfeJTcfG95eEJ5/OtxeMMyZZaoU1O',
'static/events/encrypted_notes_1.json.zip': 'sha384-jK4k63kgFvuvq1thwhkh2V7jNbWueaiJOcMbibvUxjcP3OvSljswc9MJYCDjzANN',
'static/events/encrypted_notes_10.json.zip': 'sha384-RhHxF7F2bx0a37WdLKcIB4O0PDc3TO5mnv50ayFFgWC86FTh5UXJ8nAsrXTV9hMt',
'static/events/encrypted_notes_100.json.zip': 'sha384-HNJck1bBW68p7SfyNfvogpmegi6XqaDgFDn4/cafNirDbWpCTpCrfikOFTU/ILze',
'static/events/encrypted_notes_11155111.json.zip': 'sha384-BF7nJu5NR9PIgR1OQYgzdG7iK6eJSSJjsSRG50I9TQctRKLqn3wtyUfdE8rdv96t',
'static/events/encrypted_notes_137.json.zip': 'sha384-9MBupp5P5VHpB8cMFuIfzmBoT/BE7cKbhuECk6OPm2N6KrB/4zZ59w5yfbO6lTvV',
'static/events/encrypted_notes_42161.json.zip': 'sha384-QtAZwi1JPdguLf8JUPN1fe/LHi1mTZQ+76wF0Ct6MxapUkmWkvRbV+TUk6Fi5W+Y',
'static/events/encrypted_notes_43114.json.zip': 'sha384-enjUljsf0qTe//tTV5PGW9wqlgE0ZaBzz/bDb74LAxiYzUqOI3FVAiNB0rPFPhVk',
'static/events/encrypted_notes_56.json.zip': 'sha384-umlVjJ0xe8ZCJhaTX2Slix7W1VGZdEXiMYm4f0fzRAG/HDm+KMPxQbHZF7YGLLJH',
'static/events/governance_1.json.zip': 'sha384-IJEQOOJdxsufN7Hsq59ZE5KBuyIKjjf/Ve5T9D+7/RLHi//JRmkRuI928UbWFoeN',
'static/events/governance_11155111.json.zip': 'sha384-MbeTc/EYah39LgNSnWDFAy4jns7BchGVDILO76l77a24ufJmJ6JlNivwJMiGlbMI',
'static/events/registered_1.json.zip': 'sha384-AUACMbxG7EIJgMBD6jtcvMzk8JSj8GdCD6EXgU9TrDvTzwizcVj9hUqyow9xAuYg',
'static/events/registered_11155111.json.zip': 'sha384-wyFMWtCPbyrsx2LaOUCQuXt/x61dps2v1ZG1HgyfGp/LQs2TbFKMEgfL/XZesxQh',
'static/events/relayers.json': 'sha384-Mz1FuLCjLyD/8RY9nP2Cge/PkYkra4d3Zt+MB4rx09/TvJCvoB4Z7/MXuHOFROS1',
'static/events/relayers.json.zip': 'sha384-EA6DvejrS6NO1vufecok50J0VGOWXx/EiBALAXTcDmRY0IOfdCtyuCOAIGsEK1fF',
'static/events/withdrawals_100_xdai_100.json.zip': 'sha384-HoXz34GeA97nbkluH2/L59PEPVSin++GCI/pPlExDAK2t7G0V+cNC3JbM6wM/W/6',
'static/events/withdrawals_100_xdai_1000.json.zip': 'sha384-xfrUckEy/dSUEdJxQSXcqHdYyMfN2tAxsRXkfUT6BxBkc4kdj73qYWor2bk+ju1Y',
'static/events/withdrawals_100_xdai_10000.json.zip': 'sha384-iYDsm8lPVE9DmmGkDZVygGydRF4GUfhDyVMXRd+qjo+ZxGiyi3qJK8/tC9ADItuw',
'static/events/withdrawals_100_xdai_100000.json.zip': 'sha384-etsh+M3HUyEtZUwK/+QF8//9YudFx6g+QNJbv1dvgLI+VvlsufhkMVDPbbB4a5fq',
'static/events/withdrawals_10_eth_0.1.json.zip': 'sha384-LclLA42t5MoMJph/BB7Lw2Wd15VtyjX8jUA/rVQzVH8eSJLC7h/Q1U2wecllVGPm',
'static/events/withdrawals_10_eth_1.json.zip': 'sha384-5YCH/f57fSc2p0Dz1kkdvSSJwua8ViSBy7fwd1n582+UfeFx/HVOKC8++KrshhHI',
'static/events/withdrawals_10_eth_10.json.zip': 'sha384-XVts4oweZc5qXvhCNeot9B6m/3K9EWEtqZTuOWzmQJgMNRvzW2f0/9HcH2N4en+D',
'static/events/withdrawals_10_eth_100.json.zip': 'sha384-ApTVOiZGm8mGdDfMax3ctZ0JDJ6MwWZowubJu4lQ8swxDANLkwit2ciANMEG55dT',
'static/events/withdrawals_11155111_dai_100.json.zip': 'sha384-wZXPCl/nGe9POXBv5c6jPTZESiGYVuVV9afHaT132qVOQ7ed5P/i+1wMQ3wgnxQw',
'static/events/withdrawals_11155111_dai_1000.json.zip': 'sha384-YYWCoQrLzLdAZO9qB2D46M8uZQyjHdUdkAzWXVcIv0ujZWixjgYMHYwyd1XEogl3',
'static/events/withdrawals_11155111_dai_10000.json.zip': 'sha384-rkiynDp7409fZHiWuaXzxX8hsBy0qM9aLQVYAv3L9lP7AWPp9sLsfSgDpzv5ZzSa',
'static/events/withdrawals_11155111_dai_100000.json.zip': 'sha384-KsDEGIxrF84j5GL5ZeNBbyoICIkjAz5JJ8N1HA+k21oHgrXk3fJO7N7IMWOKoZ2G',
'static/events/withdrawals_11155111_eth_0.1.json.zip': 'sha384-RBRd8cl48M4Gr+h9x5qSGsLkl1J3xfWE8nFUeInaRUTI8FuawtqJScmPUtTVbtyX',
'static/events/withdrawals_11155111_eth_1.json.zip': 'sha384-3nR+2H54CuFwl+4pX+mzyYQH3KJQRpeDjh50WBY9+j7vK4j/YrHxHr6TLbJUtFo1',
'static/events/withdrawals_11155111_eth_10.json.zip': 'sha384-R1AHoexWR3K1n2y2TkQ+lTVBGc+UI+FVlNxQwDRAU3hMV7aGeX7VkBf8R09fIjb7',
'static/events/withdrawals_11155111_eth_100.json.zip': 'sha384-mUYncP9vTxRb4k5sEKfcuMccbaG/8izTKcIVlN0gyEDJkYhGCdheC8iJ5sP26ECe',
'static/events/withdrawals_137_matic_100.json.zip': 'sha384-XtqTLEn1yScAZToaybTCm5f4zG/ThJMNBf21kPLptHR7X3ffJN+t0skI2tUOeKNA',
'static/events/withdrawals_137_matic_1000.json.zip': 'sha384-Cz9KtoBqwld0Z6wsPHxv3pBKeByL4Vi0Zncmy4xTigGqMTTNfoSpVPSveA6PAmon',
'static/events/withdrawals_137_matic_10000.json.zip': 'sha384-nJqLrhlHDitxiURYNRgdnRdB2xCvfUT67ajjcxmzEJwndBDVtVhcjyn6licaL6qt',
'static/events/withdrawals_137_matic_100000.json.zip': 'sha384-6MSAIl/TsIj4BV2YCXBPmR/7PKxotVcaYm+WP1q1Znbz2MNkKjDQjpIcjucyy5Xx',
'static/events/withdrawals_1_cdai_5000.json.zip': 'sha384-oMSzbMsWHjmJ10duwUBs2B0OlWezTiEtghQiI7gmmoOUZHmI74zv166c246jiI3N',
'static/events/withdrawals_1_cdai_50000.json.zip': 'sha384-RY2zNkSag/qtt1I2FkqRi2nmz5VAdntaRy4goI+/SkYQ2CW13cAyAODIMPQce7+U',
'static/events/withdrawals_1_cdai_500000.json.zip': 'sha384-2Z/2iSYnjrIJUV34o/Oy/I6Cd+ZLZ5f+oaVjk0QPGqjr5Yp5EcKYDoR6D2IaS647',
'static/events/withdrawals_1_cdai_5000000.json.zip': 'sha384-A5sFkXaGTK7oqc3mmUk8Zp3pR966R59Ez/ci4UwQ8TnD4LauEKNAGBYUOSVyjTBh',
'static/events/withdrawals_1_dai_100.json.zip': 'sha384-7j4T+pbMEHZqQR+lvnXGtdddysOLJx2rSTiCx3fSmlubx2+In1pUiXIctE1PEJZ5',
'static/events/withdrawals_1_dai_1000.json.zip': 'sha384-dskVGh1bEr9btiiD8us+lYZT1urGeo4v0D4gVoaeIpIyycLLaAAVsenB+pEHEtEQ',
'static/events/withdrawals_1_dai_10000.json.zip': 'sha384-MZR4eTJQr3KRySx6SzWxY9pngMuRMtb3ioYfcZJdROjw+4R4JONRsric2/FIHLAN',
'static/events/withdrawals_1_dai_100000.json.zip': 'sha384-GMe1JZ1MfTplKDyR+Ee1euj4mui6mpEB67x0MfI32/u+sUglZClADthfJorMU9bS',
'static/events/withdrawals_1_eth_0.1.json.zip': 'sha384-EUALLHA5ES/IICWcuog/nqN4NhmqjbIU7PuvjiyLHx4F9zbt7Bor/NBaxdHBv2eU',
'static/events/withdrawals_1_eth_1.json.zip': 'sha384-sz94RYCFQyJQmBxo5XYcyhDqY+88Ci5W2hVmyvbo9SC7Nu6wp8/S6/57w2Oca+eL',
'static/events/withdrawals_1_eth_10.json.zip': 'sha384-zM4yOX6Esbo4V7JnkHDct4aXLMDZv7M7TuWZ1yoKa4vZcb2ZglvbhksSQUC8bjFQ',
'static/events/withdrawals_1_eth_100.json.zip': 'sha384-2CZhP2xI8zMIU8YNl7huIV5PmbYfI8GBcw+dOqDEhDqa3EugGaobHHtHXZsWkvs6',
'static/events/withdrawals_1_usdc_100.json.zip': 'sha384-Y9mV4gW+gcDUfm0PFfcOHRxTh1dcrRpsr3s8wxU8AbfGsLhdzxwIJF4dX6ipf3KB',
'static/events/withdrawals_1_usdc_1000.json.zip': 'sha384-2OlNnWtNJcuN9l0QS/pJ3/kS7YzFpY9KPHP2gtRxL7T1Mr55Q0pK8Ft54tgGG1pG',
'static/events/withdrawals_1_usdt_100.json.zip': 'sha384-gnagdsNsMdqPoTbCG9rUZi19HMjI+E9mtrWE5SmkthtJGrloYiFUdxJWZ+OE/sMK',
'static/events/withdrawals_1_usdt_1000.json.zip': 'sha384-xiZquAIB+BKT3LKBoFYopzjw62hz78vQIQHDxp9pWvbBP12CTDIHqbcB5C5HMUpk',
'static/events/withdrawals_1_wbtc_0.1.json.zip': 'sha384-sqzhGkGZWOIOtdCQqUTCN1ZW5rFNFIOjLOy1QpXWc+eko5jKzcp3mFCf4AsWa9tH',
'static/events/withdrawals_1_wbtc_1.json.zip': 'sha384-A1//Rwa3liaMdOkI+ruW00RSgcmQgGd26z+jhHEy+bFumIYqtWyRa100uDqPHI5X',
'static/events/withdrawals_1_wbtc_10.json.zip': 'sha384-cpgNBJOQrYO8r+9WounhGiJW/stK5UduSxUFRncCSJ6qfoWWzTUiEB52J4FwC8Vv',
'static/events/withdrawals_42161_eth_0.1.json.zip': 'sha384-TVGV5jkWKEVRgzd7AWxr+9Chi8hfft+UzEzyN4DhA6ZicbcUifhmhBXKi1fc5BRn',
'static/events/withdrawals_42161_eth_1.json.zip': 'sha384-lNHohw9TW5B07O9EFhPz1OFTJmbIU2IPBkdg6KzwoPPPeNy2YcxqJ6fR2KWXxHbZ',
'static/events/withdrawals_42161_eth_10.json.zip': 'sha384-uPEH1LLp+EtNXBnI1nXaObPSErVDTcR36RrLGbvCcqKx6fjmyDcVvIfrNWquaB9q',
'static/events/withdrawals_42161_eth_100.json.zip': 'sha384-dDe5gPLIqBV8VJjuNnuG89OPDjQLEkE5m3byYpMSNAhNPpx7EkPeJMoVhJlY+yNl',
'static/events/withdrawals_43114_avax_10.json.zip': 'sha384-JO5HQirAZUhHTEXfwsgAwdqIWklIzYdXRdfGYs2BHkRiyzHpfUx4iRUs/LHeDkd6',
'static/events/withdrawals_43114_avax_100.json.zip': 'sha384-WHNGUMVxsWlKTJdfoLAJYPcv1LPkVrStMjGaVzBQfDhfX750zRZzd2hyyY6ZWCIf',
'static/events/withdrawals_43114_avax_500.json.zip': 'sha384-RnOtZx9aWrczr/32qjb9CLAlCsiYx7IazDZ91aNEKFURj+ghTG5B2O1EEl+ot2/4',
'static/events/withdrawals_56_bnb_0.1.json.zip': 'sha384-ZLE2sUH5HLYdsoWbCdGhmv7kLP/R8JmDNVFnRAkR5uefYo9JwNM8KEsrlaw1km3e',
'static/events/withdrawals_56_bnb_1.json.zip': 'sha384-l8aZ2NG2D72hnzr3tsBei1VJAMqXHDdF3EqViyKRcdneB9XRnJ/sykDbRfHOofeI',
'static/events/withdrawals_56_bnb_10.json.zip': 'sha384-LZjcjfdXVBNdhbfvcB+AUnLHrHMfFrki0MArUUT9ZYR4kfZG9CZBsKeLoWWQ1qMs',
'static/events/withdrawals_56_bnb_100.json.zip': 'sha384-yr3s7J+81mGr6rtfMRJsPJMIT1ftIFVsHZttlGDC3DMmj4BrnzBHLLPsqJKnA+eG'
};
</script>
</head>
<body>
<div class="container">
<!-- Header -->
<header class="py-2 mt-2 mb-3 border-bottom">
<nav class="navbar navbar-expand-md">
<a href="#" class="navbar-brand me-md-auto">
<img src="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/torn2.png" class="me-1 logo">
<span class="fs-4 align-middle">Tornado Withdraw</span>
</a>
<!-- Desktop Navbar -->
<ul class="nav nav-pills">
<li class="nav-item d-none d-md-block">
<a href="#" class="nav-link active">Withdraw</a>
</li>
<li class="nav-item d-none d-md-block">
<a href="#mnemonic" target="_blank" rel="noreferrer nofollow" class="nav-link">FAQ</a>
</li>
<li class="nav-item d-none d-md-block">
<a onclick="settings()" class="nav-link"><i class="bi bi-gear-fill"></i></a>
</li>
</ul>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarToggleExternalContent"
aria-controls="navbarToggleExternalContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<!-- Mobile Navbar -->
<div class="navbar-mobile collapse" id="navbarToggleExternalContent">
<ul class="navbar-nav me-auto mt-2 mb-2 mb-lg-0">
<li class="nav-item d-md-none border-top mt-2 mb-2"></li>
<li class="nav-item d-md-none">
<a id="nav-mobile-main" href="#" class="nav-link active">Withdraw</a>
</li>
<li class="nav-item d-md-none">
<a id="nav-mobile-mnemonic" href="#" target="_blank" rel="noreferrer nofollow" class="nav-link">FAQ</a>
</li>
<li class="nav-item d-md-none">
<a onclick="settings()" class="nav-link"><i class="bi bi-gear-fill"></i>&nbsp;Settings</a>
</li>
</ul>
</div>
</nav>
</header>
<div id="messages"></div>
<div class="alert alert-warning" role="alert">
This is a new open source Tornado Withdrawal UI that enables you to withdraw faster with new relayers.
It is unaudited so use at your own risk.
</div>
<div class="row" id="main">
<div class="col-md-12">
<h2 class="mb-5-super">Withdraw Notes</h2>
<p>
This UI allows you to use the new <a href="https://git.tornado.ws/tornadocontrib/tovarish-relayer" target="_blank" rel="noreferrer nofollow">Tovarish Relayer</a>
2024-10-08 04:00:30 +03:00
which provides historic Deposit Events at a faster speed than fetching it from normal nodes.
2024-10-08 03:21:59 +03:00
</p>
<div class="card card-body">
<form action="javascript:void(0);">
<div class="mb-3">
<label class="form-label">Deposit Note</label>
<div class="input-group">
<input type="text" class="form-control" id="note" placeholder="Enter your Deposit Note">
</div>
</div>
<div class="mb-3">
<label class="form-label">Recipient Address</label>
<span>( Will use <a class="donation" href="" target="_blank" rel="noreferrer nofollow">donation address</a> if not specified )</span>
<div class="input-group">
<input type="text" class="form-control" id="note-recipient" placeholder="Enter your Wallet Address">
</div>
</div>
<div id="on-note" class="d-none">
<div class="mb-3">
<label class="form-label">Select Relayer</label>
<select class="form-control form-select" id="note-relayer"></select>
</div>
<div class="mb-3">
<label class="form-label">Network</label>
<div class="input-group">
<input type="text" class="form-control" id="note-network" disabled>
</div>
</div>
<div class="mb-3">
<label class="form-label">Currency</label>
<div class="input-group">
<input type="text" class="form-control" id="note-currency" disabled>
</div>
</div>
<div class="mb-3">
<label class="form-label">Amount</label>
<div class="input-group">
<input type="text" class="form-control" id="note-amount" disabled>
</div>
</div>
</div>
<div class="mb-3">
2024-10-08 04:00:30 +03:00
<div class="form-text">Information of notes, deposits, withdrawals, or private keys is never shared among any other third parties including us, relayers, and RPC providers. You can download and audit the source code of this website by simply saving it to index.html</div>
2024-10-08 03:21:59 +03:00
</div>
<button type="button" class="btn btn-primary w-100" onclick="withdraw()">Withdraw / Compliance</button>
</form>
</div>
</div>
</div>
<!-- Footer -->
<footer class="d-flex flex-wrap justify-content-between align-items-center pt-3 mt-5 mb-4 border-top">
<ul class="nav col-md-7 mb-3">
<li class="nav-item">
<a href="https://git.tornado.ws/tornadocontrib/tornado-withdraw" target="_blank" rel="noreferrer nofollow" class="nav-link px-2 text-muted"><i class="bi bi-git"></i> Source Code</a>
</li>
<li class="nav-item">
<a href="https://element.tornadocash.social" target="_blank" rel="noreferrer nofollow" class="nav-link px-2 text-muted"><i class="bi bi-chat"></i> Matrix Chat</a>
</li>
<li class="nav-item">
<a href="https://t.me/tornadoofficial" target="_blank" rel="noreferrer nofollow" class="nav-link px-2 text-muted"><i class="bi bi-telegram"></i> Telegram</a>
</li>
</ul>
<p class="ms-2 text-muted justify-content-end">Built with <a href="https://git.tornado.ws/tornadocontrib/tornado-core" target="_blank" rel="noreferrer nofollow">@tornado/core</a></p>
</footer>
</div>
<!-- Settings modal -->
<div class="modal fade" id="settings" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="settings-title">Settings</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body settings">
<form action="javascript:void(0);">
<div class="mb-3">
<label class="form-label">RPC endpoints</label>
<div id="rpc-endpoints"></div>
</div>
<div class="mb-3">
<label class="form-label">Private Key (Optional, not saved)</label>
<input id="private-key" type="text" class="form-control" placeholder="Private Key to use for Direct Wallet Withdrawal">
</div>
<div class="mb-3">
<p>UI Version: <span class="version"></span></p>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" onclick="saveSettings()">Save</button>
</div>
</div>
</div>
</div>
<!-- Send Modal -->
<div class="modal fade" id="send" tabindex="-2">
<div class="modal-dialog modal-xl" style="max-width: 780px">
<div class="modal-content">
<div class="modal-header">
<h5 id="send-title" class="modal-title">Withdrawal</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="confirm-screen" class="d-none">
<div id="send-table"></div>
<div id="send-confirmation"></div>
</div>
<div id="status-screen" class="d-none">
<div id="send-status" class="mt-1"></div>
<img id="send-loading" src="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/torn2.png" class="loader status d-none">
<img id="send-error" src="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/failed.png" class="status d-none">
<img id="send-success" src="https://cdn.jsdelivr.net/npm/tornado-cdn@1.0.1/success.png" class="status d-none">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary d-none" onclick="confirmWithdrawal()" id="send-button">Send</button>
</div>
</div>
</div>
</div>
<script>
let settingsDB;
const AllDB = new Map();
let privateKey;
let privateKeySigner = new Map();
let browserSigner = new Map();
const allRelayers = [];
let workerChecked = false;
let job = {};
// eslint-disable-next-line no-unused-vars
function settings() {
new bootstrap.Modal('#settings', {}).toggle();
}
function hide(comp) {
if (!$(comp).hasClass('d-none')) {
$(comp).addClass('d-none');
}
}
function show(comp) {
if ($(comp).hasClass('d-none')) {
$(comp).removeClass('d-none');
}
}
function notifyMsg(msg) {
const msgId = `msg-${Date.now()}`;
$('#messages').prepend(`
<div id="${msgId}" class="alert alert-success" role="alert">
${msg}
</div>
`);
setTimeout(() => {
$(`#${msgId}`).remove();
}, 10000);
}
async function shortHash(msg) {
const digested = await Tornado.digest(new TextEncoder().encode(msg), 'SHA-1');
return Tornado.bytesToHex(digested);
}
// eslint-disable-next-line no-unused-vars
async function closeAlert(msg) {
await settingsDB.setValue(msg, 'ignore');
}
async function alertMsg(msg, permanent) {
const hash = await shortHash(msg);
const pref = await settingsDB.getValue(hash);
if (pref === 'ignore') {
return;
}
const msgId = `msg-${Date.now()}`;
$('#messages').prepend(`
<div id="${msgId}" class="alert alert-warning alert-dismissible" role="alert">
${msg}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close" onclick="closeAlert('${hash}')"></button>
</div>
`);
if (!permanent) {
setTimeout(() => {
$(`#${msgId}`).remove();
}, 60000);
}
}
function errorMsg(msg, permanent) {
const msgId = `msg-${Date.now()}`;
$('#messages').prepend(`
<div id="${msgId}" class="alert alert-danger" role="alert">
${msg}
</div>
`);
if (!permanent) {
setTimeout(() => {
$(`#${msgId}`).remove();
}, 10000);
}
}
function showConfirmation(title, context, table) {
$('#send-title').text(title);
$('#send-confirmation').text(context);
$('#send-table').empty();
if (table) {
$('#send-table').append(table);
}
show('#confirm-screen');
show('#send-button');
hide('#status-screen');
}
function showCompliance(title, context, table) {
showConfirmation(title, context, table);
hide('#send-button');
}
function showStatus(title, context, status) {
$('#send-title').text(title);
$('#send-status').text(context);
hide('#confirm-screen');
hide('#send-button');
show('#status-screen');
if (!status) {
hide('#send-success');
hide('#send-error');
show('#send-loading');
return;
}
if (status === 'success') {
show('#send-success');
hide('#send-error');
hide('#send-loading');
return;
}
if (status === 'error') {
hide('#send-success');
show('#send-error');
hide('#send-loading');
return;
}
}
async function getRpcUrl(netId) {
const savedRpc = await settingsDB.getValue(`RPC_${netId}`);
if (!savedRpc) {
const config = Tornado.getConfig(netId);
return Object.values(config?.rpcUrls || {})[0]?.url;
}
return savedRpc;
}
async function saveRpcUrl(netId, rpcUrl) {
await settingsDB.setValue(`RPC_${netId}`, rpcUrl);
}
async function loadSettings() {
const urls = await Promise.all(Tornado.enabledChains.map(async netId => {
const rpcUrl = await getRpcUrl(netId);
await saveRpcUrl(netId, rpcUrl);
return {
netId,
rpcUrl,
};
}));
$('#rpc-endpoints').empty();
for (const {netId, rpcUrl} of urls) {
const { relayerEnsSubdomain } = Tornado.getConfig(netId);
const networkName = relayerEnsSubdomain.split('-')[0];
$('#rpc-endpoints').append(`
<div class="input-group mb-2">
<div class="input-group-prepend">
<span class="input-group-text">${networkName}</span>
</div>
<input id="${netId}-rpc" type="text" class="form-control" value="${rpcUrl}">
</div>
`);
}
}
// eslint-disable-next-line no-unused-vars
async function saveSettings() {
for (const netId of Tornado.enabledChains) {
const oldRpcUrl = await getRpcUrl(netId);
const newRpcUrl = $(`#${netId}-rpc`).val();
if (newRpcUrl && oldRpcUrl !== newRpcUrl) {
const { networkName } = Tornado.getConfig(netId);
try {
await Tornado.getProvider(newRpcUrl, {
netId,
});
await saveRpcUrl(netId, newRpcUrl);
notifyMsg(`Successfully changed RPC for ${networkName} to ${newRpcUrl}`);
} catch (err) {
errorMsg(`Ignoring changes for RPC ${newRpcUrl} ${networkName} due to error: ${err.message}`);
console.log(err);
}
}
}
const newKey = /(^|\b)(0x)?[0-9a-fA-F]{64}(\b|$)/.exec($('#private-key').val())?.[0];
if (newKey) {
try {
const address = ethers.computeAddress(newKey);
privateKey = newKey;
notifyMsg(`Will use ${address} for wallet withdrawals (not saved, will be cleared once refresh)`);
} catch {
privateKey = '';
privateKeySigner = new Map();
$('#private-key').val('');
errorMsg(`Failed to derive wallet from private key ${newKey}, will clear the value`);
}
} else {
privateKey = '';
privateKeySigner = new Map();
$('#private-key').val('');
}
await loadSettings();
}
function getStaticRoot() {
const url = new URL(window.location.href);
if (url.protocol === 'file:' || url.origin.includes('tornadowithdraw.com')) {
return {
staticRoot: JSDELIVR,
origin: false,
};
}
return {
staticRoot: './static',
origin: true,
};
}
async function getAllRelayers() {
const { staticRoot } = getStaticRoot();
const url = `${staticRoot}/events/relayers.json`;
try {
const { relayers } = await Tornado.fetchData(url, {
method: 'GET',
});
allRelayers.push(...relayers);
} catch (err) {
errorMsg(`Failed to catch relayers from ${url} the functionality might be restricted: ${err.message}`, true);
console.log(err);
}
}
function displayRelayers(netId) {
const relayers = allRelayers.filter(r => {
if (r.tovarishNetworks?.includes(netId)) {
return true;
}
if (r.hostnames?.[netId]) {
return true;
}
return false;
});
$('#note-relayer').empty();
for (const relayer of relayers) {
const isTovarish = relayer.tovarishNetworks?.includes(netId);
$('#note-relayer').append(`
<option value="${relayer.ensName}">${relayer.ensName} ( ${isTovarish ? 'Tovarish' : 'Classic'} )</option>
`);
}
$('#note-relayer').append('<option value="wallet">Browser Wallet / Private Key</option>');
}
function getSelectedRelayer() {
return allRelayers.find(r => r.ensName === $('#note-relayer').find(':selected').val());
}
async function getRelayerClients(netId) {
const relayer = getSelectedRelayer();
const isTovarish = relayer?.tovarishNetworks?.includes(netId);
const isWallet = $('#note-relayer').find(':selected').val() === 'wallet';
if (!relayer && !isWallet) {
2024-10-08 04:00:30 +03:00
throw new Error('Please select the valid withdraw method, if you have refreshed the page just input the note agai');
2024-10-08 03:21:59 +03:00
}
const config = Tornado.getConfig(netId);
const relayerClient = isTovarish
? new Tornado.TovarishClient({
netId,
config,
})
: new Tornado.RelayerClient({
netId,
config,
});
const tovarishClient = isTovarish ? relayerClient : new Tornado.TovarishClient({
netId,
config,
});
if (isWallet) {
const selectedTovarishRelayer = isTovarish ? relayer : allRelayers.find(r => r.tovarishNetworks?.includes(netId));
const { validRelayers } = await tovarishClient.getValidRelayers([selectedTovarishRelayer]);
tovarishClient.selectedRelayer = validRelayers[0];
return {
relayerClient: undefined,
tovarishClient,
};
}
const { validRelayers } = await relayerClient.getValidRelayers([relayer]);
if (!validRelayers.length) {
const errMsg = `Selected Relayer (${relayer?.ensName}) is invalid, select other relayer`;
throw new Error(errMsg);
}
relayerClient.selectedRelayer = validRelayers[0];
tovarishClient.selectedRelayer = isTovarish ? validRelayers[0] : undefined;
return {
relayerClient,
tovarishClient,
};
}
function getRecipient() {
const address = $('#note-recipient').val();
if (!ethers.isAddress(address)) {
return;
}
return ethers.getAddress(address);
}
/**
* Parse supported deposit note
*/
function getNote() {
const note = $('#note').val();
const noteRegex = /tornado-(?<currency>\w+)-(?<amount>[\d.]+)-(?<netId>\d+)-0x(?<note>[0-9a-fA-F]{124})/g;
const match = noteRegex.exec(note);
if (!match) {
return;
}
const { currency, amount, netId } = match.groups || {};
if (!Tornado.enabledChains.includes(Number(netId))) {
return;
}
const config = Tornado.getConfig(Number(netId));
const instanceAddress = config.tokens[currency.toLowerCase()]?.instanceAddress?.[amount];
if (!instanceAddress) {
return;
}
return {
note,
currency,
amount,
netId: Number(netId),
};
}
async function getCachedFile(zipName, zipDigest) {
// If archived file is text like json or js
const isString = !zipName.endsWith('.bin');
const { staticRoot: staticUrl } = getStaticRoot();
if (settingsDB.dbExists) {
const cachedFile = await settingsDB.getValue(zipName);
if (cachedFile) {
return isString ? cachedFile : Tornado.base64ToBytes(cachedFile);
}
}
const fileBytes = await Tornado.downloadZip({
staticUrl,
zipName,
zipDigest,
parseJson: false,
});
let fileString = isString
? new TextDecoder().decode(fileBytes)
: Tornado.bytesToBase64(fileBytes);
if (settingsDB.dbExists) {
await settingsDB.setValue(zipName, fileString);
}
return isString ? fileString : fileBytes;
}
async function getCircuit() {
const circuit = await getCachedFile('tornado.json', hashes['static/tornado.json.zip']);
return JSON.parse(circuit);
}
async function getProvingKey() {
const provingKey = await getCachedFile('tornadoProvingKey.bin', hashes['static/tornadoProvingKey.bin.zip']);
return provingKey.buffer;
}
async function checkWorker() {
const { staticRoot } = getStaticRoot();
const fileName = 'merkleTreeWorker.umd.js';
const remote_url = `${staticRoot}/${fileName}`;
if (workerChecked) {
return remote_url;
}
const resp = await fetch(remote_url, {
method: 'GET',
});
2024-10-08 17:42:36 +03:00
if (!resp.ok) {
const errMsg = `Failed to fetch worker from ${remote_url}: ${await resp.text()}`
throw new Error(errMsg);
}
2024-10-08 03:21:59 +03:00
const hash = 'sha384-' + Tornado.bytesToBase64(await Tornado.digest(await resp.arrayBuffer()));
if (hash !== hashes[`static/${fileName}`]) {
const errMsg = `Worker hash mismatch from ${remote_url}, wants ${hashes[`static/${fileName}`]} got ${hash}`;
throw new Error(errMsg);
}
workerChecked = true;
return remote_url;
}
/**
* Using importScripts to evade cross-origin limitation (Also we verify worker with hash)
* https://stackoverflow.com/questions/21913673/execute-web-worker-from-different-origin
*/
async function getWorkerUrl() {
const { origin } = getStaticRoot();
const remote_url = await checkWorker();
if (origin) {
return remote_url;
}
const worker_url = URL.createObjectURL(
new Blob(
[`importScripts('${remote_url}')`],
{ type: 'text/javascript' }
)
);
return worker_url;
}
async function getNetworkParams(netId) {
const config = Tornado.getConfig(netId);
const rpcUrl = await getRpcUrl(netId);
return [{
chainId: `0x${Number(netId).toString(16)}`,
chainName: config.networkName,
nativeCurrency: {
name: config.networkName,
symbol: config.nativeCurrency.toUpperCase(),
decimals: 18,
},
rpcUrls: [rpcUrl],
blockExplorerUrls: [config.explorerUrl],
}];
}
async function getSigner(netId) {
if (privateKey) {
if (privateKeySigner.has(netId)) {
return privateKeySigner.get(netId);
}
const rpcUrl = await getRpcUrl(netId);
const provider = await Tornado.getProvider(rpcUrl, {
netId,
});
const signer = new Tornado.TornadoWallet(privateKey, provider);
privateKeySigner.set(netId, signer);
notifyMsg(`Private key signer (${signer.address}) connected`);
return signer;
}
if (browserSigner.has(netId)) {
return browserSigner.get(netId);
}
if (!window.ethereum) {
throw new Error('Browser Wallet not found, make sure you have installed one or try with private key on settings');
}
const rpcUrl = await getRpcUrl(netId);
const provider = await Tornado.getProvider(rpcUrl, {
netId,
});
const handleChain = async (netId) => {
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: `0x${Number(netId).toString(16)}` }]
});
} catch (switchError) {
if (switchError.code === 4902) {
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: await getNetworkParams(netId),
});
} else {
throw switchError;
}
}
};
const handleWalletFunc = () => {
if (globalThis.walletTimeout) {
return;
}
globalThis.walletTimeout = setTimeout(() => {
browserSigner = new Map();
notifyMsg('Browser Wallet signer disconnected');
globalThis.walletTimeout = null;
}, 500);
};
// Prevent immediate disconnection
globalThis.walletTimeout = true;
const browserProvider = new Tornado.TornadoBrowserProvider(window.ethereum, await provider.getNetwork(), {
netId,
connectWallet: handleChain,
handleNetworkChanges: handleWalletFunc,
handleAccountChanges: handleWalletFunc,
handleAccountDisconnect: handleWalletFunc,
});
const signer = await browserProvider.getSigner(0);
browserSigner.set(netId, signer);
// Prevent immediate disconnection
setTimeout(() => {
globalThis.walletTimeout = null;
}, 5000);
notifyMsg(`Browser Wallet signer (${signer.address}) connected`);
return signer;
}
async function getIndexedDB(netId) {
if (AllDB.has(netId)) {
return AllDB.get(netId);
}
const idb = await Tornado.getIndexedDB(netId);
AllDB.set(netId, idb);
return idb;
}
function getEventHash(instanceName) {
return hashes[`static/events/${instanceName}.json.zip`];
}
// eslint-disable-next-line no-unused-vars
async function getEvents(tovarishClient) {
const { netId, amount, currency } = getNote();
const { staticRoot } = getStaticRoot();
const idb = await getIndexedDB(netId);
const config = Tornado.getConfig(netId);
const {
deployedBlock,
networkName,
tokens: {
[currency]: {
instanceAddress: {
[amount]: instanceAddress,
}
}
}
} = config;
const provider = Tornado.getProviderWithNetId(
netId,
await getRpcUrl(netId),
config,
);
const Instance = TornadoContracts.Tornado__factory.connect(instanceAddress, provider);
const TornadoServiceConstructor = {
netId,
provider,
Tornado: Instance,
amount,
currency,
deployedBlock,
tovarishClient,
staticUrl: `${staticRoot}/events`,
idb,
};
const depositsService = new Tornado.DBTornadoService({
...TornadoServiceConstructor,
type: 'Deposit',
});
depositsService.zipDigest = getEventHash(depositsService.getInstanceName());
const withdrawalService = new Tornado.DBTornadoService({
...TornadoServiceConstructor,
type: 'Withdrawal',
});
withdrawalService.zipDigest = getEventHash(withdrawalService.getInstanceName());
const merkleTreeService = new Tornado.MerkleTreeService({
netId,
amount,
currency,
Tornado: Instance,
merkleWorkerPath: await getWorkerUrl(),
});
showStatus('Fetching Events', `Fetching Deposit Events for ${networkName} ${currency.toUpperCase()} ${amount} Instance`);
const depositEvents = (await depositsService.updateEvents()).events;
showStatus('Fetching Events', `Creating Deposit Tree for ${networkName} ${currency.toUpperCase()} ${amount} Instance`);
const tree = await merkleTreeService.verifyTree(depositEvents);
showStatus('Fetching Events', `Fetching Withdrawal Events for ${networkName} ${currency.toUpperCase()} ${amount} Instance`);
const withdrawalEvents = (await withdrawalService.updateEvents()).events;
return {
depositEvents,
withdrawalEvents,
tree,
};
}
async function compliance(depositEvent, withdrawalEvent) {
const { netId, amount, currency } = getNote() || {};
const config = Tornado.getConfig(netId);
const {
networkName,
explorerUrl,
tokens: {
[currency]: {
decimals,
}
}
} = config;
const depositDate = new Date(depositEvent.timestamp * 1000);
const withdrawalDate = withdrawalEvent ? new Date(withdrawalEvent.timestamp * 1000) : undefined;
showCompliance(
'Compliance',
`Following is a compliance info for your deposit and withdrawal from ${networkName} ${currency.toUpperCase()} ${amount} deposit`,
`
<table class="table table-bordered">
<tbody>
<tr>
<td>Deposit Date</td>
<td>${depositDate.toLocaleDateString()} ${depositDate.toLocaleTimeString()} (${moment.unix(depositEvent.timestamp).fromNow()})</td>
</tr>
<tr>
<td>From</td>
<td><a href="${explorerUrl}/address/${depositEvent.from}" target="_blank" rel="noreferrer nofollow">${depositEvent.from}</a></td>
</tr>
<tr>
<td>Deposit Transaction</td>
<td><a href="${explorerUrl}/tx/${depositEvent.transactionHash}" target="_blank" rel="noreferrer nofollow">${depositEvent.transactionHash}</a></td>
</tr>
<tr>
<td>Commitment</td>
<td>${depositEvent.commitment}</td>
</tr>
<tr>
<td>Spent</td>
<td>${Boolean(withdrawalEvent)}</td>
</tr>
${!withdrawalEvent ? '' : `
<tr>
<td>Withdrawal Date</td>
<td>${withdrawalDate.toLocaleDateString()} ${withdrawalDate.toLocaleTimeString()} (${moment.unix(withdrawalEvent.timestamp).fromNow()})</td>
</tr>
<tr>
<td>Relayer Fee</td>
<td>${ethers.formatUnits(withdrawalEvent.fee, decimals)} ${currency.toUpperCase()}</td>
</tr>
<tr>
<td>To</td>
<td><a href="${explorerUrl}/address/${withdrawalEvent.to}" target="_blank" rel="noreferrer nofollow">${withdrawalEvent.to}</a></td>
</tr>
<tr>
<td>Withdrawal Transaction</td>
<td><a href="${explorerUrl}/tx/${withdrawalEvent.transactionHash}" target="_blank" rel="noreferrer nofollow">${withdrawalEvent.transactionHash}</a></td>
</tr>
<tr>
<td>Nullifier</td>
<td>${withdrawalEvent.nullifierHash}</td>
</tr>
`}
</tbody>
</table>
`
);
}
async function createProof(depositEvent, tree, relayerClient) {
if (typeof WebAssembly === 'undefined') {
throw new Error('Please turn on WebAssembly in your browser settings.<br /> If you are using Tor browser, enable javascript.options.wasm in about:config');
}
job = {};
const { note } = getNote() || {};
// Use donation address if the recipient is unspecified
const recipient = getRecipient() || DONATION_ADDRESS;
const isWallet = $('#note-relayer').find(':selected').val() === 'wallet';
const {
netId,
currency,
amount,
nullifierHex,
nullifier,
secret,
} = await Tornado.Deposit.parseNote(note);
const {
pathElements,
pathIndices,
} = tree.path(depositEvent.leafIndex);
const config = Tornado.getConfig(netId);
const {
explorerUrl,
networkName,
nativeCurrency,
routerContract,
ovmGasPriceOracleContract,
offchainOracleContract,
multicallContract,
tokens: {
[currency]: {
decimals,
tokenAddress,
gasLimit: instanceGasLimit,
tokenGasLimit,
instanceAddress: {
[amount]: instanceAddress,
},
},
},
} = config;
const isEth = currency === nativeCurrency;
const denomination = ethers.parseUnits(amount, decimals);
const firstAmount = Object.keys(config.tokens[currency].instanceAddress).sort((a, b) => Number(a) - Number(b))[0];
const isFirstAmount = Number(amount) === Number(firstAmount);
const provider = Tornado.getProviderWithNetId(
netId,
await getRpcUrl(netId),
config,
);
const signer = isWallet ? await getSigner(netId) : undefined;
const TornadoProxy = TornadoContracts.TornadoRouter__factory.connect(
routerContract,
!isWallet ? provider : signer,
);
const tornadoFeeOracle = new Tornado.TornadoFeeOracle(
ovmGasPriceOracleContract
? TornadoContracts.OvmGasPriceOracle__factory.connect(ovmGasPriceOracleContract, provider)
: undefined,
);
const tokenPriceOracle = new Tornado.TokenPriceOracle(
provider,
TornadoContracts.Multicall__factory.connect(multicallContract, provider),
offchainOracleContract
? TornadoContracts.OffchainOracle__factory.connect(offchainOracleContract, provider)
: undefined
);
showStatus('Fetching Keys', 'Fetching Circuits and Proving Keys');
const [circuit, provingKey, l1Fee, tokenPriceInWei, feeData] = await Promise.all([
getCircuit(),
getProvingKey(),
tornadoFeeOracle.fetchL1OptimismFee(),
!isEth ? tokenPriceOracle.fetchPrices([{ tokenAddress, decimals }]).then(p => p[0]) : BigInt(0),
provider.getFeeData(),
]);
let gasPrice = feeData.maxFeePerGas
? feeData.maxFeePerGas + (feeData.maxPriorityFeePerGas || BigInt(0))
: feeData.gasPrice;
if (!isWallet && !relayerClient?.tovarish && netId === Tornado.NetId.BSC) {
gasPrice = ethers.parseUnits('3.3', 'gwei');
}
// If the config overrides default gas limit we override
const defaultGasLimit = instanceGasLimit ? BigInt(instanceGasLimit) : BigInt(DEFAULT_GAS_LIMIT);
let gasLimit = defaultGasLimit;
// If the denomination is small only refund small amount otherwise use the default value
const refundGasLimit = isFirstAmount && tokenGasLimit ? BigInt(tokenGasLimit) : undefined;
async function getProof() {
let relayer = ethers.ZeroAddress;
let fee = BigInt(0);
let refund = BigInt(0);
if (!isWallet) {
if (!isEth) {
refund = tornadoFeeOracle.defaultEthRefund(gasPrice, refundGasLimit);
}
const {
rewardAccount,
tornadoServiceFee: relayerFeePercent,
} = relayerClient?.selectedRelayer || {};
fee = tornadoFeeOracle.calculateRelayerFee({
gasPrice,
gasLimit,
l1Fee,
denomination,
ethRefund: refund,
tokenPriceInWei,
tokenDecimals: decimals,
relayerFeePercent,
isEth,
});
relayer = rewardAccount;
if (fee > denomination) {
const errMsg = `Relayer fee ${ethers.formatUnits(fee, decimals)} ${currency.toUpperCase()} ` +
`exceeds the deposit amount ${amount} ${currency.toUpperCase()}.`;
throw new Error(errMsg);
}
}
const { proof, args } = await Tornado.calculateSnarkProof(
{
root: tree.root,
nullifierHex,
recipient,
relayer,
fee,
refund,
nullifier,
secret,
pathElements,
pathIndices,
},
circuit,
provingKey,
);
return {
fee,
refund,
proof,
args,
};
}
showStatus('Creating Proof', 'Calculating Withdrawal Proof');
let { fee, refund, proof, args } = await getProof();
const withdrawOverrides = {
from: !isWallet ? relayerClient?.selectedRelayer?.rewardAccount : signer?.address,
value: args[5] || 0,
};
gasLimit = await TornadoProxy.withdraw.estimateGas(instanceAddress, proof, ...args, withdrawOverrides);
if (gasLimit > defaultGasLimit) {
({ fee, refund, proof, args } = await getProof());
gasLimit = await TornadoProxy.withdraw.estimateGas(instanceAddress, proof, ...args, withdrawOverrides);
}
let withdrawTable = '';
if (!isWallet) {
withdrawTable = `
<tr>
<td>Relayer</td>
<td>${relayerClient?.selectedRelayer?.url}</td>
</tr>
<tr>
<td>Relayer Fee</td>
<td>${ethers.formatUnits(fee, decimals)} ${currency.toUpperCase()} (${((Number(fee) / Number(denomination)) * 100).toFixed(5)}%)</td>
</tr>
<tr>
<td>Relayer Fee Percent</td>
<td>${relayerClient?.selectedRelayer?.tornadoServiceFee}%</td>
</tr>
<tr>
<td>Amount to receive</td>
<td>${Number(ethers.formatUnits(denomination - fee, decimals)).toFixed(5)} ${currency.toUpperCase()}</td>
</tr>
<tr>
<td>${nativeCurrency.toUpperCase()} purchase</td>
<td>${ethers.formatEther(refund)} ${nativeCurrency.toUpperCase()}</td>
</tr>
<tr>
<td>To</td>
<td><a href="${explorerUrl}/address/${recipient}" target="_blank" rel="noreferrer nofollow">${recipient === DONATION_ADDRESS ? 'Donation' : recipient}</a></td>
</tr>
<tr>
<td>Nullifier</td>
<td>${nullifierHex}</td>
</tr>
`;
} else {
const txFee = gasPrice * gasLimit;
const txFeeInToken = !isEth
? tornadoFeeOracle.calculateTokenAmount(txFee, tokenPriceInWei, decimals)
: BigInt(0);
const txFeeString = !isEth
? `(${Number(ethers.formatUnits(txFeeInToken, decimals)).toFixed(5)} ${currency.toUpperCase()} worth) ` +
`(${((Number(ethers.formatUnits(txFeeInToken, decimals)) / Number(amount)) * 100).toFixed(5)}%)`
: `(${((Number(ethers.formatUnits(txFee, decimals)) / Number(amount)) * 100).toFixed(5)}%)`;
withdrawTable = `
<tr>
<td>Signer</td>
<td><a href="${explorerUrl}/address/${signer?.address}" target="_blank" rel="noreferrer nofollow">${signer?.address}</a></td>
</tr>
<tr>
<td>Transaction Fee</td>
<td>${Number(ethers.formatEther(txFee)).toFixed(5)} ${nativeCurrency.toUpperCase()} ${txFeeString}</td>
</tr>
<tr>
<td>Amount to receive</td>
<td>${amount} ${currency.toUpperCase()}</td>
</tr>
<tr>
<td>To</td>
<td><a href="${explorerUrl}/address/${recipient}" target="_blank" rel="noreferrer nofollow">${recipient === DONATION_ADDRESS ? 'Donation' : recipient}</a></td>
</tr>
<tr>
<td>Nullifier</td>
<td>${nullifierHex}</td>
</tr>
`;
}
const depositDate = new Date(depositEvent.timestamp * 1000);
showConfirmation(
'Confirm Withdrawal',
`Review your withdrawal information for ${networkName} ${currency.toUpperCase()} ${amount} deposit`,
`
<table class="table table-bordered">
<tbody>
<tr>
<td>Deposit Date</td>
<td>${depositDate.toLocaleDateString()} ${depositDate.toLocaleTimeString()} (${moment.unix(depositEvent.timestamp).fromNow()})</td>
</tr>
<tr>
<td>From</td>
<td><a href="${explorerUrl}/address/${depositEvent.from}" target="_blank" rel="noreferrer nofollow">${depositEvent.from}</a></td>
</tr>
<tr>
<td>Deposit Transaction</td>
<td><a href="${explorerUrl}/tx/${depositEvent.transactionHash}" target="_blank" rel="noreferrer nofollow">${depositEvent.transactionHash}</a></td>
</tr>
<tr>
<td>Commitment</td>
<td>${depositEvent.commitment}</td>
</tr>
<tr>
<td>Gas Price</td>
<td>${ethers.formatUnits(gasPrice, 'gwei')} gwei</td>
</tr>
${withdrawTable}
</tbody>
</table>
`
);
job = {
netId,
isWallet,
explorerUrl,
TornadoProxy,
relayerClient,
contract: instanceAddress,
proof,
args,
};
}
// eslint-disable-next-line no-unused-vars
async function confirmWithdrawal() {
try {
if (!job.contract) {
throw new Error('Job not found');
}
const { isWallet, explorerUrl, TornadoProxy, relayerClient, contract, proof, args } = job;
if (!isWallet) {
let relayerStatus;
await relayerClient.tornadoWithdraw(
{
contract,
proof,
args,
},
(resp) => {
const { id, status, txHash, confirmations } = resp;
if (relayerStatus !== status) {
if (status === 'SENT') {
showStatus(
'Job sent',
`Relayer has sent withdrawal job ${id} ${explorerUrl}/tx/${txHash}`
);
} else if (status === 'MINED') {
showStatus(
'Job mined',
`Withdrawal tx ${explorerUrl}/tx/${txHash} has been mined (confirmations: ${confirmations})`
);
} else if (status === 'CONFIRMED') {
showStatus(
'Job completed',
`Withdrawal tx ${explorerUrl}/tx/${txHash} has been confirmed (confirmations: ${confirmations})`,
'success',
);
}
relayerStatus = status;
}
}
);
} else {
const { hash } = await TornadoProxy.withdraw(contract, proof, ...args);
showStatus(
'TX Sent',
`Sent withdrawal tx ${explorerUrl}/tx/${hash}`,
'success'
);
}
job = {};
} catch (err) {
showStatus('Withdrawal Failed', `Error while processing withdrawal: ${err.message}`, 'error');
console.log(err);
job = {};
}
}
// eslint-disable-next-line no-unused-vars
async function withdraw() {
Tornado.initGroth16();
const { note, netId } = getNote() || {};
if (!note) {
errorMsg('Note not found');
return;
}
try {
// Test provider connection
await Tornado.getProvider(await getRpcUrl(netId), {
netId,
});
} catch (err) {
errorMsg(`Failed to connect with RPC, make sure to change with working one on settings: ${err.message}`);
console.log(err);
return;
}
try {
// Toggle Modal
new bootstrap.Modal('#send', {}).toggle();
showStatus('Getting Relayers', 'Getting Relayer Clients');
const relayerClients = await getRelayerClients(netId);
if (!relayerClients) {
return;
}
const { relayerClient, tovarishClient } = relayerClients;
const { depositEvents, withdrawalEvents, tree } = await getEvents(tovarishClient);
const { commitmentHex, nullifierHex } = await Tornado.Deposit.parseNote(note);
const depositEvent = depositEvents.find(({ commitment }) => commitment === commitmentHex);
const withdrawalEvent = withdrawalEvents.find(({ nullifierHash }) => nullifierHash === nullifierHex);
if (!depositEvent) {
2024-10-08 04:00:30 +03:00
showStatus('Deposit not found', 'Can not find a deposit for your note, try again in a few minutes if you have recently made the deposi', 'error');
2024-10-08 03:21:59 +03:00
return;
}
// Draw compliance here
if (withdrawalEvent) {
compliance(depositEvent, withdrawalEvent);
return;
}
await createProof(depositEvent, tree, relayerClient);
} catch (err) {
showStatus('Error from Withdrawal', `Error while processing withdrawal: ${err.message}`, 'error');
console.log(err);
}
}
$(document).ready(async function() {
$('.version').text(VERSION);
$('.donation').attr('href', `https://etherscan.io/address/${DONATION_ADDRESS}`);
if (typeof WebAssembly === 'undefined') {
errorMsg('Error: Please turn on WebAssembly in your browser settings.<br /> If you are using Tor browser, enable javascript.options.wasm in about:config', true);
}
settingsDB = await Tornado.getIndexedDB();
if (!settingsDB.dbExists) {
errorMsg('Can not use IndexedDB, perfomance of this UI may be degraded', true);
}
if (new URL(window.location.href).protocol === 'https:') {
alertMsg(
2024-10-08 04:00:30 +03:00
'You are accessing the UI from the remote environment which allows us to barely audit or secure the environment. Consider using the UI from the local environment cloned from git',
2024-10-08 03:21:59 +03:00
true,
);
}
await loadSettings();
await getAllRelayers();
2024-10-08 17:42:36 +03:00
const parseInput = () => {
2024-10-08 03:21:59 +03:00
const { note, netId, currency, amount } = getNote() || {};
if (!note) {
hide('#on-note');
return;
}
const {
networkName,
} = Tornado.getConfig(netId);
displayRelayers(netId);
$('#note-network').val(networkName);
$('#note-currency').val(currency.toUpperCase());
$('#note-amount').val(amount);
show('#on-note');
};
parseInput();
$('#note').on('input', parseInput);
$('#note-relayer').on('change', () => {
const { note, netId } = getNote() || {};
if (!note) {
return;
}
const selectedRelayer = getSelectedRelayer();
if (!selectedRelayer || selectedRelayer.tovarishNetworks?.includes(netId)) {
return;
}
alertMsg(`Selected Classic Relayer (${selectedRelayer.ensName}) doesn't support Events API thus withdrawal process will be slower than usual, Select Tovarish Relayer to fix this`);
});
});
</script>
</body>
</html>