Compare commits
62 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9e3861c56f | ||
![]() |
03543f87a8 | ||
![]() |
02f79a0de0 | ||
![]() |
6130c46d90 | ||
![]() |
62f079608e | ||
![]() |
2cc751f9d2 | ||
![]() |
2623117f17 | ||
![]() |
2e96df3b7f | ||
![]() |
7342d41faf | ||
![]() |
22a372fae1 | ||
![]() |
1f24d46360 | ||
![]() |
59c252b826 | ||
![]() |
3f04b9392a | ||
![]() |
6ec1a509cf | ||
![]() |
0d700118d6 | ||
![]() |
03462c0a41 | ||
![]() |
937c221e22 | ||
![]() |
2fbd860f51 | ||
![]() |
ad0d1391dc | ||
![]() |
e49e3e0c0d | ||
![]() |
ed422786c0 | ||
![]() |
9d1f66eec0 | ||
![]() |
a8c238c2af | ||
![]() |
eb59acd319 | ||
![]() |
322184baf8 | ||
![]() |
b492ef6e20 | ||
![]() |
4ecde79c86 | ||
![]() |
2b61afbafe | ||
![]() |
aef16eda5f | ||
![]() |
5aef9e6d06 | ||
![]() |
ea97a39aff | ||
![]() |
11c87ff319 | ||
![]() |
064c481c02 | ||
![]() |
90ef7362bf | ||
![]() |
889f02fa8c | ||
![]() |
2ec1ed18b1 | ||
![]() |
ef4104a186 | ||
![]() |
21a19e6db7 | ||
![]() |
efcfac5774 | ||
![]() |
0b6e21f721 | ||
![]() |
479b1e798b | ||
![]() |
8d038c5869 | ||
![]() |
d11b01d83b | ||
![]() |
fb62cf3796 | ||
![]() |
a9b27bf4c1 | ||
![]() |
d7d9ebe214 | ||
![]() |
b2304b7008 | ||
![]() |
61c2865c46 | ||
![]() |
85a222d93a | ||
![]() |
5da31361c6 | ||
![]() |
ef04356f84 | ||
![]() |
2b059eb0f9 | ||
![]() |
a628c50b32 | ||
![]() |
7787a8d207 | ||
![]() |
c1155ed3ad | ||
![]() |
1d15649faa | ||
![]() |
551bf1a98e | ||
![]() |
c80e4bb2fb | ||
![]() |
1702178aa9 | ||
![]() |
9343eeeea5 | ||
![]() |
b277b603c9 | ||
![]() |
35a02aa949 |
.gitignore.npmrcREADME.md
assets/styles/components
components
DepositModalBox.vueFooter.vue
Loaders
Navbar.vueNotices.vueSettings.vueStatistics.vuegovernance
withdraw
constants
langs
lib
modules/account/store/actions/decryptNotes
networkConfig.jsnuxt.config.jspackage.jsonpages
plugins
scripts
services
static/events
deposits_100_xdai_100.json.gzdeposits_100_xdai_1000.json.gzdeposits_100_xdai_10000.json.gzdeposits_100_xdai_100000.json.gzdeposits_137_matic_100.json.gzdeposits_137_matic_1000.json.gzdeposits_137_matic_10000.json.gzdeposits_137_matic_100000.json.gzdeposits_1_eth_0.1.json.gzdeposits_1_eth_1.json.gzdeposits_1_eth_10.json.gzdeposits_1_eth_100.json.gzdeposits_56_bnb_0.1.json.gzdeposits_56_bnb_1.json.gzdeposits_56_bnb_10.json.gzdeposits_56_bnb_100.json.gzdeposits_bnb_0.1.json.zipdeposits_bnb_1.json.zipdeposits_bnb_10.json.zipdeposits_bnb_100.json.zipdeposits_eth_0.1.json.zipdeposits_eth_1.json.zipdeposits_eth_10.json.zipdeposits_eth_100.json.zipdeposits_matic_100.json.zipdeposits_matic_1000.json.zipdeposits_matic_10000.json.zipdeposits_matic_100000.json.zipdeposits_xdai_100.json.zipdeposits_xdai_1000.json.zipdeposits_xdai_10000.json.zipdeposits_xdai_100000.json.zipencrypted_notes_1.json.gzencrypted_notes_1.json.zipencrypted_notes_100.json.gzencrypted_notes_100.json.zipencrypted_notes_137.json.gzencrypted_notes_137.json.zipencrypted_notes_5.json.gzencrypted_notes_56.json.gzencrypted_notes_56.json.zipwithdrawals_100_xdai_100.json.gzwithdrawals_100_xdai_1000.json.gzwithdrawals_100_xdai_10000.json.gzwithdrawals_100_xdai_100000.json.gzwithdrawals_137_matic_100.json.gzwithdrawals_137_matic_1000.json.gzwithdrawals_137_matic_10000.json.gzwithdrawals_137_matic_100000.json.gzwithdrawals_1_eth_0.1.json.gzwithdrawals_1_eth_1.json.gzwithdrawals_1_eth_10.json.gzwithdrawals_1_eth_100.json.gzwithdrawals_56_bnb_0.1.json.gzwithdrawals_56_bnb_1.json.gzwithdrawals_56_bnb_10.json.gzwithdrawals_56_bnb_100.json.gzwithdrawals_bnb_0.1.json.zipwithdrawals_bnb_1.json.zip
3
.gitignore
vendored
3
.gitignore
vendored
@ -87,3 +87,6 @@ sw.*
|
||||
|
||||
# Mac OSX
|
||||
.DS_Store
|
||||
|
||||
|
||||
static/*/*.json
|
1
.npmrc
Normal file
1
.npmrc
Normal file
@ -0,0 +1 @@
|
||||
@tornado:registry=https://git.tornado.ws/api/packages/tornado-packages/npm/
|
37
README.md
37
README.md
@ -1,6 +1,6 @@
|
||||
# Tornado Cash Classic UI
|
||||
|
||||
> UI for non-custodial Ethereum Privacy solution
|
||||
> Self-hostable Tornado Cash UI software for interacting with the protocol
|
||||
|
||||
## Building locally
|
||||
|
||||
@ -27,33 +27,46 @@ For detailed explanation on how things work, checkout [Nuxt.js docs](https://nux
|
||||
|
||||
## Audit
|
||||
|
||||
[TornadoCash_Classic_dApp_audit_Decurity.pdf](https://tornado.cash/audits/TornadoCash_Classic_dApp_audit_Decurity.pdf)
|
||||
[TornadoCash_Classic_dApp_audit_Decurity.pdf](https://ipfs.io/ipfs/QmXzmwfsb4GwzmPD7W9VDNHh7ttyYKgXCY74973QMZqBDA)
|
||||
|
||||
## Update cached files
|
||||
|
||||
- For update deposits and withdrawals events use `yarn update:events {chainId}`
|
||||
- For update encrypted notes use `yarn update:encrypted {chainId}`
|
||||
- For update merkle tree use `yarn update:tree {chainId}`
|
||||
- To update deposit and withdrawal events use `yarn update:events {chainId} {optional: tokenOrEvent} {optional: tokenOrEvent}`
|
||||
- To update encrypted notes use `yarn update:encrypted {chainId}`
|
||||
- To update merkle tree use `yarn update:tree {chainId}`
|
||||
|
||||
#### NOTE!
|
||||
|
||||
After update cached files do not forget to use `yarn update:zip`
|
||||
After updating cached files do not forget to use `yarn update:zip`.
|
||||
|
||||
### Example for Ethereum Mainnet:
|
||||
|
||||
```
|
||||
yarn update:events 1
|
||||
yarn update:encrypted 1
|
||||
yarn update:tree 1
|
||||
You may set in [`networkConfig.js`](./networkConfig.js) the `blockSyncInterval` (def: 10_000) to the maximum value allowed by your RPC provider. Command usage follows below.
|
||||
|
||||
```bash
|
||||
# Updating events with just the required chain id parameter
|
||||
yarn update:events 1
|
||||
# Updating events for only one token across all instances on that network
|
||||
yarn update:events 1 dai
|
||||
# Updating events for only one event on only some network
|
||||
yarn update:events 1 deposit
|
||||
# Both
|
||||
yarn update:events 1 dai deposit
|
||||
# Updating encrypted notes for some chain id
|
||||
yarn update:encrypted 1
|
||||
# Updating trees for some chain id
|
||||
yarn update:tree 1
|
||||
# Finally zips must be updated
|
||||
yarn update:zip
|
||||
```
|
||||
|
||||
### Example for Binance Smart Chain:
|
||||
|
||||
```
|
||||
```bash
|
||||
yarn update:events 56
|
||||
yarn update:events 56 bnb
|
||||
yarn update:events 56 bnb deposit
|
||||
yarn update:encrypted 56
|
||||
|
||||
yarn update:tree 56
|
||||
yarn update:zip
|
||||
```
|
||||
|
@ -293,6 +293,10 @@
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M297.216 243.2c0 15.616-11.52 28.416-26.112 28.416-14.336 0-26.112-12.8-26.112-28.416s11.52-28.416 26.112-28.416c14.592 0 26.112 12.8 26.112 28.416zm-119.552-28.416c-14.592 0-26.112 12.8-26.112 28.416s11.776 28.416 26.112 28.416c14.592 0 26.112-12.8 26.112-28.416.256-15.616-11.52-28.416-26.112-28.416zM448 52.736V512c-64.494-56.994-43.868-38.128-118.784-107.776l13.568 47.36H52.48C23.552 451.584 0 428.032 0 398.848V52.736C0 23.552 23.552 0 52.48 0h343.04C424.448 0 448 23.552 448 52.736zm-72.96 242.688c0-82.432-36.864-149.248-36.864-149.248-36.864-27.648-71.936-26.88-71.936-26.88l-3.584 4.096c43.52 13.312 63.744 32.512 63.744 32.512-60.811-33.329-132.244-33.335-191.232-7.424-9.472 4.352-15.104 7.424-15.104 7.424s21.248-20.224 67.328-33.536l-2.56-3.072s-35.072-.768-71.936 26.88c0 0-36.864 66.816-36.864 149.248 0 0 21.504 37.12 78.08 38.912 0 0 9.472-11.52 17.152-21.248-32.512-9.728-44.8-30.208-44.8-30.208 3.766 2.636 9.976 6.053 10.496 6.4 43.21 24.198 104.588 32.126 159.744 8.96 8.96-3.328 18.944-8.192 29.44-15.104 0 0-12.8 20.992-46.336 30.464 7.68 9.728 16.896 20.736 16.896 20.736 56.576-1.792 78.336-38.912 78.336-38.912z'%3E%3C/path%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
&-git {
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='92pt' height='92pt' viewBox='0 0 92 92'%3E%3Cpath style='stroke:none;fill-rule:nonzero;fill:%6b6b6b;fill-opacity:1' d='M90.156 41.965 50.036 1.848a5.918 5.918 0 0 0-8.372 0l-8.328 8.332 10.566 10.566a7.03 7.03 0 0 1 7.23 1.684 7.034 7.034 0 0 1 1.669 7.277l10.187 10.184a7.028 7.028 0 0 1 7.278 1.672 7.04 7.04 0 0 1 0 9.957 7.05 7.05 0 0 1-9.965 0 7.044 7.044 0 0 1-1.528-7.66l-9.5-9.497V59.36a7.04 7.04 0 0 1 1.86 11.29 7.04 7.04 0 0 1-9.957 0 7.04 7.04 0 0 1 0-9.958 7.06 7.06 0 0 1 2.304-1.539V33.926a7.049 7.049 0 0 1-3.82-9.234L29.242 14.272 1.73 41.777a5.925 5.925 0 0 0 0 8.371L41.852 90.27a5.925 5.925 0 0 0 8.37 0l39.934-39.934a5.925 5.925 0 0 0 0-8.371'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
&-discourse {
|
||||
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3Cpath d='M225.9 32C103.3 32 0 130.5 0 252.1 0 256 .1 480 .1 480l225.8-.2c122.7 0 222.1-102.3 222.1-223.9C448 134.3 348.6 32 225.9 32zM224 384c-19.4 0-37.9-4.3-54.4-12.1L88.5 392l22.9-75c-9.8-18.1-15.4-38.9-15.4-61 0-70.7 57.3-128 128-128s128 57.3 128 128-57.3 128-128 128z'%3E%3C/path%3E%3C/svg%3E");
|
||||
}
|
||||
|
@ -1,3 +1,10 @@
|
||||
.warning {
|
||||
color: #ff8a00;
|
||||
border-color: #ff8a00;
|
||||
border-width: 2px;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.info {
|
||||
&-name {
|
||||
font-size: 0.929rem;
|
||||
|
@ -29,10 +29,8 @@
|
||||
{{ $t('saveAsFile') }} <span class="has-text-primary">{{ filename }}</span>
|
||||
</div>
|
||||
<template v-if="!isSetupAccount">
|
||||
<i18n tag="div" path="yourDontHaveAccount" class="notice">
|
||||
<template v-slot:account>
|
||||
<a @click="_redirectToAccount">{{ $t('account.button') }}</a>
|
||||
</template>
|
||||
<i18n tag="div" path="yourDontHaveAccount" class="notice warning">
|
||||
<template v-slot:account></template>
|
||||
</i18n>
|
||||
</template>
|
||||
<b-checkbox v-if="isSetupAccount" v-model="isEncrypted">
|
||||
|
@ -37,47 +37,15 @@
|
||||
<b-button
|
||||
tag="a"
|
||||
type="is-icon"
|
||||
href="https://forums.tornadocash.community"
|
||||
href="https://git.tornado.ws/tornadocash/classic-ui"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
icon-right="discourse"
|
||||
icon-right="git"
|
||||
></b-button>
|
||||
<b-button
|
||||
tag="a"
|
||||
type="is-icon"
|
||||
href="https://matrix.tornadocash.community"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
icon-right="matrix"
|
||||
></b-button>
|
||||
<b-button
|
||||
tag="a"
|
||||
type="is-icon"
|
||||
href="https://tornado-cash.medium.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
icon-right="medium"
|
||||
></b-button>
|
||||
<b-button
|
||||
tag="a"
|
||||
type="is-icon"
|
||||
href="https://twitter.com/TornadoCashOrg"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
icon-right="twitter"
|
||||
></b-button>
|
||||
<b-button
|
||||
tag="a"
|
||||
type="is-icon"
|
||||
href="https://t.me/TornadoCashOrg"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
icon-right="telegram"
|
||||
></b-button>
|
||||
<b-button
|
||||
tag="a"
|
||||
type="is-icon"
|
||||
href="https://development.tornadocash.community"
|
||||
href="https://github.com/tornadocash"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
icon-right="github"
|
||||
|
@ -3,15 +3,14 @@
|
||||
<div class="loading-container">
|
||||
<div class="loading-tornado" data-test="tornado_loader"></div>
|
||||
<div class="loading-message">{{ message }}...</div>
|
||||
<div v-if="progress >= 0" class="loading-message">{{ progress }}%</div>
|
||||
<approve-loader v-if="isApprove" />
|
||||
</div>
|
||||
</b-loading>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
|
||||
import ApproveLoader from './ApproveLoader'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ApproveLoader
|
||||
@ -19,7 +18,7 @@ export default {
|
||||
computed: {
|
||||
...mapGetters('metamask', ['isWalletConnect']),
|
||||
...mapState('metamask', ['providerName']),
|
||||
...mapState('loading', ['enabled', 'message', 'type']),
|
||||
...mapState('loading', ['enabled', 'message', 'progress', 'type']),
|
||||
isApprove() {
|
||||
return this.type === 'approve'
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
{{ $t('compliance') }}
|
||||
</b-navbar-item>
|
||||
<b-navbar-item
|
||||
href="https://docs.tornado.cash"
|
||||
href="https://docs.tornado.ws"
|
||||
target="_blank"
|
||||
data-test="docs_link"
|
||||
rel="noopener noreferrer"
|
||||
|
@ -18,12 +18,7 @@
|
||||
</template>
|
||||
<template v-slot:description>{{ notice.description }}</template>
|
||||
</i18n>
|
||||
<a
|
||||
v-if="notice.nova"
|
||||
href="https://nova.tornadocash.eth.link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<a v-if="notice.nova" href="https://nova.tornado.ws/" target="_blank" rel="noopener noreferrer">
|
||||
Tornado Cash Nova
|
||||
</a>
|
||||
<a
|
||||
|
@ -47,6 +47,51 @@
|
||||
{{ hasErrorRpc.msg }}
|
||||
</p>
|
||||
</div>
|
||||
<template v-if="!isEthereumNetwork">
|
||||
<div class="field">
|
||||
<b-field label="Ethereum RPC provider" class="has-custom-field" data-test="rpc_endpoint_eth_dropdown">
|
||||
<b-dropdown v-model="selectedEthRpc" expanded aria-role="list">
|
||||
<div slot="trigger" class="control" :class="{ 'is-loading': checkingRpc && !isCustomEthRpc }">
|
||||
<div class="input">
|
||||
<span>{{ isCustomEthRpc ? $t('customRpc') : selectedEthRpc }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<b-dropdown-item
|
||||
v-for="{ name, url } in Object.values(ethNetworkConfig.rpcUrls)"
|
||||
:key="name"
|
||||
:value="name"
|
||||
aria-role="listitem"
|
||||
:data-test="`rpc_endpoint_eth_${name}`"
|
||||
@click="checkEthRpc({ name, url })"
|
||||
>
|
||||
{{ name }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
value="custom"
|
||||
aria-role="listitem"
|
||||
data-test="rpc_endpoint_eth_custom"
|
||||
@click="checkEthRpc({ name: 'custom' })"
|
||||
>
|
||||
{{ $t('customRpc') }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</b-field>
|
||||
<div v-if="isCustomEthRpc" class="field has-custom-field">
|
||||
<b-input
|
||||
ref="customInputTwo"
|
||||
v-model="customEthRpcUrl"
|
||||
type="url"
|
||||
:placeholder="$t('customRpcPlaceholder')"
|
||||
:custom-class="hasErrorEthRpc.type"
|
||||
:use-html5-validation="false"
|
||||
@input="checkCustomEthRpc"
|
||||
></b-input>
|
||||
</div>
|
||||
<p v-if="hasErrorEthRpc.msg" class="help" :class="hasErrorEthRpc.type">
|
||||
{{ hasErrorEthRpc.msg }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<div class="buttons buttons__halfwidth">
|
||||
<b-button type="is-primary" outlined data-test="button_reset_rpc" @mousedown.prevent @click="onReset">
|
||||
{{ $t('reset') }}
|
||||
@ -75,9 +120,13 @@ export default {
|
||||
return {
|
||||
checkingRpc: false,
|
||||
hasErrorRpc: { type: '', msg: '' },
|
||||
hasErrorEthRpc: { type: '', msg: '' },
|
||||
customRpcUrl: '',
|
||||
customEthUrl: '',
|
||||
selectedRpc: 'custom',
|
||||
rpc: { name: 'custom', url: '' }
|
||||
selectedEthRpc: 'custom',
|
||||
rpc: { name: 'custom', url: '' },
|
||||
ethRpc: { name: 'custom', url: '' }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -85,9 +134,18 @@ export default {
|
||||
networkConfig() {
|
||||
return networkConfig[`netId${this.netId}`]
|
||||
},
|
||||
ethNetworkConfig() {
|
||||
return networkConfig.netId1
|
||||
},
|
||||
isEthereumNetwork() {
|
||||
return this.netId === 1
|
||||
},
|
||||
isCustomRpc() {
|
||||
return this.selectedRpc === 'custom'
|
||||
},
|
||||
isCustomEthRpc() {
|
||||
return this.selectedEthRpc === 'custom'
|
||||
},
|
||||
isDisabledSave() {
|
||||
return (
|
||||
this.hasErrorRpc.type === 'is-warning' || this.checkingRpc || (this.isCustomRpc && !this.customRpcUrl)
|
||||
@ -95,16 +153,24 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.ethRpc = this.getRpc(1)
|
||||
this.rpc = this.getRpc(this.netId)
|
||||
this.selectedRpc = this.rpc.name
|
||||
this.selectedEthRpc = this.ethRpc.name
|
||||
|
||||
if (this.selectedRpc === 'custom') {
|
||||
this.$nextTick(() => {
|
||||
this.customRpcUrl = this.rpc.url
|
||||
})
|
||||
}
|
||||
if (this.selectedEthRpc === 'custom') {
|
||||
this.$nextTick(() => {
|
||||
this.customEthRpcUrl = this.ethRpc.url
|
||||
})
|
||||
}
|
||||
|
||||
this.checkRpc(this.rpc)
|
||||
this.checkEthRpc(this.ethRpc)
|
||||
},
|
||||
methods: {
|
||||
...mapMutations('settings', ['SAVE_RPC']),
|
||||
@ -113,25 +179,40 @@ export default {
|
||||
this.hasErrorRpc = { type: '', msg: '' }
|
||||
|
||||
this.rpc = Object.entries(this.networkConfig.rpcUrls)[0][1]
|
||||
this.ethRpc = Object.entries(this.ethNetworkConfig.rpcUrls)[0][1]
|
||||
this.selectedRpc = this.rpc.name
|
||||
this.selectedEthRpc = this.ethRpc.name
|
||||
this.checkEthRpc(this.ethRpc)
|
||||
this.checkRpc(this.rpc)
|
||||
},
|
||||
onSave() {
|
||||
this.SAVE_RPC({ ...this.rpc, netId: this.netId })
|
||||
if (this.netId !== 1) {
|
||||
this.SAVE_RPC({ ...this.ethRpc, netId: 1 })
|
||||
}
|
||||
this.$emit('close')
|
||||
},
|
||||
onCancel() {
|
||||
this.$emit('cancel')
|
||||
},
|
||||
checkRpc({ name, url = '' }) {
|
||||
this.checkingRpc = true
|
||||
|
||||
if (name === 'custom') {
|
||||
this.customRpcUrl = ''
|
||||
this.hasErrorRpc = { type: '', msg: '' }
|
||||
this.checkingRpc = true
|
||||
}
|
||||
this._checkRpc({ name, url })
|
||||
},
|
||||
checkEthRpc({ name, url = '' }) {
|
||||
this.checkingRpc = true
|
||||
|
||||
if (name === 'custom') {
|
||||
this.customEthRpcUrl = ''
|
||||
this.hasErrorEthRpc = { type: '', msg: '' }
|
||||
return
|
||||
}
|
||||
|
||||
this._checkRpc({ name, url })
|
||||
this._checkEthRpc({ name, url })
|
||||
},
|
||||
checkCustomRpc(url) {
|
||||
const trimmedUrl = url.trim()
|
||||
@ -141,6 +222,14 @@ export default {
|
||||
}
|
||||
debounce(this._checkRpc, { name: 'custom', url: trimmedUrl })
|
||||
},
|
||||
checkCustomEthRpc(url) {
|
||||
const trimmedUrl = url.trim()
|
||||
if (!trimmedUrl) {
|
||||
this.hasErrorEthRpc = { type: '', msg: '' }
|
||||
return
|
||||
}
|
||||
debounce(this._checkEthRpc, { name: 'custom', url: trimmedUrl })
|
||||
},
|
||||
async _checkRpc({ name, url }) {
|
||||
this.checkingRpc = true
|
||||
this.hasErrorRpc = { type: '', msg: '' }
|
||||
@ -159,6 +248,27 @@ export default {
|
||||
this.hasErrorRpc.msg = error
|
||||
}
|
||||
|
||||
this.checkingRpc = false
|
||||
},
|
||||
async _checkEthRpc({ name, url }) {
|
||||
this.checkingRpc = true
|
||||
this.hasErrorEthRpc = { type: '', msg: '' }
|
||||
|
||||
const { isValid, error } = await this.$store.dispatch('settings/checkRpc', {
|
||||
url,
|
||||
netId: 1,
|
||||
isEthRpc: true
|
||||
})
|
||||
|
||||
if (isValid) {
|
||||
this.hasErrorEthRpc.type = 'is-primary'
|
||||
this.hasErrorEthRpc.msg = this.$t('rpcStatusOk')
|
||||
this.ethRpc = { name, url }
|
||||
} else {
|
||||
this.hasErrorEthRpc.type = 'is-warning'
|
||||
this.hasErrorEthRpc.msg = error
|
||||
}
|
||||
|
||||
this.checkingRpc = false
|
||||
}
|
||||
}
|
||||
|
@ -93,9 +93,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.timer) {
|
||||
this.updateEvents()
|
||||
}
|
||||
this.updateEvents()
|
||||
},
|
||||
beforeDestroy() {
|
||||
clearTimeout(this.timer)
|
||||
@ -103,10 +101,6 @@ export default {
|
||||
methods: {
|
||||
updateEvents() {
|
||||
this.$store.dispatch('application/updateSelectEvents')
|
||||
|
||||
this.timer = setTimeout(() => {
|
||||
this.updateEvents()
|
||||
}, 60 * 1000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,8 +59,13 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('governance/gov', ['lockedBalance', 'proposals']),
|
||||
...mapGetters('governance/gov', ['isFetchingProposals', 'constants', 'isFetchingBalances']),
|
||||
...mapState('governance/gov', ['proposals']),
|
||||
...mapGetters('governance/gov', [
|
||||
'isFetchingProposals',
|
||||
'constants',
|
||||
'isFetchingBalances',
|
||||
'votingPower'
|
||||
]),
|
||||
...mapGetters('token', ['toDecimals']),
|
||||
filteredProposals() {
|
||||
return this.proposals
|
||||
@ -74,7 +79,7 @@ export default {
|
||||
},
|
||||
hasProposalThreshold() {
|
||||
const PROPOSAL_THRESHOLD = toBN(this.constants.PROPOSAL_THRESHOLD)
|
||||
return toBN(this.lockedBalance).gte(PROPOSAL_THRESHOLD)
|
||||
return toBN(this.votingPower).gte(PROPOSAL_THRESHOLD)
|
||||
},
|
||||
proposalThreshold() {
|
||||
return this.toDecimals(this.constants.PROPOSAL_THRESHOLD, 18)
|
||||
|
@ -51,8 +51,7 @@
|
||||
data-test="enter_note_field"
|
||||
></b-input>
|
||||
<div v-if="hasErrorNote" class="help" :class="hasErrorNote.type">
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<p v-html="hasErrorNote.msg"></p>
|
||||
<p>{{ hasErrorNote.msg }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!hasErrorNote && depositTxHash" class="field field-withdraw">
|
||||
@ -341,6 +340,7 @@ export default {
|
||||
if (currency !== this.nativeCurrency) {
|
||||
this.$store.dispatch('application/setDefaultEthToReceive', { currency })
|
||||
}
|
||||
this.$store.dispatch('loading/updateProgress', { progress: -1 })
|
||||
this.depositsPast = Number(depositsPast) <= 0 ? 0 : depositsPast
|
||||
this.depositTxHash = txHash
|
||||
this.depositTimestamp = timestamp
|
||||
|
@ -60,6 +60,12 @@ export const cachedEventsLength = {
|
||||
}
|
||||
}
|
||||
|
||||
export const httpConfig = {
|
||||
// buffer for tor connections
|
||||
timeout: 30000,
|
||||
keepAlive: true
|
||||
}
|
||||
|
||||
export const PROVIDERS = {
|
||||
walletConnect: {
|
||||
name: 'WalletConnect',
|
||||
|
@ -37,7 +37,7 @@
|
||||
"iBackedUpTheNote": "I backed up the note",
|
||||
"iEncryptedTheNote": "Create an on-chain backup of this note with your Account {address}",
|
||||
"yourNoteWontBeSaved": "Your note won't be saved in your browser. Please make sure it's backed up!",
|
||||
"yourDontHaveAccount": "You can also save encrypted notes on-chain by setting up the Note Account. Create one on the {account} page.",
|
||||
"yourDontHaveAccount": "FAILURE TO BACKUP NOTES WILL RESULT IN LOSS OF FUNDS",
|
||||
"sendDeposit": "Send Deposit",
|
||||
"clickToCopy": "Click to copy",
|
||||
"copied": "Copied!",
|
||||
@ -151,7 +151,7 @@
|
||||
"nullifierHash": "Nullifier Hash",
|
||||
"verified": "Verified",
|
||||
"generatePdfReport": "Generate PDF report",
|
||||
"compliancePrintWarning": "This Compliance Report is for informational purposes only. You should confirm the validity of this report by using Tornado’s Compliance Tool (https://tornadocash.eth.link/compliance) or via any other cryptographic software that can compute and verify the information contained herein(the \"Tornado Compliance Tool\"). Any discrepancies between information found in this report and provided by the above tool indicate that the information in this report may be inaccurate and/or fraudulent.{newline}THE COMPLIANCE REPORT IS PROVIDED \"AS IS,\" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OF THE TORNADO.CASH COMPLIANCE TOOL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS COMPLIANCE REPORT.",
|
||||
"compliancePrintWarning": "This Compliance Report is for informational purposes only. You should confirm the validity of this report by using Tornado’s Compliance Tool (https://tornado.ws/compliance) or via any other cryptographic software that can compute and verify the information contained herein(the \"Tornado Compliance Tool\"). Any discrepancies between information found in this report and provided by the above tool indicate that the information in this report may be inaccurate and/or fraudulent.{newline}THE COMPLIANCE REPORT IS PROVIDED \"AS IS,\" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OF THE TORNADO.CASH COMPLIANCE TOOL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS COMPLIANCE REPORT.",
|
||||
"relayRequestFailed": "Relayer {relayerName} is down. Please choose a different relayer.",
|
||||
"selectProvider": "Select provider",
|
||||
"walletDoesNotSupported": "The wallet is not supported",
|
||||
|
@ -151,7 +151,7 @@
|
||||
"nullifierHash": "Hash del Nullifier",
|
||||
"verified": "Verificador",
|
||||
"generatePdfReport": "Genere informe PDF",
|
||||
"compliancePrintWarning": "Este Informe de Compromiso es para propósito informativo unicamente. Debería confirmar la validez de este informe utilizando la Herramienta de Cumplimiento de Tornado (https://tornadocash.eth.link/compliance) o cualquier otro software criptográfico que pueda procesar y verificar la información contenida aquí(la \"Tornado Compliance Tool\"). Cualquier discrepancia entre la información recogida en este informe y entregado por la herramienta anterior indica que este informe no es riguroso y/o fraudulento.{newline}EL INFORME DE CUMPLIMIENTO SE PRESENTA \"COMO TAL,\" SIN GARANTÍA DE NINGÚN TIPO, EXPRESA O IMPLÍCITAMENTE, INCLUYENDO PERO NO LIMITADA A LAS GARANTÍAS MERCANTILES, ADECUADAS PARA UN PROPÓSITO PARTICULAR Y LA NO INFRACCIÓN. EN NINGÚN CASO DEBERÍAN LOS AUTORES DE LA HERRAMIENTA DE CUMPLIMIENTO DE TORNADO.CASH SER RESPONSABLES U OBJETO DE CUALQUIER RECLAMO, DAÑO U OTRA RESPONSABILIDAD, YA SEA EN ACCIÓN CONTRACTUAL, AGRAVIADO O DE CUALQUIER OTRO MODO, DERIVADO DE, PRODUCTO DE O EN CONEXIÓN CON EL MENCIONADO INFORME DE CUMPLIMIENTO.",
|
||||
"compliancePrintWarning": "Este Informe de Compromiso es para propósito informativo unicamente. Debería confirmar la validez de este informe utilizando la Herramienta de Cumplimiento de Tornado (https://tornado.ws/compliance) o cualquier otro software criptográfico que pueda procesar y verificar la información contenida aquí(la \"Tornado Compliance Tool\"). Cualquier discrepancia entre la información recogida en este informe y entregado por la herramienta anterior indica que este informe no es riguroso y/o fraudulento.{newline}EL INFORME DE CUMPLIMIENTO SE PRESENTA \"COMO TAL,\" SIN GARANTÍA DE NINGÚN TIPO, EXPRESA O IMPLÍCITAMENTE, INCLUYENDO PERO NO LIMITADA A LAS GARANTÍAS MERCANTILES, ADECUADAS PARA UN PROPÓSITO PARTICULAR Y LA NO INFRACCIÓN. EN NINGÚN CASO DEBERÍAN LOS AUTORES DE LA HERRAMIENTA DE CUMPLIMIENTO DE TORNADO.CASH SER RESPONSABLES U OBJETO DE CUALQUIER RECLAMO, DAÑO U OTRA RESPONSABILIDAD, YA SEA EN ACCIÓN CONTRACTUAL, AGRAVIADO O DE CUALQUIER OTRO MODO, DERIVADO DE, PRODUCTO DE O EN CONEXIÓN CON EL MENCIONADO INFORME DE CUMPLIMIENTO.",
|
||||
"relayRequestFailed": "El retransmisor {relayerName} no responde. Por favor escoja uno diferente.",
|
||||
"selectProvider": "Seleccione proveedor",
|
||||
"walletDoesNotSupported": "El monedero no es compatible",
|
||||
|
@ -151,7 +151,7 @@
|
||||
"nullifierHash": "Hash Nullifié",
|
||||
"verified": "Verifié",
|
||||
"generatePdfReport": "Générer un rapport PDF",
|
||||
"compliancePrintWarning": "Ce rapport de conformité est uniquement destiné à des fins d'information. Vous devez confirmer la validité de ce rapport en utilisant l'outil de conformité de Tornado (https://tornadocash.eth.link/compliance) ou tout autre logiciel cryptographique capable de calculer et de vérifier les informations contenues dans ce document (l' \"Outil de Conformité Tornado\"). Toute divergence entre les informations trouvées dans ce rapport et celles fournies par l'outil susmentionné indique que les informations contenues dans ce rapport sont inexactes et/ou frauduleuses.{newline}LE RAPPORT DE CONFORMITÉ EST FOURNI \"EN L'ÉTAT\", SANS GARANTIE D'AUCUNE SORTE, EXPRESSE OU IMPLICITE, Y COMPRIS, MAIS SANS S'Y LIMITER, LES GARANTIES DE QUALITÉ MARCHANDE, D'ADÉQUATION À UN USAGE PARTICULIER ET D'ABSENCE DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS DE L'OUTIL DE CONFORMITÉ TORNADO.CASH NE POURRONT ÊTRE TENUS RESPONSABLES DE TOUTE RÉCLAMATION, DE TOUT DOMMAGE OU DE TOUTE AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D'UNE ACTION CONTRACTUELLE, DÉLICTUELLE OU AUTRE, DÉCOULANT DE, EN DEHORS DE OU EN RELATION AVEC CE RAPPORT DE CONFORMITÉ.",
|
||||
"compliancePrintWarning": "Ce rapport de conformité est uniquement destiné à des fins d'information. Vous devez confirmer la validité de ce rapport en utilisant l'outil de conformité de Tornado (https://tornado.ws/compliance) ou tout autre logiciel cryptographique capable de calculer et de vérifier les informations contenues dans ce document (l' \"Outil de Conformité Tornado\"). Toute divergence entre les informations trouvées dans ce rapport et celles fournies par l'outil susmentionné indique que les informations contenues dans ce rapport sont inexactes et/ou frauduleuses.{newline}LE RAPPORT DE CONFORMITÉ EST FOURNI \"EN L'ÉTAT\", SANS GARANTIE D'AUCUNE SORTE, EXPRESSE OU IMPLICITE, Y COMPRIS, MAIS SANS S'Y LIMITER, LES GARANTIES DE QUALITÉ MARCHANDE, D'ADÉQUATION À UN USAGE PARTICULIER ET D'ABSENCE DE CONTREFAÇON. EN AUCUN CAS, LES AUTEURS DE L'OUTIL DE CONFORMITÉ TORNADO.CASH NE POURRONT ÊTRE TENUS RESPONSABLES DE TOUTE RÉCLAMATION, DE TOUT DOMMAGE OU DE TOUTE AUTRE RESPONSABILITÉ, QUE CE SOIT DANS LE CADRE D'UNE ACTION CONTRACTUELLE, DÉLICTUELLE OU AUTRE, DÉCOULANT DE, EN DEHORS DE OU EN RELATION AVEC CE RAPPORT DE CONFORMITÉ.",
|
||||
"relayRequestFailed": "Le relais {relayerName} est en panne. Veuillez choisir un autre relais.",
|
||||
"selectProvider": "Sélectionner le fournisseur",
|
||||
"walletDoesNotSupported": "Le portefeuille n'est pas supporté",
|
||||
|
@ -37,7 +37,7 @@
|
||||
"iBackedUpTheNote": "Я сделал резервную копию",
|
||||
"iEncryptedTheNote": "Создать резервную копию этой Note в блокчейне с помощью Аккаунта {address}",
|
||||
"yourNoteWontBeSaved": "Ваша Note не будет сохранена в браузере. Убедитесь, что вы сделали резервную копию!",
|
||||
"yourDontHaveAccount": "Вы также можете сохранять зашифрованные Note в блокчейне, создав аккаунт для приватных Note. Создайте его на странице {account}.",
|
||||
"yourDontHaveAccount": "НЕВОЗМОЖНОСТЬ СОЗДАТЬ РЕЗЕРВНУЮ ЗАПИСКУ ПРИВЕДЕТ К ПОТЕРЕ СРЕДСТВ",
|
||||
"sendDeposit": "Отправить депозит",
|
||||
"clickToCopy": "Скопировать",
|
||||
"copied": "Скопировано!",
|
||||
@ -151,7 +151,7 @@
|
||||
"nullifierHash": "Nullifier Hash",
|
||||
"verified": "Подтверждено",
|
||||
"generatePdfReport": "Сгенерировать PDF отчёт",
|
||||
"compliancePrintWarning": "Настоящий отчет о соответствии носит исключительно информационный характер. Вы должны подтвердить действительность этого отчета с помощью средства проверки соответствия Tornado (https://tornadocash.eth.link/compliance) или с помощью любого другого криптографического программного обеспечения, которое может обработать и проверить информацию, содержащуюся в этом отчете(\"Tornado Compliance Tool\"). Любые расхождения между информацией, приведенной в данном отчете и предоставленной вышеуказанным инструментом, указывают на то, что информация, содержащаяся в этом отчете, является неточной и/или мошеннической.{newline}ОТЧЕТ О СООТВЕТСТВИИ ПРЕДОСТАВЛЯЕТСЯ \"КАК ЕСТЬ,\" БЕЗ ГАРАНТИЙ ЛЮБОГО РОДА, ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОГО КАЧЕСТВА, ПРИГОДНОСТЬЮ К КОНКРЕТНОЙ ЦЕЛИ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОРЫ ИНСТРУМЕНТА СООТВЕТСТВИЯ TORNADO.CASH НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УЩЕРБ ИЛИ ДРУГУЮ ОТВЕТСТВЕННОСТЬ, ОТНОСЯЩУЮСЯ К ДЕЙСТВИЮ ДОГОВОРОВ, ГРАЖДАНСКИМ ПРАВОНАРУШЕНИЯМ, А ТАКЖЕ ВЫТЕКАЮЩУЮ ИЗ НАСТОЯЩЕГО ОТЧЕТА О СООТВЕТСТВИИ ИЛИ СВЯЗАННУЮ С НИМ.",
|
||||
"compliancePrintWarning": "Настоящий отчет о соответствии носит исключительно информационный характер. Вы должны подтвердить действительность этого отчета с помощью средства проверки соответствия Tornado (https://tornado.ws/compliance) или с помощью любого другого криптографического программного обеспечения, которое может обработать и проверить информацию, содержащуюся в этом отчете(\"Tornado Compliance Tool\"). Любые расхождения между информацией, приведенной в данном отчете и предоставленной вышеуказанным инструментом, указывают на то, что информация, содержащаяся в этом отчете, является неточной и/или мошеннической.{newline}ОТЧЕТ О СООТВЕТСТВИИ ПРЕДОСТАВЛЯЕТСЯ \"КАК ЕСТЬ,\" БЕЗ ГАРАНТИЙ ЛЮБОГО РОДА, ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОГО КАЧЕСТВА, ПРИГОДНОСТЬЮ К КОНКРЕТНОЙ ЦЕЛИ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОРЫ ИНСТРУМЕНТА СООТВЕТСТВИЯ TORNADO.CASH НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УЩЕРБ ИЛИ ДРУГУЮ ОТВЕТСТВЕННОСТЬ, ОТНОСЯЩУЮСЯ К ДЕЙСТВИЮ ДОГОВОРОВ, ГРАЖДАНСКИМ ПРАВОНАРУШЕНИЯМ, А ТАКЖЕ ВЫТЕКАЮЩУЮ ИЗ НАСТОЯЩЕГО ОТЧЕТА О СООТВЕТСТВИИ ИЛИ СВЯЗАННУЮ С НИМ.",
|
||||
"relayRequestFailed": "Relayer {relayerName} не отвечает. Попробуйте сменить Relayer.",
|
||||
"selectProvider": "Выберите кошелёк",
|
||||
"walletDoesNotSupported": "Выбранный кошелёк не поддерживается",
|
||||
|
@ -151,7 +151,7 @@
|
||||
"nullifierHash": "Nullifier Hash",
|
||||
"verified": "Onaylanmış",
|
||||
"generatePdfReport": "PDF rapora dönüştür.",
|
||||
"compliancePrintWarning": "Bu Uyumluluk Raporu yalnızca bilgilendirme amaçlıdır. Bu raporun geçerliliğini Tornado’nun Uyumluluk Aracını (https://tornadocash.eth.link/compliance) veya burada yer alan bilgileri hesaplayabilen ve doğrulayabilen diğer herhangi bir şifreleme yazılımıyla (\"Tornado Uyumluluk Aracı\") kullanarak onaylamalısınız.) Bu raporda bulunan ve yukarıdaki araç tarafından sağlanan bilgiler arasındaki herhangi bir tutarsızlık, rapordaki bilgilerin yanlış ve/veya sahte olduğunu gösterir.{newline} UYGUNLUK RAPORU, HERHANGİ BİR GARANTİ OLMADAN tamamen\"OLDUĞU GİBİ\" SUNULMAKTADIR. BELİRLİ BİR AMACA UYGUNLUK VE İHLAL ETMEME GARANTİLERİ DAHİLDİR ANCAK BUNLARLA SINIRLI OLMAMAK ÜZERE ZIMNİ VEYA ZIMNİ OLARAK GEÇERLİDİR. TORNADO.CASH UYUM ARACININ YAZARLARI RAPORDAN KAYNAKLANAN, UYUMLULUKTAN KAYNAKLANAN VEYA BAĞLANTILI OLARAK SÖZLEŞME, HAKSIZ YA DA BAŞKA BİR DURUMDA OLAN HERHANGİ BİR İDDİADAN, ZARAR VEYA BAŞKA SORUMLULUKTAN SORUMLU TUTULAMAZ.",
|
||||
"compliancePrintWarning": "Bu Uyumluluk Raporu yalnızca bilgilendirme amaçlıdır. Bu raporun geçerliliğini Tornado’nun Uyumluluk Aracını (https://tornado.ws/compliance) veya burada yer alan bilgileri hesaplayabilen ve doğrulayabilen diğer herhangi bir şifreleme yazılımıyla (\"Tornado Uyumluluk Aracı\") kullanarak onaylamalısınız.) Bu raporda bulunan ve yukarıdaki araç tarafından sağlanan bilgiler arasındaki herhangi bir tutarsızlık, rapordaki bilgilerin yanlış ve/veya sahte olduğunu gösterir.{newline} UYGUNLUK RAPORU, HERHANGİ BİR GARANTİ OLMADAN tamamen\"OLDUĞU GİBİ\" SUNULMAKTADIR. BELİRLİ BİR AMACA UYGUNLUK VE İHLAL ETMEME GARANTİLERİ DAHİLDİR ANCAK BUNLARLA SINIRLI OLMAMAK ÜZERE ZIMNİ VEYA ZIMNİ OLARAK GEÇERLİDİR. TORNADO.CASH UYUM ARACININ YAZARLARI RAPORDAN KAYNAKLANAN, UYUMLULUKTAN KAYNAKLANAN VEYA BAĞLANTILI OLARAK SÖZLEŞME, HAKSIZ YA DA BAŞKA BİR DURUMDA OLAN HERHANGİ BİR İDDİADAN, ZARAR VEYA BAŞKA SORUMLULUKTAN SORUMLU TUTULAMAZ.",
|
||||
"relayRequestFailed": "Relayer {relayerName} çöktü. lütfen başka bir relayer seçin.",
|
||||
"selectProvider": "Sağlayıcı seçin",
|
||||
"walletDoesNotSupported": "Bu cüzdan desteklenmiyor",
|
||||
|
@ -37,7 +37,7 @@
|
||||
"iBackedUpTheNote": "我已备份了凭证",
|
||||
"iEncryptedTheNote": "用您的账户{address}创建此凭证的链上备份",
|
||||
"yourNoteWontBeSaved": "你的存款凭证不会被存储在浏览器的缓存中,请确认已作好备份。",
|
||||
"yourDontHaveAccount": "您还可以通过设置凭证账户将加密的凭证保存在链上。 在 {account} 页面上创建。",
|
||||
"yourDontHaveAccount": "未能备份票据将导致资金损失",
|
||||
"sendDeposit": "发送存款",
|
||||
"clickToCopy": "点击复制",
|
||||
"copied": "已复制!",
|
||||
@ -151,7 +151,7 @@
|
||||
"nullifierHash": "无效符",
|
||||
"verified": "已验证",
|
||||
"generatePdfReport": "生成 PDF 报告",
|
||||
"compliancePrintWarning": "这本来源证明报告仅供参考的。 你应该使用Tornado的来源证明工具来确认报告 (https://tornadocash.eth.link/compliance) 的有效性,或者与可以算出和验证此处包含信息的任何其他密码学软件 (\"Tornado来源证明工具\") 一起使用。 报告中发现的信息与上述工具提供的信息之间存在任何差异,表明报告中的信息是不正确的{newline} 来源证明报告按 \"原样,\" 提供,不提供任何明示或暗示担保,包括但不限于对适销性,用途的适用性和非侵权专利的担保。 无论是出于合同要求、侵权或其他原因,由本来源证明报告引起与相关的任何索赔,损害或其他责任,Tornado.cash的作者概不负责。",
|
||||
"compliancePrintWarning": "这本来源证明报告仅供参考的。 你应该使用Tornado的来源证明工具来确认报告 (https://tornado.ws/compliance) 的有效性,或者与可以算出和验证此处包含信息的任何其他密码学软件 (\"Tornado来源证明工具\") 一起使用。 报告中发现的信息与上述工具提供的信息之间存在任何差异,表明报告中的信息是不正确的{newline} 来源证明报告按 \"原样,\" 提供,不提供任何明示或暗示担保,包括但不限于对适销性,用途的适用性和非侵权专利的担保。 无论是出于合同要求、侵权或其他原因,由本来源证明报告引起与相关的任何索赔,损害或其他责任,Tornado.cash的作者概不负责。",
|
||||
"relayRequestFailed": "中继者 {relayerName} 无法使用,请选择其他中继者。",
|
||||
"selectProvider": "请选择钱包",
|
||||
"walletDoesNotSupported": "此钱包不受支持",
|
||||
|
@ -1,6 +1,6 @@
|
||||
const { EIP712Signer } = require('@ticket721/e712')
|
||||
import { concatSig } from 'eth-sig-util'
|
||||
|
||||
const Permit = [
|
||||
const PermitType = [
|
||||
{ name: 'owner', type: 'address' },
|
||||
{ name: 'spender', type: 'address' },
|
||||
{ name: 'value', type: 'uint256' },
|
||||
@ -8,36 +8,53 @@ const Permit = [
|
||||
{ name: 'deadline', type: 'uint256' }
|
||||
]
|
||||
|
||||
class PermitSigner extends EIP712Signer {
|
||||
const EIP712DomainType = [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'version', type: 'string' },
|
||||
{ name: 'chainId', type: 'uint256' },
|
||||
{ name: 'verifyingContract', type: 'address' }
|
||||
]
|
||||
|
||||
export default class PermitSigner {
|
||||
constructor(_domain, _permitArgs) {
|
||||
super(_domain, ['Permit', Permit])
|
||||
this.permitArgs = _permitArgs
|
||||
this.domain = _domain
|
||||
}
|
||||
|
||||
// Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)
|
||||
setPermitInfo(_permitArgs) {
|
||||
this.permitArgs = _permitArgs
|
||||
}
|
||||
|
||||
getPayload() {
|
||||
return this.generatePayload(this.permitArgs, 'Permit')
|
||||
}
|
||||
|
||||
async getSignature(privateKey) {
|
||||
const payload = this.getPayload()
|
||||
const { hex, v, r, s } = await this.sign(privateKey, payload)
|
||||
getReqPayload() {
|
||||
return {
|
||||
hex,
|
||||
v,
|
||||
r: '0x' + r,
|
||||
s: '0x' + s
|
||||
domain: this.domain,
|
||||
primaryType: 'Permit',
|
||||
types: {
|
||||
Permit: PermitType,
|
||||
EIP712Domain: EIP712DomainType
|
||||
},
|
||||
message: this.permitArgs
|
||||
}
|
||||
}
|
||||
|
||||
getSignerAddress(permitArgs, signature) {
|
||||
const originalPayload = this.generatePayload(permitArgs, 'Permit')
|
||||
return this.verify(originalPayload, signature)
|
||||
getSignature(response) {
|
||||
response = response.substring(2)
|
||||
|
||||
const r = '0x' + response.substring(0, 64)
|
||||
const s = '0x' + response.substring(64, 128)
|
||||
|
||||
let v = parseInt(response.substring(128, 130), 16)
|
||||
|
||||
// fix ledger sign
|
||||
if (v === 0 || v === 1) {
|
||||
v = v + 27
|
||||
}
|
||||
|
||||
return {
|
||||
hex: concatSig(v, r, s),
|
||||
v,
|
||||
r,
|
||||
s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { PermitSigner }
|
||||
|
@ -25,7 +25,7 @@ export async function _encryptFormatTx({ dispatch, getters, rootGetters }, { eve
|
||||
if (!instance) {
|
||||
return acc
|
||||
}
|
||||
const name = `${instance.amount}${instance.currency}`
|
||||
const name = `${netId}${instance.amount}${instance.currency}`
|
||||
if (!acc[name]) {
|
||||
const service = eventsInterface.getService({ netId, ...instance })
|
||||
acc[name] = { ...instance, service }
|
||||
@ -49,7 +49,7 @@ export async function _encryptFormatTx({ dispatch, getters, rootGetters }, { eve
|
||||
if (!instance) {
|
||||
return
|
||||
}
|
||||
const { service } = instances[`${instance.amount}${instance.currency}`]
|
||||
const { service } = instances[`${netId}${instance.amount}${instance.currency}`]
|
||||
return getDeposit({ event, netId, service, instance })
|
||||
})
|
||||
|
||||
|
@ -1,3 +1,6 @@
|
||||
export const blockSyncInterval = 10000
|
||||
export const enabledChains = ['1', '10', '56', '100', '137', '43114', '42161']
|
||||
export const chainsWithEncryptedNotes = ['1', '5', '56', '100', '137']
|
||||
export default {
|
||||
netId1: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
@ -19,12 +22,21 @@ export default {
|
||||
networkName: 'Ethereum Mainnet',
|
||||
deployedBlock: 9116966,
|
||||
rpcUrls: {
|
||||
SecureRPC: {
|
||||
name: 'SecureRPC',
|
||||
url: 'https://api.securerpc.com/v1'
|
||||
chainnodes: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607'
|
||||
},
|
||||
mevblockerRPC: {
|
||||
name: 'MevblockerRPC',
|
||||
url: 'https://rpc.mevblocker.io'
|
||||
},
|
||||
llamaRPC: {
|
||||
name: 'llamarpc',
|
||||
url: 'https://eth.llamarpc.com'
|
||||
}
|
||||
},
|
||||
multicall: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
|
||||
routerContract: '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b',
|
||||
registryContract: '0x58E8dCC13BE9780fC42E8723D8EaD4CF46943dF2',
|
||||
echoContractAccount: '0x9B27DD5Bb15d42DC224FCD0B7caEbBe16161Df42',
|
||||
aggregatorContract: '0xE8F47A78A6D52D317D0D2FFFac56739fE14D1b49',
|
||||
@ -111,7 +123,7 @@ export default {
|
||||
'torn.contract.tornadocash.eth': '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
|
||||
'governance.contract.tornadocash.eth': '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce',
|
||||
'tornado-router.contract.tornadocash.eth': '0xd90e2f925DA726b50C4Ed8D0Fb90Ad053324F31b',
|
||||
'staking-rewards.contract.tornadocash.eth': '0x2FC93484614a34f26F7970CBB94615bA109BB4bf'
|
||||
'staking-rewards.contract.tornadocash.eth': '0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29'
|
||||
},
|
||||
netId56: {
|
||||
rpcCallRetryAttempt: 15,
|
||||
@ -135,9 +147,13 @@ export default {
|
||||
multicall: '0x41263cba59eb80dc200f3e2544eda4ed6a90e76c',
|
||||
echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
rpcUrls: {
|
||||
bscRpc: {
|
||||
name: 'BSC RPC',
|
||||
url: 'https://bscrpc.com/'
|
||||
chainnodes: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://bsc-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607'
|
||||
},
|
||||
oneRPC: {
|
||||
name: '1RPC',
|
||||
url: 'https://1rpc.io/bnb'
|
||||
}
|
||||
},
|
||||
tokens: {
|
||||
@ -182,9 +198,13 @@ export default {
|
||||
multicall: '0x11ce4B23bD875D7F5C6a31084f55fDe1e9A87507',
|
||||
echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
rpcUrls: {
|
||||
polygonRPC: {
|
||||
name: 'Polygon RPC',
|
||||
url: `https://polygon-rpc.com`
|
||||
chainnodes: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://polygon-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607'
|
||||
},
|
||||
oneRpc: {
|
||||
name: '1RPC',
|
||||
url: 'https://1rpc.io/matic'
|
||||
}
|
||||
},
|
||||
tokens: {
|
||||
@ -230,9 +250,13 @@ export default {
|
||||
echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
ovmGasPriceOracleContract: '0x420000000000000000000000000000000000000F',
|
||||
rpcUrls: {
|
||||
Optimism: {
|
||||
name: 'Optimism',
|
||||
url: `https://mainnet.optimism.io`
|
||||
chainnodes: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://optimism-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607'
|
||||
},
|
||||
oneRpc: {
|
||||
name: '1RPC',
|
||||
url: 'https://1rpc.io/op'
|
||||
}
|
||||
},
|
||||
tokens: {
|
||||
@ -277,8 +301,16 @@ export default {
|
||||
multicall: '0x842eC2c7D803033Edf55E478F461FC547Bc54EB2',
|
||||
echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
rpcUrls: {
|
||||
chainnodes: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://arbitrum-one.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607'
|
||||
},
|
||||
oneRpc: {
|
||||
name: '1rpc',
|
||||
url: 'https://1rpc.io/arb'
|
||||
},
|
||||
Arbitrum: {
|
||||
name: 'Arbitrum Public RPC',
|
||||
name: 'Arbitrum RPC',
|
||||
url: 'https://arb1.arbitrum.io/rpc'
|
||||
}
|
||||
},
|
||||
@ -324,9 +356,13 @@ export default {
|
||||
multicall: '0xb5b692a88bdfc81ca69dcb1d924f59f0413a602a',
|
||||
echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
rpcUrls: {
|
||||
publicRpc: {
|
||||
name: 'Community RPC',
|
||||
url: 'https://development.tornadocash.community/rpc/v1'
|
||||
chainnodes: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://gnosis-mainnet.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607'
|
||||
},
|
||||
blockPi: {
|
||||
name: 'BlockPi',
|
||||
url: 'https://gnosis.blockpi.network/v1/rpc/public'
|
||||
}
|
||||
},
|
||||
tokens: {
|
||||
@ -371,9 +407,17 @@ export default {
|
||||
multicall: '0xe86e3989c74293Acc962156cd3F525c07b6a1B6e',
|
||||
echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
|
||||
rpcUrls: {
|
||||
publicRpc: {
|
||||
communityRPC: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://avalanche-rpc.tornado.ws/ext/bc/C/rpc'
|
||||
},
|
||||
publicRpc1: {
|
||||
name: 'Avalanche RPC',
|
||||
url: 'https://api.avax.network/ext/bc/C/rpc'
|
||||
},
|
||||
oneRpc: {
|
||||
name: '1RPC',
|
||||
ulr: 'https://1rpc.io/avax/'
|
||||
}
|
||||
},
|
||||
tokens: {
|
||||
@ -418,9 +462,9 @@ export default {
|
||||
echoContractAccount: '0x37e6859804b6499d1e4a86d70a5fdd5de6a0ac65',
|
||||
aggregatorContract: '0x8cb1436F64a3c33aD17bb42F94e255c4c0E871b2',
|
||||
rpcUrls: {
|
||||
Infura: {
|
||||
name: 'Infura',
|
||||
url: 'https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161'
|
||||
chainnodes: {
|
||||
name: 'Tornado RPC',
|
||||
url: 'https://goerli.chainnodes.org/d692ae63-0a7e-43e0-9da9-fe4f4cc6c607'
|
||||
}
|
||||
},
|
||||
tokens: {
|
||||
|
@ -79,7 +79,7 @@ export default {
|
||||
{
|
||||
hid: 'og:url',
|
||||
property: 'og:url',
|
||||
content: 'https://tornado.cash'
|
||||
content: 'https://tornado.ws'
|
||||
},
|
||||
{
|
||||
hid: 'og:type',
|
||||
@ -89,7 +89,7 @@ export default {
|
||||
{
|
||||
hid: 'og:image',
|
||||
property: 'og:image',
|
||||
content: 'https://tornado.cash/tw.png'
|
||||
content: 'https://tornado.ws/tw.png'
|
||||
},
|
||||
{
|
||||
hid: 'description',
|
||||
|
16
package.json
16
package.json
@ -7,24 +7,22 @@
|
||||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
|
||||
"precommit": "yarn lint",
|
||||
"test": "jest",
|
||||
"dev": "NODE_OPTIONS='--max-old-space-size=8192' nuxt",
|
||||
"dev": "cross-env NODE_OPTIONS='--max-old-space-size=8192' nuxt",
|
||||
"build": "nuxt build",
|
||||
"start": "nuxt start",
|
||||
"update:zip": "node -r esm scripts/updateZip.js",
|
||||
"update:events": "node -r esm scripts/updateEvents.js --network",
|
||||
"update:encrypted": "node -r esm scripts/updateEncryptedEvents.js --network",
|
||||
"update:tree": "node -r esm scripts/updateTree.js --network",
|
||||
"generate": "NODE_OPTIONS='--max-old-space-size=8192' nuxt generate && cp dist/404.html dist/ipfs-404.html",
|
||||
"generate": "cross-env NODE_OPTIONS='--max-old-space-size=8192' nuxt generate && cp dist/404.html dist/ipfs-404.html",
|
||||
"check:sync": "node -r esm scripts/checkEventsSync.js",
|
||||
"ipfsUpload": "node scripts/ipfsUpload.js",
|
||||
"deploy:ipfs": "yarn generate && yarn ipfsUpload"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.3.20",
|
||||
"@ensdomains/ensjs": "^2.1.0",
|
||||
"@metamask/onboarding": "^1.0.0",
|
||||
"@nuxtjs/moment": "^1.6.0",
|
||||
"@ticket721/e712": "^0.4.1",
|
||||
"@walletconnect/web3-provider": "1.7.8",
|
||||
"ajv": "^6.10.2",
|
||||
"arraybuffer-loader": "^1.0.8",
|
||||
@ -43,7 +41,6 @@
|
||||
"graphql": "^15.5.1",
|
||||
"idb": "^6.0.0",
|
||||
"jspdf": "^1.5.3",
|
||||
"jszip": "^3.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"node-fetch": "^2.6.1",
|
||||
"numbro": "^2.3.2",
|
||||
@ -52,13 +49,14 @@
|
||||
"nuxt-web3-provider": "0.1.4",
|
||||
"push-dir": "^0.4.1",
|
||||
"recursive-fs": "^2.1.0",
|
||||
"snarkjs": "git+https://development.tornadocash.community/tornadocash/snarkjs.git#869181cfaf7526fe8972073d31655493a04326d5",
|
||||
"v-idle": "^0.2.0",
|
||||
"vue-clipboard2": "^0.3.1",
|
||||
"vue-i18n": "^8.15.4",
|
||||
"vuex-persistedstate": "^2.7.0",
|
||||
"web3": "1.5.2",
|
||||
"websnark": "git+https://development.tornadocash.community/tornadocash/websnark.git#671762fab73f01771d0e7ebcf6b6a3123e193fb4"
|
||||
"cross-env": "7.0.3",
|
||||
"@tornado/snarkjs": "0.1.20-p2",
|
||||
"@tornado/websnark": "0.0.4-p1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/eslint-config": "^1.1.2",
|
||||
@ -83,13 +81,11 @@
|
||||
"eslint-plugin-vue": "^6.0.1",
|
||||
"esm": "^3.2.25",
|
||||
"jest": "^24.9.0",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"nodemon": "^2.0.0",
|
||||
"prettier": "^1.19.1",
|
||||
"raw-loader": "^3.1.0",
|
||||
"sass": "^1.49.9",
|
||||
"sass-loader": "^8.0.0",
|
||||
"vue-jest": "^3.0.5",
|
||||
"zip-local": "^0.3.4"
|
||||
"vue-jest": "^3.0.5"
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
>
|
||||
<i18n path="trustBanner.trustLess">
|
||||
<template v-slot:link>
|
||||
<a href="https://tornado.cash/">{{ $t('trustBanner.link') }}</a>
|
||||
<a href="https://tornado.ws/">{{ $t('trustBanner.link') }}</a>
|
||||
</template>
|
||||
</i18n>
|
||||
</b-notification>
|
||||
@ -73,7 +73,7 @@
|
||||
</template>
|
||||
<template v-slot:linkThree>
|
||||
<a
|
||||
href="https://hackmd.io/@gozzy/tornado-cash-post-censorship#RPC"
|
||||
href="https://docs.tornado.ws/general/guides/post-censorship#RPC"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
@ -83,31 +83,6 @@
|
||||
</i18n>
|
||||
</b-notification>
|
||||
|
||||
<b-notification
|
||||
v-if="isEthLink"
|
||||
:active="isActiveNotification.ethLink"
|
||||
class="main-notification"
|
||||
type="is-warning"
|
||||
icon-pack="icon"
|
||||
has-icon
|
||||
:aria-close-label="$t('closeNotification')"
|
||||
@close="disableNotification({ key: 'ethLink' })"
|
||||
>
|
||||
<i18n path="ethLinkBanner.notification">
|
||||
<template v-slot:issue>
|
||||
<a
|
||||
href="https://discuss.ens.domains/t/eth-link-expiry/13899"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{ $t('ethLinkBanner.issue') }}</a
|
||||
>
|
||||
</template>
|
||||
<template v-slot:alternative>
|
||||
<a href="https://tornado.cash/">{{ $t('ethLinkBanner.alternative') }}</a>
|
||||
</template>
|
||||
</i18n>
|
||||
</b-notification>
|
||||
|
||||
<div class="columns">
|
||||
<div class="column is-half">
|
||||
<b-tabs v-model="activeTab" class="is-tornado" :animated="false" @input="tabChanged">
|
||||
@ -140,8 +115,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
activeTab: 0,
|
||||
isActive: false,
|
||||
isEthLink: window.location.host === 'tornadocash.eth.link'
|
||||
isActive: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -184,8 +158,19 @@ export default {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const { currency, amount } = this.selectedInstance
|
||||
this.$store.dispatch('application/setAndUpdateStatistic', { currency, amount })
|
||||
const userSelection = this.selectedInstance
|
||||
const stateSelection = this.selectedStatistic
|
||||
|
||||
if (
|
||||
!stateSelection ||
|
||||
userSelection.amount !== stateSelection.amount ||
|
||||
userSelection.currency !== stateSelection.currency
|
||||
) {
|
||||
this.$store.dispatch('application/setAndUpdateStatistic', {
|
||||
currency: userSelection.currency,
|
||||
amount: userSelection.amount
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,24 @@ export default ({ store, isHMR, app }, inject) => {
|
||||
inject('isLoadedFromIPFS', main)
|
||||
}
|
||||
function main() {
|
||||
const whiteListedDomains = ['localhost:3000', 'tornadocash.eth.link', 'tornadocash.eth.limo']
|
||||
const whiteListedDomains = [
|
||||
'tornadocash.eth.link',
|
||||
'tornadocash.eth.limo',
|
||||
'tornadocashcommunity.eth.link',
|
||||
'tornadocashcommunity.eth.limo'
|
||||
]
|
||||
|
||||
const NETLIFY_REGEXP = /deploy-preview-(\d+)--tornadocash\.netlify\.app/
|
||||
const IPFS_GATEWAY_REGEXP = /.ipfs./
|
||||
const IPFS_LOCAL_REGEXP = /.ipfs.localhost:/
|
||||
const IPFS_SOP_GATEWAY_REGEXP = /\/ipfs\//
|
||||
|
||||
if (NETLIFY_REGEXP.test(window.location.host)) {
|
||||
if (IPFS_LOCAL_REGEXP.test(window.location.host)) {
|
||||
return false
|
||||
} else if (!whiteListedDomains.includes(window.location.host)) {
|
||||
} else if (
|
||||
IPFS_GATEWAY_REGEXP.test(window.location.host) ||
|
||||
IPFS_SOP_GATEWAY_REGEXP.test(window.location.host) ||
|
||||
whiteListedDomains.includes(window.location.host)
|
||||
) {
|
||||
console.warn('The page has been loaded from ipfs.io. LocalStorage is disabled')
|
||||
return true
|
||||
}
|
||||
|
@ -264,24 +264,24 @@ export default async (ctx, inject) => {
|
||||
Object.keys(tokens[token].instanceAddress).forEach((amount) => {
|
||||
if (nativeCurrency === token && netId === 1) {
|
||||
stores.push({
|
||||
name: `stringify_bloom_${token}_${amount}`,
|
||||
name: `stringify_bloom_${netId}_${token}_${amount}`,
|
||||
keyPath: 'hashBloom'
|
||||
})
|
||||
}
|
||||
|
||||
stores.push(
|
||||
{
|
||||
name: `deposits_${token}_${amount}`,
|
||||
name: `deposits_${netId}_${token}_${amount}`,
|
||||
keyPath: 'leafIndex', // the key by which it refers to the object must be in all instances of the storage
|
||||
indexes: DEPOSIT_INDEXES
|
||||
},
|
||||
{
|
||||
name: `withdrawals_${token}_${amount}`,
|
||||
keyPath: 'transactionHash',
|
||||
name: `withdrawals_${netId}_${token}_${amount}`,
|
||||
keyPath: 'blockNumber',
|
||||
indexes: WITHDRAWAL_INDEXES
|
||||
},
|
||||
{
|
||||
name: `stringify_tree_${token}_${amount}`,
|
||||
name: `stringify_tree_${netId}_${token}_${amount}`,
|
||||
keyPath: 'hashTree'
|
||||
}
|
||||
)
|
||||
|
@ -23,9 +23,9 @@ function main(store) {
|
||||
window.multipleTabsDetected = true
|
||||
window.onbeforeunload = null
|
||||
window.alert(
|
||||
'Multiple tabs opened. Your page will be closed. Please only use single instance of https://tornado.cash'
|
||||
'Multiple tabs opened. Your page will be closed. Please only use single instance of https://tornado.ws'
|
||||
)
|
||||
window.location = 'https://twitter.com/tornadocash'
|
||||
window.location = 'https://t.me/TornadoOfficial'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,21 @@
|
||||
import networkConfig from '../networkConfig'
|
||||
import ABI from '../abis/Instance.abi.json'
|
||||
import { loadCachedEvents, getPastEvents } from './helpers'
|
||||
import networkConfig, { enabledChains } from '../networkConfig'
|
||||
import { loadCachedEvents } from './helpers'
|
||||
|
||||
const EVENTS_PATH = './static/events/'
|
||||
const enabledChains = ['1', '56', '100', '137' ]
|
||||
|
||||
async function main() {
|
||||
for (let network in enabledChains) {
|
||||
const netId = enabledChains[network]
|
||||
function main() {
|
||||
for (const netId of enabledChains) {
|
||||
const config = networkConfig[`netId${netId}`]
|
||||
const { constants, tokens, nativeCurrency, deployedBlock } = config
|
||||
const CONTRACTS = tokens[nativeCurrency].instanceAddress
|
||||
|
||||
console.log(`\n ::: ${netId} [${nativeCurrency.toUpperCase()}] :::`)
|
||||
|
||||
for (const [instance, _contract] of Object.entries(CONTRACTS)) {
|
||||
for (const [instance] of Object.entries(CONTRACTS)) {
|
||||
console.log(`\n instanceDenomation - ${instance}`)
|
||||
|
||||
const withdrawalCachedEvents = await loadCachedEvents({
|
||||
name: `withdrawals_${nativeCurrency}_${instance}.json`,
|
||||
const withdrawalCachedEvents = loadCachedEvents({
|
||||
name: `withdrawals_${netId}_${nativeCurrency}_${instance}.json`,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock
|
||||
})
|
||||
@ -27,8 +24,8 @@ async function main() {
|
||||
console.log('cachedEvents count - ', withdrawalCachedEvents.events.length)
|
||||
console.log('lastBlock - ', withdrawalCachedEvents.lastBlock)
|
||||
|
||||
const depositCachedEvents = await loadCachedEvents({
|
||||
name: `withdrawals_${nativeCurrency}_${instance}.json`,
|
||||
const depositCachedEvents = loadCachedEvents({
|
||||
name: `deposits_${netId}_${nativeCurrency}_${instance}.json`,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock
|
||||
})
|
||||
@ -37,7 +34,7 @@ async function main() {
|
||||
console.log('cachedEvents count - ', depositCachedEvents.events.length)
|
||||
console.log('lastBlock - ', depositCachedEvents.lastBlock)
|
||||
|
||||
const notesCachedEvents = await loadCachedEvents({
|
||||
const notesCachedEvents = loadCachedEvents({
|
||||
name: `encrypted_notes_${netId}.json`,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock: constants.ENCRYPTED_NOTES_BLOCK
|
||||
@ -46,7 +43,6 @@ async function main() {
|
||||
console.log('- Notes')
|
||||
console.log('cachedEvents count - ', notesCachedEvents.events.length)
|
||||
console.log('lastBlock - ', notesCachedEvents.lastBlock)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,28 @@
|
||||
import fs from 'fs'
|
||||
import Jszip from 'jszip'
|
||||
import zlib from 'zlib'
|
||||
import Web3 from 'web3'
|
||||
import networkConfig from '../../networkConfig'
|
||||
|
||||
const jszip = new Jszip()
|
||||
import networkConfig, { blockSyncInterval } from '../../networkConfig'
|
||||
|
||||
export async function download({ name, directory, contentType }) {
|
||||
const path = `${directory}${name}.zip`.toLowerCase()
|
||||
export function download({ name, directory }) {
|
||||
const path = `${directory}${name}.gz`.toLowerCase()
|
||||
|
||||
const data = fs.readFileSync(path)
|
||||
const zip = await jszip.loadAsync(data)
|
||||
|
||||
const file = zip.file(
|
||||
path
|
||||
.replace(directory, '')
|
||||
.slice(0, -4)
|
||||
.toLowerCase()
|
||||
)
|
||||
|
||||
const content = await file.async(contentType)
|
||||
const data = fs.readFileSync(path, { flag: 'as+' })
|
||||
const content = zlib.inflateSync(data)
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
export async function loadCachedEvents({ name, directory, deployedBlock }) {
|
||||
export function loadCachedEvents({ name, directory, deployedBlock }) {
|
||||
try {
|
||||
const module = await download({ contentType: 'string', directory, name })
|
||||
const module = download({ contentType: 'string', directory, name })
|
||||
|
||||
if (module) {
|
||||
const events = JSON.parse(module)
|
||||
|
||||
const [lastEvent] = JSON.parse(module).sort(
|
||||
(a, b) => (b.block || b.blockNumber) - (a.block || a.blockNumber)
|
||||
)
|
||||
const lastBlock = lastEvent.block || lastEvent.blockNumber
|
||||
|
||||
return {
|
||||
events,
|
||||
lastBlock
|
||||
lastBlock: events[events.length - 1].blockNumber
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@ -68,8 +53,7 @@ export async function getPastEvents({ type, fromBlock, netId, events, contractAt
|
||||
const blockDifference = Math.ceil(blockNumberBuffer - fromBlock)
|
||||
|
||||
// eth_logs and eth_filter are restricted > 10,000 block queries
|
||||
const blockDenom = blockDifference > 10000 ? 4950 : 20
|
||||
const blockRange = blockDifference / blockDenom
|
||||
const blockRange = blockSyncInterval ? blockSyncInterval : 10_000
|
||||
|
||||
let chunksCount = blockDifference === 0 ? 1 : Math.ceil(blockDifference / blockRange)
|
||||
const chunkSize = Math.ceil(blockDifference / chunksCount)
|
||||
@ -83,6 +67,7 @@ export async function getPastEvents({ type, fromBlock, netId, events, contractAt
|
||||
}
|
||||
|
||||
console.log(`Fetching ${type}, chainId - ${netId}`, `chunksCount - ${chunksCount}`)
|
||||
|
||||
for (let i = 0; i < chunksCount; i++)
|
||||
try {
|
||||
await new Promise((resolve) => setTimeout(resolve, 200))
|
||||
|
@ -1,17 +1,20 @@
|
||||
import fs from 'fs'
|
||||
import zipper from 'zip-local'
|
||||
import zlib from 'zlib'
|
||||
|
||||
export function save(fileName) {
|
||||
export function save(filePath) {
|
||||
try {
|
||||
zipper.sync
|
||||
.zip(`${fileName}`)
|
||||
.compress()
|
||||
.save(`${fileName}.zip`)
|
||||
const data = fs.readFileSync(`${filePath}`)
|
||||
|
||||
const payload = zlib.deflateSync(data, {
|
||||
level: zlib.constants.Z_BEST_COMPRESSION,
|
||||
strategy: zlib.constants.Z_FILTERED
|
||||
})
|
||||
|
||||
fs.writeFileSync(`${filePath}.gz`, payload)
|
||||
|
||||
fs.unlinkSync(fileName)
|
||||
return true
|
||||
} catch (err) {
|
||||
console.log('on save error', fileName, err.message)
|
||||
console.log('on save error', filePath, err.message)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,12 @@ import 'dotenv/config'
|
||||
import fs from 'fs'
|
||||
import { uniqBy } from 'lodash'
|
||||
|
||||
import networkConfig from '../networkConfig'
|
||||
import networkConfig, { enabledChains } from '../networkConfig'
|
||||
import ABI from '../abis/TornadoProxy.abi.json'
|
||||
|
||||
import { getPastEvents, loadCachedEvents } from './helpers'
|
||||
|
||||
const EVENTS_PATH = './static/events/'
|
||||
const enabledChains = ['1', '5', '56', '100', '137']
|
||||
|
||||
async function saveEncryptedNote(netId) {
|
||||
const {
|
||||
@ -23,7 +23,7 @@ async function saveEncryptedNote(netId) {
|
||||
let encryptedEvents = []
|
||||
const name = `encrypted_notes_${netId}.json`
|
||||
|
||||
const cachedEvents = await loadCachedEvents({
|
||||
const cachedEvents = loadCachedEvents({
|
||||
name,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock: constants.ENCRYPTED_NOTES_BLOCK
|
||||
@ -57,11 +57,13 @@ async function saveEncryptedNote(netId) {
|
||||
freshEvents = uniqBy(freshEvents, 'encryptedNote').sort((a, b) => b.blockNumber - a.blockNumber)
|
||||
|
||||
const eventsJson = JSON.stringify(freshEvents, null, 2) + '\n'
|
||||
|
||||
fs.writeFileSync(`${EVENTS_PATH}${name}`, eventsJson)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const [, , , chain] = process.argv
|
||||
|
||||
if (!enabledChains.includes(chain)) {
|
||||
throw new Error(`Supported chain ids ${enabledChains.join(', ')}`)
|
||||
}
|
||||
|
@ -3,86 +3,120 @@ import 'dotenv/config'
|
||||
import fs from 'fs'
|
||||
import { uniqBy } from 'lodash'
|
||||
|
||||
import networkConfig from '../networkConfig'
|
||||
import networkConfig, { enabledChains } from '../networkConfig'
|
||||
import ABI from '../abis/Instance.abi.json'
|
||||
|
||||
import { loadCachedEvents, getPastEvents } from './helpers'
|
||||
|
||||
const EVENTS_PATH = './static/events/'
|
||||
const EVENTS = ['Deposit', 'Withdrawal']
|
||||
const enabledChains = ['1', '56', '5', '100', '137' ]
|
||||
|
||||
async function main(type, netId) {
|
||||
const { tokens, nativeCurrency, deployedBlock } = networkConfig[`netId${netId}`]
|
||||
const CONTRACTS = tokens[nativeCurrency].instanceAddress
|
||||
function parseArg(netId, tokenOrEvent) {
|
||||
const { tokens } = networkConfig[`netId${netId}`]
|
||||
const keys = Object.keys(tokens)
|
||||
if (tokenOrEvent !== undefined) {
|
||||
const lower = tokenOrEvent.toLowerCase()
|
||||
return keys.includes(lower)
|
||||
? { token: lower }
|
||||
: { event: lower[0].toUpperCase() + lower.slice(1).toLowerCase() }
|
||||
} else return undefined
|
||||
}
|
||||
|
||||
for (const [instance, _contract] of Object.entries(CONTRACTS)) {
|
||||
const cachedEvents = await loadCachedEvents({
|
||||
name: `${type.toLowerCase()}s_${nativeCurrency}_${instance}.json`,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock
|
||||
})
|
||||
|
||||
console.log('cachedEvents count - ', cachedEvents.events.length)
|
||||
console.log('lastBlock - ', cachedEvents.lastBlock)
|
||||
|
||||
let events = []
|
||||
|
||||
events = await getPastEvents({
|
||||
type,
|
||||
netId,
|
||||
events,
|
||||
contractAttrs: [ABI, _contract],
|
||||
fromBlock: cachedEvents.lastBlock + 1
|
||||
})
|
||||
|
||||
if (type === 'Deposit') {
|
||||
events = events.map(({ blockNumber, transactionHash, returnValues }) => {
|
||||
const { commitment, leafIndex, timestamp } = returnValues
|
||||
return {
|
||||
timestamp,
|
||||
commitment,
|
||||
blockNumber,
|
||||
transactionHash,
|
||||
leafIndex: Number(leafIndex)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (type === 'Withdrawal') {
|
||||
events = events.map(({ blockNumber, transactionHash, returnValues }) => {
|
||||
const { nullifierHash, to, fee } = returnValues
|
||||
return {
|
||||
to,
|
||||
fee,
|
||||
blockNumber,
|
||||
nullifierHash,
|
||||
transactionHash
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
let freshEvents = cachedEvents.events.concat(events)
|
||||
|
||||
if (type === 'Withdrawal') {
|
||||
freshEvents = uniqBy(freshEvents, 'nullifierHash').sort((a, b) => b.blockNumber - a.blockNumber)
|
||||
} else {
|
||||
freshEvents = freshEvents.filter((e, index) => Number(e.leafIndex) === index)
|
||||
}
|
||||
|
||||
const eventsJson = JSON.stringify(freshEvents, null, 2) + '\n'
|
||||
fs.writeFileSync(`${EVENTS_PATH}${type.toLowerCase()}s_${nativeCurrency}_${instance}.json`, eventsJson)
|
||||
function parseDepositEvent({ blockNumber, transactionHash, returnValues }) {
|
||||
const { commitment, leafIndex, timestamp } = returnValues
|
||||
return {
|
||||
timestamp,
|
||||
commitment,
|
||||
blockNumber,
|
||||
transactionHash,
|
||||
leafIndex: Number(leafIndex)
|
||||
}
|
||||
}
|
||||
|
||||
function parseWithdrawalEvent({ blockNumber, transactionHash, returnValues }) {
|
||||
const { nullifierHash, to, fee } = returnValues
|
||||
return {
|
||||
to,
|
||||
fee,
|
||||
blockNumber,
|
||||
nullifierHash,
|
||||
transactionHash
|
||||
}
|
||||
}
|
||||
|
||||
function filterWithdrawalEvents(events) {
|
||||
return uniqBy(events, 'nullifierHash').sort((a, b) => a.blockNumber - b.blockNumber)
|
||||
}
|
||||
|
||||
function filterDepositEvents(events) {
|
||||
return events.filter((e, index) => Number(e.leafIndex) === index)
|
||||
}
|
||||
|
||||
async function main(netId, chosenToken, chosenEvent) {
|
||||
const { tokens, deployedBlock } = networkConfig[`netId${netId}`]
|
||||
|
||||
const tokenSymbols = chosenToken !== undefined ? [chosenToken] : Object.keys(tokens)
|
||||
const eventNames = chosenEvent !== undefined ? [chosenEvent] : ['Deposit', 'Withdrawal']
|
||||
|
||||
for (const eventName of eventNames) {
|
||||
// Get the parser that we need
|
||||
const parser = eventName === 'Deposit' ? parseDepositEvent : parseWithdrawalEvent
|
||||
// Get the parser that we need
|
||||
const filter = eventName === 'Deposit' ? filterDepositEvents : filterWithdrawalEvents
|
||||
|
||||
for (const tokenSymbol of tokenSymbols) {
|
||||
// Now load the denominations and address
|
||||
const instanceData = Object.entries(tokens[tokenSymbol].instanceAddress)
|
||||
|
||||
// And now sync
|
||||
for (const data of instanceData) {
|
||||
const denom = data[0]
|
||||
const address = data[1]
|
||||
|
||||
// Now load cached events
|
||||
const cachedEvents = loadCachedEvents({
|
||||
name: `${eventName.toLowerCase()}s_${netId}_${tokenSymbol}_${denom}.json`,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock
|
||||
})
|
||||
|
||||
console.log('Update events for', denom, tokenSymbol.toUpperCase(), `${eventName.toLowerCase()}s`)
|
||||
console.log('cachedEvents count - ', cachedEvents.events.length)
|
||||
console.log('lastBlock - ', cachedEvents.lastBlock)
|
||||
|
||||
let events = await getPastEvents({
|
||||
type: eventName,
|
||||
fromBlock: cachedEvents.lastBlock + 1,
|
||||
netId: netId,
|
||||
events: [],
|
||||
contractAttrs: [ABI, address]
|
||||
})
|
||||
|
||||
events = filter(cachedEvents.events.concat(events.map(parser)))
|
||||
|
||||
fs.writeFileSync(
|
||||
`${EVENTS_PATH}${eventName.toLowerCase()}s_${netId}_${tokenSymbol}_${denom}.json`,
|
||||
JSON.stringify(events, null, 2) + '\n'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param netId ID of the network for which event(s) should be synced.
|
||||
* @param tokenOrEvent Optional token or event.
|
||||
* @param eventOrToken Optional token or event. Overwrites the former option.
|
||||
*/
|
||||
async function start() {
|
||||
const [, , , chain] = process.argv
|
||||
if (!enabledChains.includes(chain)) {
|
||||
const [, , , netId, tokenOrEvent, eventOrToken] = process.argv
|
||||
|
||||
const args = { ...parseArg(netId, tokenOrEvent), ...parseArg(netId, eventOrToken) }
|
||||
|
||||
if (!enabledChains.includes(netId)) {
|
||||
throw new Error(`Supported chain ids ${enabledChains.join(', ')}`)
|
||||
}
|
||||
|
||||
for await (const event of EVENTS) {
|
||||
await main(event, chain)
|
||||
}
|
||||
await main(netId, args.token, args.event)
|
||||
}
|
||||
|
||||
start()
|
||||
|
@ -1,11 +1,12 @@
|
||||
import 'dotenv/config'
|
||||
|
||||
import fs from 'fs'
|
||||
|
||||
import BloomFilter from 'bloomfilter.js'
|
||||
import { MerkleTree } from 'fixed-merkle-tree'
|
||||
import { buildMimcSponge } from 'circomlibjs'
|
||||
|
||||
import networkConfig from '../networkConfig'
|
||||
import networkConfig, { enabledChains } from '../networkConfig'
|
||||
|
||||
import { loadCachedEvents, save } from './helpers'
|
||||
|
||||
@ -14,7 +15,7 @@ const TREES_PATH = './static/trees/'
|
||||
const EVENTS_PATH = './static/events/'
|
||||
|
||||
const EVENTS = ['deposit']
|
||||
const enabledChains = ['1', '56', '100', '137' ]
|
||||
|
||||
let mimcHash
|
||||
|
||||
const trees = {
|
||||
@ -22,8 +23,8 @@ const trees = {
|
||||
LEVELS: 20 // const from contract
|
||||
}
|
||||
|
||||
function getName({ path, type, instance, format = '.json', currName = 'eth' }) {
|
||||
return `${path}${type.toLowerCase()}s_${currName}_${instance}${format}`
|
||||
function getName({ path, type, netId, instance, format = '.json', currName = 'eth' }) {
|
||||
return `${path}${type.toLowerCase()}s_${netId}_${currName}_${instance}${format}`
|
||||
}
|
||||
|
||||
function createTreeZip(netId) {
|
||||
@ -36,6 +37,7 @@ function createTreeZip(netId) {
|
||||
const baseFilename = getName({
|
||||
type,
|
||||
instance,
|
||||
netId,
|
||||
format: '',
|
||||
path: TREES_PATH,
|
||||
currName: currencyName.toLowerCase()
|
||||
@ -45,7 +47,8 @@ function createTreeZip(netId) {
|
||||
|
||||
treesFolder.forEach((fileName) => {
|
||||
fileName = `${TREES_PATH}${fileName}`
|
||||
const isInstanceFile = !fileName.includes('.zip') && fileName.includes(baseFilename)
|
||||
|
||||
const isInstanceFile = !fileName.includes('.gz') && fileName.includes(baseFilename)
|
||||
|
||||
if (isInstanceFile) {
|
||||
save(fileName)
|
||||
@ -67,6 +70,7 @@ async function createTree(netId) {
|
||||
const filePath = getName({
|
||||
type,
|
||||
instance,
|
||||
netId,
|
||||
format: '',
|
||||
path: TREES_PATH,
|
||||
currName: currencyName.toLowerCase()
|
||||
@ -74,8 +78,8 @@ async function createTree(netId) {
|
||||
|
||||
console.log('createTree', { type, instance })
|
||||
|
||||
const { events } = await loadCachedEvents({
|
||||
name: `${type}s_${nativeCurrency}_${instance}.json`,
|
||||
const { events } = loadCachedEvents({
|
||||
name: `${type}s_${netId}_${nativeCurrency}_${instance}.json`,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock
|
||||
})
|
||||
@ -118,10 +122,12 @@ async function createTree(netId) {
|
||||
}, [])
|
||||
|
||||
const sliceJson = JSON.stringify(slice, null, 2) + '\n'
|
||||
|
||||
fs.writeFileSync(`${filePath}_slice${index + 1}.json`, sliceJson)
|
||||
})
|
||||
|
||||
const bloomCache = bloom.serialize()
|
||||
|
||||
fs.writeFileSync(`${filePath}_bloom.json`, bloomCache)
|
||||
}
|
||||
}
|
||||
@ -137,13 +143,16 @@ async function initMimc() {
|
||||
|
||||
async function main() {
|
||||
const [, , , chain] = process.argv
|
||||
|
||||
if (!enabledChains.includes(chain)) {
|
||||
throw new Error(`Supported chain ids ${enabledChains.join(', ')}`)
|
||||
}
|
||||
|
||||
await initMimc()
|
||||
|
||||
await createTree(chain)
|
||||
await createTreeZip(chain)
|
||||
|
||||
createTreeZip(chain)
|
||||
}
|
||||
|
||||
main()
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { uniqBy } from 'lodash'
|
||||
|
||||
import networkConfig from '../networkConfig'
|
||||
import networkConfig, { enabledChains, chainsWithEncryptedNotes } from '../networkConfig'
|
||||
|
||||
import { loadCachedEvents, save } from './helpers'
|
||||
|
||||
const EVENTS_PATH = './static/events/'
|
||||
@ -9,22 +10,26 @@ const EVENTS = ['Deposit', 'Withdrawal']
|
||||
function updateEncrypted(netId) {
|
||||
try {
|
||||
const file = `${EVENTS_PATH}encrypted_notes_${netId}.json`
|
||||
|
||||
save(file)
|
||||
} catch {}
|
||||
}
|
||||
|
||||
async function updateCommon(netId) {
|
||||
const { nativeCurrency, tokens } = networkConfig[`netId${netId}`]
|
||||
|
||||
console.log(Object.keys(tokens[nativeCurrency].instanceAddress))
|
||||
|
||||
for await (const type of EVENTS) {
|
||||
for await (const instance of Object.keys(tokens[nativeCurrency].instanceAddress)) {
|
||||
console.warn('instance', instance)
|
||||
const filename = `${type.toLowerCase()}s_${nativeCurrency}_${instance}.json`
|
||||
|
||||
const filename = `${type.toLowerCase()}s_${netId}_${nativeCurrency}_${instance}.json`
|
||||
|
||||
const isSaved = save(`${EVENTS_PATH}${filename}`)
|
||||
|
||||
if (isSaved) {
|
||||
try {
|
||||
await testCommon(netId, type, filename)
|
||||
testCommon(netId, type, filename)
|
||||
} catch (err) {
|
||||
console.error(err.message)
|
||||
}
|
||||
@ -33,10 +38,10 @@ async function updateCommon(netId) {
|
||||
}
|
||||
}
|
||||
|
||||
async function testCommon(netId, type, filename) {
|
||||
function testCommon(netId, type, filename) {
|
||||
const { deployedBlock } = networkConfig[`netId${netId}`]
|
||||
|
||||
const cachedEvents = await loadCachedEvents({
|
||||
const cachedEvents = loadCachedEvents({
|
||||
name: filename,
|
||||
directory: EVENTS_PATH,
|
||||
deployedBlock
|
||||
@ -45,11 +50,13 @@ async function testCommon(netId, type, filename) {
|
||||
console.log('cachedEvents', cachedEvents.events.length, type)
|
||||
|
||||
let events = cachedEvents.events
|
||||
|
||||
if (type === 'Withdrawal') {
|
||||
events = uniqBy(cachedEvents.events, 'nullifierHash')
|
||||
} else if (type === 'Deposit') {
|
||||
events = cachedEvents.events.filter((e, index) => Number(e.leafIndex) === index)
|
||||
}
|
||||
|
||||
if (events.length !== cachedEvents.events.length) {
|
||||
console.error('events.length', events.length)
|
||||
console.error('cachedEvents.events.length', cachedEvents.events.length)
|
||||
@ -58,10 +65,11 @@ async function testCommon(netId, type, filename) {
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const NETWORKS = [1, 5, 56, 100, 137 ]
|
||||
for (let i = 0; i < enabledChains.length; i++) {
|
||||
const netId = enabledChains[i]
|
||||
|
||||
if (netId === chainsWithEncryptedNotes[i]) updateEncrypted(netId)
|
||||
|
||||
for await (const netId of NETWORKS) {
|
||||
updateEncrypted(netId)
|
||||
await updateCommon(netId)
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,24 @@ import Web3 from 'web3'
|
||||
|
||||
import graph from '@/services/graph'
|
||||
import { download } from '@/store/snark'
|
||||
import networkConfig from '@/networkConfig'
|
||||
import networkConfig, { enabledChains } from '@/networkConfig'
|
||||
import InstanceABI from '@/abis/Instance.abi.json'
|
||||
import { CONTRACT_INSTANCES, eventsType } from '@/constants'
|
||||
import { sleep, formatEvents, capitalizeFirstLetter } from '@/utils'
|
||||
import { CONTRACT_INSTANCES, eventsType, httpConfig } from '@/constants'
|
||||
import { sleep, flattenNArray, formatEvents, capitalizeFirstLetter } from '@/utils'
|
||||
|
||||
const supportedCaches = ['1', '56', '100', '137']
|
||||
let store
|
||||
if (process.browser) {
|
||||
window.onNuxtReady(({ $store }) => {
|
||||
store = $store
|
||||
})
|
||||
}
|
||||
|
||||
class EventService {
|
||||
constructor({ netId, amount, currency, factoryMethods }) {
|
||||
this.idb = window.$nuxt.$indexedDB(netId)
|
||||
|
||||
const { nativeCurrency } = networkConfig[`netId${netId}`]
|
||||
const hasCache = supportedCaches.indexOf(Number(this.netId)) !== 0
|
||||
const hasCache = enabledChains.includes(netId.toString())
|
||||
|
||||
this.netId = netId
|
||||
this.amount = amount
|
||||
@ -28,7 +33,16 @@ class EventService {
|
||||
}
|
||||
|
||||
getInstanceName(type) {
|
||||
return `${type}s_${this.currency}_${this.amount}`
|
||||
return `${type}s_${this.netId}_${this.currency}_${this.amount}`
|
||||
}
|
||||
|
||||
updateEventProgress(percentage, type) {
|
||||
if (store) {
|
||||
store.dispatch('loading/updateProgress', {
|
||||
message: `Fetching past ${type} events`,
|
||||
progress: Math.ceil(percentage * 100)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async getEvents(type) {
|
||||
@ -37,14 +51,17 @@ class EventService {
|
||||
if (!cachedEvents && this.hasCache) {
|
||||
cachedEvents = await this.getEventsFromCache(type)
|
||||
}
|
||||
|
||||
return cachedEvents
|
||||
}
|
||||
|
||||
async updateEvents(type, cachedEvents) {
|
||||
const { deployedBlock } = networkConfig[`netId${this.netId}`]
|
||||
|
||||
const savedEvents = cachedEvents || (await this.getEvents(type))
|
||||
|
||||
let fromBlock = deployedBlock
|
||||
|
||||
if (savedEvents) {
|
||||
fromBlock = savedEvents.lastBlock + 1
|
||||
}
|
||||
@ -61,7 +78,6 @@ class EventService {
|
||||
}
|
||||
return a.blockNumber - b.blockNumber
|
||||
})
|
||||
|
||||
const lastBlock = allEvents[allEvents.length - 1].blockNumber
|
||||
|
||||
this.saveEvents({ events: allEvents, lastBlock, type })
|
||||
@ -114,7 +130,7 @@ class EventService {
|
||||
|
||||
const module = await download({
|
||||
contentType: 'string',
|
||||
name: `events/${instanceName}.json.zip`
|
||||
name: `events/${instanceName}.json.gz`
|
||||
})
|
||||
|
||||
if (module) {
|
||||
@ -138,22 +154,15 @@ class EventService {
|
||||
async getEventsFromDB(type) {
|
||||
try {
|
||||
const instanceName = this.getInstanceName(type)
|
||||
|
||||
const savedEvents = await this.idb.getAll({ storeName: instanceName })
|
||||
|
||||
if (!savedEvents || !savedEvents.length) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const event = await this.idb.getFromIndex({
|
||||
storeName: 'lastEvents',
|
||||
indexName: 'name',
|
||||
key: instanceName
|
||||
})
|
||||
|
||||
return {
|
||||
events: savedEvents,
|
||||
lastBlock: event.blockNumber
|
||||
lastBlock: savedEvents[savedEvents.length - 1].blockNumber
|
||||
}
|
||||
} catch (err) {
|
||||
return undefined
|
||||
@ -235,75 +244,137 @@ class EventService {
|
||||
}
|
||||
}
|
||||
|
||||
async getEventsPartFromRpc({ fromBlock, toBlock, type }) {
|
||||
getPastEvents({ fromBlock, toBlock, type }, shouldRetry = false, i = 0) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.contract
|
||||
.getPastEvents(capitalizeFirstLetter(type), {
|
||||
fromBlock,
|
||||
toBlock
|
||||
})
|
||||
.then((events) => resolve(events))
|
||||
.catch((err) => {
|
||||
i = i + 1
|
||||
// maximum 5 second buffer for rate-limiting
|
||||
if (shouldRetry) {
|
||||
const isRetry = i !== 5
|
||||
|
||||
sleep(1000 * i).then(() =>
|
||||
this.getPastEvents({ fromBlock, toBlock, type }, isRetry, i)
|
||||
.then((events) => resolve(events))
|
||||
.catch((_) => resolve(undefined))
|
||||
)
|
||||
} else {
|
||||
reject(new Error(err))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async getEventsPartFromRpc(parameters, shouldRetry = false) {
|
||||
try {
|
||||
const { fromBlock, type } = parameters
|
||||
const { currentBlockNumber } = await this.getBlocksDiff({ fromBlock })
|
||||
|
||||
if (fromBlock > currentBlockNumber) {
|
||||
if (fromBlock < currentBlockNumber) {
|
||||
const eventsPart = await this.getPastEvents(parameters, shouldRetry)
|
||||
|
||||
if (eventsPart) {
|
||||
if (eventsPart.length > 0) {
|
||||
return {
|
||||
events: formatEvents(eventsPart, type),
|
||||
lastBlock: eventsPart[eventsPart.length - 1].blockNumber
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: fromBlock
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: fromBlock
|
||||
}
|
||||
}
|
||||
|
||||
const events = await this.contract.getPastEvents(capitalizeFirstLetter(type), {
|
||||
fromBlock,
|
||||
toBlock
|
||||
})
|
||||
|
||||
if (!events?.length) {
|
||||
return {
|
||||
events: [],
|
||||
lastBlock: fromBlock
|
||||
}
|
||||
}
|
||||
return {
|
||||
events: formatEvents(events, type),
|
||||
lastBlock: events[events.length - 1].blockNumber
|
||||
}
|
||||
} catch (err) {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
createBatchRequest(batchArray) {
|
||||
return batchArray.map(
|
||||
(e, i) =>
|
||||
new Promise((resolve) =>
|
||||
sleep(20 * i).then(() =>
|
||||
this.getEventsPartFromRpc({ ...e }, true).then((batch) => {
|
||||
if (!batch) {
|
||||
resolve([{ isFailedBatch: true, ...e }])
|
||||
} else {
|
||||
resolve(batch.events)
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
async getBatchEventsFromRpc({ fromBlock, type }) {
|
||||
try {
|
||||
const blockRange = 4950
|
||||
const batchSize = 10
|
||||
const blockRange = 10000
|
||||
|
||||
let [events, failed] = [[], []]
|
||||
let lastBlock = fromBlock
|
||||
|
||||
const { blockDifference, currentBlockNumber } = await this.getBlocksDiff({ fromBlock })
|
||||
const batchDigest = blockDifference === 0 ? 1 : Math.ceil(blockDifference / blockRange)
|
||||
|
||||
let numberParts = blockDifference === 0 ? 1 : Math.ceil(blockDifference / blockRange)
|
||||
const part = Math.ceil(blockDifference / numberParts)
|
||||
|
||||
let events = []
|
||||
let toBlock = fromBlock + part
|
||||
const blockDenom = Math.ceil(blockDifference / batchDigest)
|
||||
const batchCount = Math.ceil(batchDigest / batchSize)
|
||||
|
||||
if (fromBlock < currentBlockNumber) {
|
||||
if (toBlock >= currentBlockNumber) {
|
||||
toBlock = 'latest'
|
||||
numberParts = 1
|
||||
await this.updateEventProgress(0, type)
|
||||
|
||||
for (let batchIndex = 0; batchIndex < batchCount; batchIndex++) {
|
||||
const isLastBatch = batchIndex === batchCount - 1
|
||||
const params = new Array(batchSize).fill('').map((_, i) => {
|
||||
const toBlock = (i + 1) * blockDenom + lastBlock
|
||||
const fromBlock = toBlock - blockDenom
|
||||
return { fromBlock, toBlock, type }
|
||||
})
|
||||
const batch = await Promise.all(this.createBatchRequest(params))
|
||||
const requests = flattenNArray(batch)
|
||||
|
||||
events = events.concat(requests.filter((e) => !e.isFailedBatch))
|
||||
failed = failed.concat(requests.filter((e) => e.isFailedBatch))
|
||||
lastBlock = params[batchSize - 1].toBlock
|
||||
|
||||
const progressIndex = batchIndex - failed.length / batchSize
|
||||
|
||||
if (isLastBatch && failed.length !== 0) {
|
||||
const failedBatch = await Promise.all(this.createBatchRequest(failed))
|
||||
const failedReqs = flattenNArray(failedBatch)
|
||||
const failedRept = failedReqs.filter((e) => e.isFailedBatch)
|
||||
|
||||
if (failedRept.length === 0) {
|
||||
events = events.concat(failedReqs)
|
||||
} else {
|
||||
throw new Error('Failed to batch events')
|
||||
}
|
||||
}
|
||||
await this.updateEventProgress(progressIndex / batchCount, type)
|
||||
}
|
||||
|
||||
for (let i = 0; i < numberParts; i++) {
|
||||
try {
|
||||
await sleep(200)
|
||||
const partOfEvents = await this.getEventsPartFromRpc({ fromBlock, toBlock, type })
|
||||
if (partOfEvents) {
|
||||
events = events.concat(partOfEvents.events)
|
||||
}
|
||||
fromBlock = toBlock
|
||||
toBlock += part
|
||||
} catch {
|
||||
numberParts = numberParts + 1
|
||||
}
|
||||
}
|
||||
if (events.length) {
|
||||
return {
|
||||
events,
|
||||
lastBlock: toBlock === 'latest' ? currentBlockNumber : toBlock
|
||||
}
|
||||
return {
|
||||
lastBlock: events[events.length - 1].blockNumber,
|
||||
events
|
||||
}
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
return undefined
|
||||
} catch (err) {
|
||||
return undefined
|
||||
}
|
||||
@ -311,15 +382,19 @@ class EventService {
|
||||
|
||||
async getEventsFromRpc({ fromBlock, type }) {
|
||||
try {
|
||||
const { blockDifference } = await this.getBlocksDiff({ fromBlock })
|
||||
const blockRange = 10000
|
||||
|
||||
let events
|
||||
|
||||
if (Number(this.netId) === 1) {
|
||||
if (blockDifference < blockRange) {
|
||||
const rpcEvents = await this.getEventsPartFromRpc({ fromBlock, toBlock: 'latest', type })
|
||||
events = rpcEvents?.events || []
|
||||
} else {
|
||||
const rpcEvents = await this.getBatchEventsFromRpc({ fromBlock, type })
|
||||
events = rpcEvents?.events || []
|
||||
}
|
||||
|
||||
return events
|
||||
} catch (err) {
|
||||
return []
|
||||
@ -332,6 +407,7 @@ class EventService {
|
||||
const rpcEvents = await this.getEventsFromRpc({ fromBlock, type })
|
||||
|
||||
const allEvents = [].concat(rpcEvents || [])
|
||||
|
||||
if (allEvents.length) {
|
||||
return {
|
||||
events: allEvents,
|
||||
@ -374,7 +450,9 @@ class EventsFactory {
|
||||
instances = new Map()
|
||||
|
||||
constructor(rpcUrl) {
|
||||
this.provider = new Web3(rpcUrl).eth
|
||||
const httpProvider = new Web3.providers.HttpProvider(rpcUrl, httpConfig)
|
||||
|
||||
this.provider = new Web3(httpProvider).eth
|
||||
}
|
||||
|
||||
getBlockNumber = () => {
|
||||
@ -386,7 +464,7 @@ class EventsFactory {
|
||||
}
|
||||
|
||||
getService = (payload) => {
|
||||
const instanceName = `${payload.currency}_${payload.amount}`
|
||||
const instanceName = `${payload.netId}_${payload.currency}_${payload.amount}`
|
||||
|
||||
if (this.instances.has(instanceName)) {
|
||||
return this.instances.get(instanceName)
|
||||
|
@ -39,6 +39,7 @@ const defaultOptions = {
|
||||
|
||||
const client = new ApolloClient({
|
||||
uri: link,
|
||||
credentials: 'omit',
|
||||
cache: new InMemoryCache(),
|
||||
defaultOptions
|
||||
})
|
||||
@ -46,6 +47,7 @@ const client = new ApolloClient({
|
||||
const registryClient = new ApolloClient({
|
||||
uri: 'https://api.thegraph.com/subgraphs/name/tornadocash/tornado-relayer-registry',
|
||||
cache: new InMemoryCache(),
|
||||
credentials: 'omit',
|
||||
defaultOptions
|
||||
})
|
||||
|
||||
|
@ -5,6 +5,8 @@ import { download } from '@/store/snark'
|
||||
import networkConfig from '@/networkConfig'
|
||||
import { mimc, bloomService } from '@/services'
|
||||
|
||||
const supportedCaches = ['1', '56', '100', '137']
|
||||
|
||||
class MerkleTreeService {
|
||||
constructor({ netId, amount, currency, commitment, instanceName }) {
|
||||
this.netId = netId
|
||||
@ -14,18 +16,19 @@ class MerkleTreeService {
|
||||
this.instanceName = instanceName
|
||||
|
||||
this.idb = window.$nuxt.$indexedDB(netId)
|
||||
|
||||
this.bloomService = bloomService({
|
||||
netId,
|
||||
amount,
|
||||
commitment,
|
||||
instanceName,
|
||||
fileFolder: 'trees',
|
||||
fileName: `deposits_${currency}_${amount}_bloom.json.zip`
|
||||
fileName: `deposits_${netId}_${currency}_${amount}_bloom.json.gz`
|
||||
})
|
||||
}
|
||||
|
||||
getFileName(partNumber = trees.PARTS_COUNT) {
|
||||
return `trees/deposits_${this.currency}_${this.amount}_slice${partNumber}.json.zip`
|
||||
return `trees/deposits_${this.netId}_${this.currency}_${this.amount}_slice${partNumber}.json.gz`
|
||||
}
|
||||
|
||||
createTree({ events }) {
|
||||
@ -153,8 +156,7 @@ class MerkleTreeService {
|
||||
}
|
||||
|
||||
async getTree() {
|
||||
const { nativeCurrency } = networkConfig[`netId${this.netId}`]
|
||||
const hasCache = nativeCurrency === this.currency && Number(this.netId) === 1
|
||||
const hasCache = supportedCaches.includes(this.netId.toString())
|
||||
|
||||
let cachedTree = await this.getTreeFromDB()
|
||||
|
||||
@ -184,7 +186,7 @@ class TreesFactory {
|
||||
instances = new Map()
|
||||
|
||||
getService = (payload) => {
|
||||
const instanceName = `${payload.currency}_${payload.amount}`
|
||||
const instanceName = `${payload.netId}_${payload.currency}_${payload.amount}`
|
||||
if (this.instances.has(instanceName)) {
|
||||
return this.instances.get(instanceName)
|
||||
}
|
||||
|
@ -1,15 +1,16 @@
|
||||
import Web3 from 'web3'
|
||||
import namehash from 'eth-ens-namehash'
|
||||
import { BigNumber as BN } from 'bignumber.js'
|
||||
import { toChecksumAddress } from 'web3-utils'
|
||||
import { toChecksumAddress, isAddress } from 'web3-utils'
|
||||
|
||||
import { graph } from '@/services'
|
||||
import networkConfig from '@/networkConfig'
|
||||
import { REGISTRY_DEPLOYED_BLOCK } from '@/constants'
|
||||
import { sleep, flattenNArray } from '@/utils'
|
||||
|
||||
import AggregatorABI from '@/abis/Aggregator.abi.json'
|
||||
import RelayerRegistryABI from '@/abis/RelayerRegistry.abi.json'
|
||||
|
||||
const MIN_STAKE_BALANCE = '0x22B1C8C1227A00000' // 40 TORN
|
||||
const MIN_STAKE_BALANCE = '0X1B1AE4D6E2EF500000' // 500 TORN
|
||||
|
||||
const subdomains = Object.values(networkConfig).map(({ ensSubdomainKey }) => ensSubdomainKey)
|
||||
|
||||
@ -24,28 +25,88 @@ class RelayerRegister {
|
||||
this.relayerRegistry = new this.provider.Contract(RelayerRegistryABI, registryContract)
|
||||
}
|
||||
|
||||
fetchEvents = async (fromBlock, toBlock) => {
|
||||
if (fromBlock <= toBlock) {
|
||||
try {
|
||||
const registeredEventsPart = await this.relayerRegistry.getPastEvents('RelayerRegistered', {
|
||||
fromBlock,
|
||||
toBlock
|
||||
fetchEvents = ({ fromBlock, toBlock }, shouldRetry = false) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (fromBlock <= toBlock) {
|
||||
this.relayerRegistry
|
||||
.getPastEvents('RelayerRegistered', { fromBlock, toBlock })
|
||||
.then((events) => resolve(events))
|
||||
.catch((_) => {
|
||||
if (shouldRetry) {
|
||||
sleep(500).then(() =>
|
||||
this.fetchEvents({ fromBlock, toBlock })
|
||||
.then((events) => resolve(events))
|
||||
.catch((_) => resolve(undefined))
|
||||
)
|
||||
} else {
|
||||
resolve(undefined)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolve(undefined)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
batchFetchEvents = async ({ fromBlock, toBlock }) => {
|
||||
const batchSize = 10
|
||||
const blockRange = 10000
|
||||
const blockDifference = toBlock - fromBlock
|
||||
const chunkCount = Math.ceil(blockDifference / blockRange)
|
||||
const blockDenom = Math.ceil(blockDifference / chunkCount)
|
||||
const chunkSize = Math.ceil(chunkCount / batchSize)
|
||||
|
||||
let failed = []
|
||||
let events = []
|
||||
let lastBlock = fromBlock
|
||||
|
||||
for (let batchIndex = 0; batchIndex < chunkSize; batchIndex++) {
|
||||
const params = new Array(batchSize).fill('').map((_, i) => {
|
||||
const toBlock = (i + 1) * blockDenom + lastBlock
|
||||
const fromBlock = toBlock - blockDenom
|
||||
return { fromBlock, toBlock }
|
||||
})
|
||||
const promises = new Array(batchSize).fill('').map(
|
||||
(_, i) =>
|
||||
new Promise((resolve) =>
|
||||
sleep(i * 20).then(() => {
|
||||
this.fetchEvents(params[i], true).then((batch) => {
|
||||
if (!batch) {
|
||||
resolve([{ isFailedBatch: true, fromBlock, toBlock }])
|
||||
} else {
|
||||
resolve(batch)
|
||||
}
|
||||
})
|
||||
})
|
||||
)
|
||||
)
|
||||
const requests = flattenNArray(await Promise.all(promises))
|
||||
const failedIndexes = requests
|
||||
.filter((e) => e.isFailedBatch)
|
||||
.map((e) => {
|
||||
const reqIndex = requests.indexOf(e)
|
||||
return params[reqIndex]
|
||||
})
|
||||
|
||||
return registeredEventsPart
|
||||
} catch (error) {
|
||||
const midBlock = (fromBlock + toBlock) >> 1
|
||||
|
||||
if (midBlock - fromBlock < 2) {
|
||||
throw new Error(`error fetching events: ${error.message}`)
|
||||
}
|
||||
|
||||
const arr1 = await this.fetchEvents(fromBlock, midBlock)
|
||||
const arr2 = await this.fetchEvents(midBlock + 1, toBlock)
|
||||
return [...arr1, ...arr2]
|
||||
}
|
||||
failed = failed.concat(failedIndexes || [])
|
||||
events = events.concat(requests.filter((e) => !e.isFailedBatch))
|
||||
lastBlock = params[batchSize - 1].toBlock
|
||||
}
|
||||
return []
|
||||
|
||||
if (failed.length !== 0) {
|
||||
const failedReqs = failed.map((e) => this.fetchEvents(e))
|
||||
const failedBatch = flattenNArray(await Promise.all(failedReqs))
|
||||
|
||||
events = events.concat(failedBatch || [])
|
||||
}
|
||||
|
||||
events = events.map((e) => ({ ...e.returnValues }))
|
||||
|
||||
if (events.length === 0) {
|
||||
throw new Error('Failed to fetch registry events')
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
saveEvents = async ({ events, lastSyncBlock, storeName }) => {
|
||||
@ -96,51 +157,70 @@ class RelayerRegister {
|
||||
}
|
||||
}
|
||||
|
||||
getENSAddress = async (ensName) => {
|
||||
const { url } = Object.values(networkConfig.netId1.rpcUrls)[0]
|
||||
const provider = new Web3(url)
|
||||
|
||||
const ensAddress = await provider.eth.ens.getAddress(ensName)
|
||||
|
||||
return ensAddress
|
||||
}
|
||||
|
||||
fetchRelayers = async () => {
|
||||
const blockRange = 10000
|
||||
// eslint-disable-next-line prefer-const
|
||||
let { blockFrom, blockTo, cachedEvents } = await this.getCachedData()
|
||||
let { blockTo, cachedEvents } = await this.getCachedData()
|
||||
let allRelayers = cachedEvents
|
||||
|
||||
if (blockFrom !== blockTo) {
|
||||
const registeredRelayersEvents = await graph.getAllRegisters(blockFrom)
|
||||
const currentBlockNumber = await this.provider.getBlockNumber()
|
||||
const fromBlock = cachedEvents.length === 0 ? REGISTRY_DEPLOYED_BLOCK[1] : blockTo
|
||||
const blockDifference = currentBlockNumber - fromBlock
|
||||
|
||||
let relayers = {
|
||||
lastSyncBlock: registeredRelayersEvents.lastSyncBlock,
|
||||
events: registeredRelayersEvents.events.map((el) => ({
|
||||
ensName: el.ensName,
|
||||
relayerAddress: toChecksumAddress(el.address)
|
||||
}))
|
||||
try {
|
||||
let toBlock
|
||||
let registerRelayerEvents
|
||||
let lastSyncBlock = blockTo
|
||||
|
||||
if (cachedEvents.length > 0 || blockDifference === 0) {
|
||||
return cachedEvents
|
||||
} else if (blockDifference >= blockRange) {
|
||||
toBlock = currentBlockNumber
|
||||
registerRelayerEvents = await this.batchFetchEvents({ fromBlock, toBlock })
|
||||
lastSyncBlock = toBlock
|
||||
} else {
|
||||
toBlock = fromBlock + blockRange
|
||||
registerRelayerEvents = await this.fetchEvents({ fromBlock, toBlock }, true)
|
||||
lastSyncBlock = toBlock
|
||||
}
|
||||
|
||||
const isGraphLate = relayers.lastSyncBlock && blockTo > Number(relayers.lastSyncBlock)
|
||||
const relayerEvents = cachedEvents.concat(registerRelayerEvents || [])
|
||||
const events = []
|
||||
|
||||
if (isGraphLate) {
|
||||
blockFrom = relayers.lastSyncBlock
|
||||
}
|
||||
for (let x = 0; x < relayerEvents.length; x++) {
|
||||
const { ensName, relayerAddress } = relayerEvents[x]
|
||||
let ensAddress
|
||||
|
||||
if (!relayers.events.length || isGraphLate) {
|
||||
const multicallEvents = await this.fetchEvents(blockFrom, blockTo)
|
||||
const eventsRelayers = multicallEvents.map(({ returnValues }) => ({
|
||||
ensName: returnValues.ensName,
|
||||
relayerAddress: returnValues.relayerAddress
|
||||
}))
|
||||
|
||||
relayers = {
|
||||
lastSyncBlock: blockTo,
|
||||
events: relayers.events.concat(eventsRelayers)
|
||||
if (!isAddress(relayerAddress)) {
|
||||
ensAddress = await this.getENSAddress(ensName)
|
||||
ensAddress = toChecksumAddress(ensAddress)
|
||||
} else {
|
||||
ensAddress = relayerAddress
|
||||
}
|
||||
|
||||
events.push({ ensName, relayerAddress: ensAddress })
|
||||
}
|
||||
|
||||
await this.saveEvents({ storeName: 'register_events', ...relayers })
|
||||
allRelayers = allRelayers.concat(relayers.events)
|
||||
}
|
||||
await this.saveEvents({ storeName: 'register_events', lastSyncBlock, events })
|
||||
|
||||
allRelayers = allRelayers.concat(events)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
return allRelayers
|
||||
}
|
||||
|
||||
filterRelayer = (acc, curr, ensSubdomainKey, relayer) => {
|
||||
const subdomainIndex = subdomains.indexOf(ensSubdomainKey)
|
||||
|
||||
const mainnetSubdomain = curr.records[0]
|
||||
const hostname = curr.records[subdomainIndex]
|
||||
const isHostWithProtocol = hostname.includes('http')
|
||||
@ -191,7 +271,6 @@ class RelayerRegister {
|
||||
|
||||
getRelayers = async (ensSubdomainKey) => {
|
||||
const relayers = await this.fetchRelayers()
|
||||
|
||||
const validRelayers = await this.getValidRelayers(relayers, ensSubdomainKey)
|
||||
|
||||
return validRelayers
|
||||
|
BIN
static/events/deposits_100_xdai_100.json.gz
Normal file
BIN
static/events/deposits_100_xdai_100.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_100_xdai_1000.json.gz
Normal file
BIN
static/events/deposits_100_xdai_1000.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_100_xdai_10000.json.gz
Normal file
BIN
static/events/deposits_100_xdai_10000.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_100_xdai_100000.json.gz
Normal file
BIN
static/events/deposits_100_xdai_100000.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_137_matic_100.json.gz
Normal file
BIN
static/events/deposits_137_matic_100.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_137_matic_1000.json.gz
Normal file
BIN
static/events/deposits_137_matic_1000.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_137_matic_10000.json.gz
Normal file
BIN
static/events/deposits_137_matic_10000.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_137_matic_100000.json.gz
Normal file
BIN
static/events/deposits_137_matic_100000.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_1_eth_0.1.json.gz
Normal file
BIN
static/events/deposits_1_eth_0.1.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_1_eth_1.json.gz
Normal file
BIN
static/events/deposits_1_eth_1.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_1_eth_10.json.gz
Normal file
BIN
static/events/deposits_1_eth_10.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_1_eth_100.json.gz
Normal file
BIN
static/events/deposits_1_eth_100.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_56_bnb_0.1.json.gz
Normal file
BIN
static/events/deposits_56_bnb_0.1.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_56_bnb_1.json.gz
Normal file
BIN
static/events/deposits_56_bnb_1.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_56_bnb_10.json.gz
Normal file
BIN
static/events/deposits_56_bnb_10.json.gz
Normal file
Binary file not shown.
BIN
static/events/deposits_56_bnb_100.json.gz
Normal file
BIN
static/events/deposits_56_bnb_100.json.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
static/events/encrypted_notes_1.json.gz
Normal file
BIN
static/events/encrypted_notes_1.json.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/events/encrypted_notes_100.json.gz
Normal file
BIN
static/events/encrypted_notes_100.json.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/events/encrypted_notes_137.json.gz
Normal file
BIN
static/events/encrypted_notes_137.json.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/events/encrypted_notes_5.json.gz
Normal file
BIN
static/events/encrypted_notes_5.json.gz
Normal file
Binary file not shown.
BIN
static/events/encrypted_notes_56.json.gz
Normal file
BIN
static/events/encrypted_notes_56.json.gz
Normal file
Binary file not shown.
Binary file not shown.
BIN
static/events/withdrawals_100_xdai_100.json.gz
Normal file
BIN
static/events/withdrawals_100_xdai_100.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_100_xdai_1000.json.gz
Normal file
BIN
static/events/withdrawals_100_xdai_1000.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_100_xdai_10000.json.gz
Normal file
BIN
static/events/withdrawals_100_xdai_10000.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_100_xdai_100000.json.gz
Normal file
BIN
static/events/withdrawals_100_xdai_100000.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_137_matic_100.json.gz
Normal file
BIN
static/events/withdrawals_137_matic_100.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_137_matic_1000.json.gz
Normal file
BIN
static/events/withdrawals_137_matic_1000.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_137_matic_10000.json.gz
Normal file
BIN
static/events/withdrawals_137_matic_10000.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_137_matic_100000.json.gz
Normal file
BIN
static/events/withdrawals_137_matic_100000.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_1_eth_0.1.json.gz
Normal file
BIN
static/events/withdrawals_1_eth_0.1.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_1_eth_1.json.gz
Normal file
BIN
static/events/withdrawals_1_eth_1.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_1_eth_10.json.gz
Normal file
BIN
static/events/withdrawals_1_eth_10.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_1_eth_100.json.gz
Normal file
BIN
static/events/withdrawals_1_eth_100.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_56_bnb_0.1.json.gz
Normal file
BIN
static/events/withdrawals_56_bnb_0.1.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_56_bnb_1.json.gz
Normal file
BIN
static/events/withdrawals_56_bnb_1.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_56_bnb_10.json.gz
Normal file
BIN
static/events/withdrawals_56_bnb_10.json.gz
Normal file
Binary file not shown.
BIN
static/events/withdrawals_56_bnb_100.json.gz
Normal file
BIN
static/events/withdrawals_56_bnb_100.json.gz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user