Compare commits

...

35 Commits

Author SHA1 Message Date
AlienTornadosaurusHex
9e3861c56f enable avax
Signed-off-by: AlienTornadosaurusHex <>
2023-07-04 18:25:01 +00:00
AlienTornadosaurusHex
03543f87a8 update README
Signed-off-by: AlienTornadosaurusHex <>
2023-07-04 18:20:44 +00:00
AlienTornadosaurusHex
02f79a0de0 allow setting sync interval for blocks
Signed-off-by: AlienTornadosaurusHex <>
2023-07-04 13:57:33 +00:00
Theo
6130c46d90 Merge pull request '#PR1: classic-ui: Prefix static caches with network id and code quality' (#25) from AlienTornadosaurusHex/classic-ui:master into master
Reviewed-on: https://git.tornado.ws/tornadocash/classic-ui/pulls/25
2023-06-27 13:53:49 +02:00
AlienTornadosaurusHex
62f079608e hopefully fix rest of issues with netId addition
Signed-off-by: AlienTornadosaurusHex <>
2023-06-23 17:00:40 +00:00
AlienTornadosaurusHex
2cc751f9d2 set proper names for indexed db stores
Signed-off-by: AlienTornadosaurusHex <>
2023-06-22 22:00:36 +00:00
AlienTornadosaurusHex
2623117f17 create file if reading and not exist
Signed-off-by: AlienTornadosaurusHex <>
2023-06-22 20:39:28 +00:00
AlienTornadosaurusHex
2e96df3b7f move tornado rpc to top
Signed-off-by: AlienTornadosaurusHex <>
2023-06-22 15:07:58 +00:00
AlienTornadosaurusHex
7342d41faf Merge branch 'master' of https://git.tornado.ws/tornadocash/classic-ui 2023-06-22 15:07:03 +00:00
Theo
22a372fae1 Update docs & redirect link, add Tornado RPC to all chains 2023-06-13 05:57:35 -07:00
Theo
1f24d46360 Fix proposal naming & editing: remove crutch code, validate JSON in proposal 15 directly, add title to empty hacker proposal 21 2023-06-08 23:52:55 -07:00
Theo
59c252b826 Eslint fix 2023-06-08 23:49:14 -07:00
Theo
3f04b9392a Change links to actual 2023-06-04 12:41:27 -07:00
Theo
6ec1a509cf Change Tornado dependencies source to Tornado Git registry 2023-06-04 09:05:53 -07:00
Theo
0d700118d6 Change staking contract address after proposal 22 execution 2023-06-04 09:04:56 -07:00
AlienTornadosaurusHex
03462c0a41 updateEvents: improve script
Signed-off-by: AlienTornadosaurusHex <>
2023-05-19 17:57:10 +00:00
AlienTornadosaurusHex
937c221e22 allow any token events to be updated
Signed-off-by: AlienTornadosaurusHex <>
2023-05-18 22:26:08 +00:00
AlienTornadosaurusHex
2fbd860f51 networkConfig: keep default export separate to not break UI
Signed-off-by: AlienTornadosaurusHex <>
2023-05-16 15:25:03 +00:00
AlienTornadosaurusHex
ad0d1391dc static cache should be prefixed by network
Signed-off-by: AlienTornadosaurusHex <>
2023-05-12 22:19:58 +00:00
Theo
e49e3e0c0d Update cache for all available chains 2023-05-09 23:41:49 +03:00
Theo
ed422786c0 Improve logging when updating events 2023-05-09 23:41:03 +03:00
Theo
9d1f66eec0 Add unarchived .json event files to gitignore 2023-05-09 23:36:54 +03:00
gozzy
a8c238c2af correct proposeByDelegate support 2023-04-16 02:36:20 +00:00
gozzy
eb59acd319 event promise chaining 2023-04-16 02:30:43 +00:00
gozzy
322184baf8 update rpcs 2023-04-13 00:35:17 +00:00
gozzy
b492ef6e20 increase relayer minimum stake balance 2023-04-11 19:47:02 +00:00
gozzy
4ecde79c86 proposeByDelegate support 2023-03-23 03:03:21 +00:00
gozzy
2b61afbafe improve rpc rate-limit conditions 2023-03-22 20:50:13 +00:00
gozzy
aef16eda5f factor for invalid proposal json 2023-03-22 10:03:27 +00:00
gozzy
5aef9e6d06 fix: #11 2023-01-31 19:35:39 +00:00
gozzy
ea97a39aff increase gas price timeout & update rpcs 2022-12-03 16:29:21 +00:00
gozzy
11c87ff319 eth rpc custom configuration 2022-12-03 16:02:03 +00:00
gozzy
064c481c02 event retry & err conditioning 2022-12-02 21:02:43 +00:00
gozzy
90ef7362bf Merge pull request 'Community build #003' (#10) from staging into master
Reviewed-on: https://development.tornadocash.community/tornadocash/classic-ui/pulls/10
2022-11-24 10:55:39 +00:00
gozzy
c80e4bb2fb Merge pull request 'Community build #002' (#3) from staging
[#3](https://development.tornadocash.community/tornadocash/classic-ui/pulls/3)
2022-09-22 07:18:55 +00:00
173 changed files with 662 additions and 344 deletions

3
.gitignore vendored
View File

@ -87,3 +87,6 @@ sw.*
# Mac OSX
.DS_Store
static/*/*.json

1
.npmrc Normal file
View File

@ -0,0 +1 @@
@tornado:registry=https://git.tornado.ws/api/packages/tornado-packages/npm/

View File

@ -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
@ -31,29 +31,42 @@ For detailed explanation on how things work, checkout [Nuxt.js docs](https://nux
## 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
```

View File

@ -37,7 +37,7 @@
<b-button
tag="a"
type="is-icon"
href="https://development.tornadocash.community/tornadocash/classic-ui"
href="https://git.tornado.ws/tornadocash/classic-ui"
target="_blank"
rel="noopener noreferrer"
icon-right="git"

View File

@ -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"

View File

@ -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

View File

@ -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
}
}

View File

@ -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)

View File

@ -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 Tornados 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 Tornados 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",

View File

@ -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",

View File

@ -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é",

View File

@ -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": "Выбранный кошелёк не поддерживается",

View File

@ -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 Tornadonun 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 Tornadonun 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",

View File

@ -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": "此钱包不受支持",

View File

@ -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 })
})

View File

@ -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,9 +301,17 @@ export default {
multicall: '0x842eC2c7D803033Edf55E478F461FC547Bc54EB2',
echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4',
rpcUrls: {
Arbitrum: {
name: '1RPC',
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 RPC',
url: 'https://arb1.arbitrum.io/rpc'
}
},
tokens: {
@ -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: {

View File

@ -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',

View File

@ -7,14 +7,14 @@
"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"
@ -49,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",

View File

@ -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"
>

View File

@ -4,12 +4,8 @@ export default ({ store, isHMR, app }, inject) => {
}
function main() {
const whiteListedDomains = [
'tornadocash.3th.li',
'tornadocash.3th.ws',
'tornadocash.eth.link',
'tornadocash.eth.limo',
'tornadocashcommunity.3th.li',
'tornadocashcommunity.3th.ws',
'tornadocashcommunity.eth.link',
'tornadocashcommunity.eth.limo'
]

View File

@ -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}`,
name: `withdrawals_${netId}_${token}_${amount}`,
keyPath: 'blockNumber',
indexes: WITHDRAWAL_INDEXES
},
{
name: `stringify_tree_${token}_${amount}`,
name: `stringify_tree_${netId}_${token}_${amount}`,
keyPath: 'hashTree'
}
)

View File

@ -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'
}
}

View File

@ -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)
}
}
}

View File

@ -2,27 +2,27 @@ import fs from 'fs'
import zlib from 'zlib'
import Web3 from 'web3'
import networkConfig from '../../networkConfig'
import networkConfig, { blockSyncInterval } from '../../networkConfig'
export async function download({ name, directory, contentType }) {
export function download({ name, directory }) {
const path = `${directory}${name}.gz`.toLowerCase()
const data = fs.readFileSync(path)
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)
return {
events,
lastBlock: events[events.length - 1].blockNumber
lastBlock: events[events.length - 1].blockNumber
}
}
} catch (err) {
@ -53,7 +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 blockRange = 10000
const blockRange = blockSyncInterval ? blockSyncInterval : 10_000
let chunksCount = blockDifference === 0 ? 1 : Math.ceil(blockDifference / blockRange)
const chunkSize = Math.ceil(blockDifference / chunksCount)
@ -67,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))

View File

@ -1,14 +1,11 @@
import fs from 'fs'
import zlib from 'zlib'
export async function save(filePath) {
const directories = filePath.split('/')
const fileName = directories[directories.length - 1]
export function save(filePath) {
try {
const data = fs.readFileSync(`${filePath}`)
const payload = await zlib.deflateSync(data, {
const payload = zlib.deflateSync(data, {
level: zlib.constants.Z_BEST_COMPRESSION,
strategy: zlib.constants.Z_FILTERED
})

View File

@ -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(', ')}`)
}

View File

@ -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', '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) => a.blockNumber - b.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()

View File

@ -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,6 +47,7 @@ function createTreeZip(netId) {
treesFolder.forEach((fileName) => {
fileName = `${TREES_PATH}${fileName}`
const isInstanceFile = !fileName.includes('.gz') && fileName.includes(baseFilename)
if (isInstanceFile) {
@ -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()

View File

@ -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)
}
}

View File

@ -2,13 +2,11 @@ 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, httpConfig } from '@/constants'
import { sleep, flattenNArray, formatEvents, capitalizeFirstLetter } from '@/utils'
const supportedCaches = ['1', '56', '100', '137']
let store
if (process.browser) {
window.onNuxtReady(({ $store }) => {
@ -21,7 +19,7 @@ class EventService {
this.idb = window.$nuxt.$indexedDB(netId)
const { nativeCurrency } = networkConfig[`netId${netId}`]
const hasCache = supportedCaches.includes(netId.toString())
const hasCache = enabledChains.includes(netId.toString())
this.netId = netId
this.amount = amount
@ -35,7 +33,7 @@ class EventService {
}
getInstanceName(type) {
return `${type}s_${this.currency}_${this.amount}`
return `${type}s_${this.netId}_${this.currency}_${this.amount}`
}
updateEventProgress(percentage, type) {
@ -80,7 +78,6 @@ class EventService {
}
return a.blockNumber - b.blockNumber
})
const lastBlock = allEvents[allEvents.length - 1].blockNumber
this.saveEvents({ events: allEvents, lastBlock, type })
@ -247,87 +244,80 @@ class EventService {
}
}
getPastEvents({ fromBlock, toBlock, type }) {
getPastEvents({ fromBlock, toBlock, type }, shouldRetry = false, i = 0) {
return new Promise((resolve, reject) => {
const repsonse = this.contract.getPastEvents(capitalizeFirstLetter(type), {
fromBlock,
toBlock
})
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
if (repsonse) {
resolve(repsonse)
} else {
reject(new Error())
}
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({ fromBlock, toBlock, type }, shouldRetry = false, i = 0) {
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
}
}
let events = []
try {
events = await this.getPastEvents({ fromBlock, toBlock, type })
} catch (e) {
if (shouldRetry) {
i = i + 1
// maximum 10 second buffer for rate-limiting
await sleep(2000 * i)
events = await this.getEventsPartFromRpc(
{
fromBlock,
toBlock,
type
},
i !== 5,
i
)
}
}
if (!events?.length) {
return {
events: [],
lastBlock: fromBlock
}
}
return {
events: formatEvents(events, type),
lastBlock: events[events.length - 1].blockNumber
}
} catch (err) {
return undefined
}
}
createBatchRequest({ batchIndex, batchSize, batchBlocks, blockDenom, type }) {
return new Array(batchSize).fill('').map(
(_, i) =>
new Promise(async (resolve) => {
const toBlock = batchBlocks[batchIndex * batchSize + i]
const fromBlock = toBlock - blockDenom
const batchEvents = await this.getEventsPartFromRpc(
{
fromBlock,
toBlock,
type
},
true
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)
}
})
)
resolve(batchEvents.events)
})
)
)
}
@ -335,38 +325,56 @@ class EventService {
try {
const batchSize = 10
const blockRange = 10000
const { blockDifference, currentBlockNumber } = await this.getBlocksDiff({ fromBlock })
let [events, failed] = [[], []]
let lastBlock = fromBlock
const { blockDifference, currentBlockNumber } = await this.getBlocksDiff({ fromBlock })
const batchDigest = blockDifference === 0 ? 1 : Math.ceil(blockDifference / blockRange)
const blockDenom = Math.ceil(blockDifference / batchDigest)
const batchCount = Math.ceil(batchDigest / batchSize)
const blocks = new Array(batchCount * batchSize).fill('')
const batchBlocks = blocks.map((_, i) => (i + 1) * blockDenom + fromBlock)
let events = []
if (fromBlock < currentBlockNumber) {
this.updateEventProgress(0, type)
await this.updateEventProgress(0, type)
for (let batchIndex = 0; batchIndex < batchCount; batchIndex++) {
const batch = await Promise.all(
this.createBatchRequest({ batchIndex, batchBlocks, blockDenom, batchSize, type })
)
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)
this.updateEventProgress(batchIndex / batchCount, type)
events = events.concat(batch)
await sleep(200)
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)
}
events = flattenNArray(events)
return {
lastBlock: events[events.length - 1].blockNumber,
events
}
} else {
return undefined
}
return undefined
} catch (err) {
return undefined
}
@ -456,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)

View File

@ -16,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.gz`
fileName: `deposits_${netId}_${currency}_${amount}_bloom.json.gz`
})
}
getFileName(partNumber = trees.PARTS_COUNT) {
return `trees/deposits_${this.currency}_${this.amount}_slice${partNumber}.json.gz`
return `trees/deposits_${this.netId}_${this.currency}_${this.amount}_slice${partNumber}.json.gz`
}
createTree({ events }) {
@ -185,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)
}

View File

@ -10,7 +10,7 @@ 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)
@ -28,54 +28,83 @@ class RelayerRegister {
fetchEvents = ({ fromBlock, toBlock }, shouldRetry = false) => {
return new Promise((resolve, reject) => {
if (fromBlock <= toBlock) {
try {
const registeredEventsPart = this.relayerRegistry.getPastEvents('RelayerRegistered', {
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)
}
})
resolve(registeredEventsPart)
} catch (error) {
if (shouldRetry) {
sleep(1000)
const events = this.fetchEvents({ fromBlock, toBlock })
resolve(events)
} else {
reject(new Error(error))
}
}
} else {
resolve([])
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)
const promises = new Array(chunkCount).fill('').map(
(_, i) =>
new Promise((resolve) => {
sleep(300)
let failed = []
let events = []
let lastBlock = fromBlock
const batch = this.fetchEvents(
{
fromBlock: i * blockDenom + fromBlock,
toBlock: (i + 1) * blockDenom + fromBlock
},
true
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)
}
})
})
)
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]
})
)
const batchEvents = flattenNArray(await Promise.all(promises))
const events = batchEvents.map((e) => ({ ...e.returnValues }))
failed = failed.concat(failedIndexes || [])
events = events.concat(requests.filter((e) => !e.isFailedBatch))
lastBlock = params[batchSize - 1].toBlock
}
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
}
@ -170,6 +199,7 @@ class RelayerRegister {
for (let x = 0; x < relayerEvents.length; x++) {
const { ensName, relayerAddress } = relayerEvents[x]
let ensAddress
if (!isAddress(relayerAddress)) {
ensAddress = await this.getENSAddress(ensName)
ensAddress = toChecksumAddress(ensAddress)

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More