Compare commits

...

11 Commits

Author SHA1 Message Date
torndao
30c4b44a5c fix ipfs detection
Some checks failed
Node.js CI / cleanup (push) Has been cancelled
Node.js CI / build (push) Has been cancelled
Node.js CI / deploy-minified (push) Has been cancelled
Node.js CI / deploy-docker (push) Has been cancelled
Node.js CI / deploy-ipfs (push) Has been cancelled
Node.js CI / notify (push) Has been cancelled
2025-07-23 15:50:32 +08:00
torndao
10a96e4ecc Update Ethereum RPCs 2025-07-23 14:14:43 +08:00
torndao
c82771d9d5 rename tornado dot cash to tornado cash 2025-07-23 14:03:28 +08:00
torndao
b1e9965c62 Merge ETC code and add Pool Fee calculation 2025-06-09 16:32:01 +08:00
torndao
79af93bc69 add ETC Network 2025-06-08 21:59:57 +08:00
torndao
b1ae1c1623 Fixed the issue with incorrect relayers data in cache 2025-06-05 12:26:29 +08:00
torndao
170765864c Fixed the issue of not being able to fetch new relayers 2025-06-04 15:15:31 +08:00
torndao
5f7521882b Add USDT and USDC risk warnings 2025-05-29 14:32:15 +08:00
torndao
cc901c105c Fix block number of register_events 2025-05-23 14:52:13 +08:00
torndao
6634754a0e The relayer list is sorted by the stakeBalance from largest to smallest 2025-05-17 21:07:09 +08:00
torndao
54a9dd40cb filter out duplicate relayers 2025-04-26 13:44:11 +08:00
22 changed files with 307 additions and 79 deletions

1
.gitignore vendored
View File

@@ -93,3 +93,4 @@ static/*/*.json
# UI build archive
dist.zip
package-lock.json

View File

@@ -317,6 +317,10 @@
mask-image: url('../img/icons/ethereum.svg');
}
&-ethereum-classic {
mask-image: url('../img/icons/ethereum.svg');
}
&-ethereum-sepolia {
mask-image: url('../img/icons/ethereum.svg');
}

View File

@@ -52,7 +52,7 @@
type="is-primary is-fullwidth"
:loading="isDepositBtnClicked"
data-test="button_deposit"
@click="onDeposit"
@click="onPreDeposit"
>
{{ $t('depositButton') }}
</b-button>
@@ -65,6 +65,7 @@ import { mapGetters } from 'vuex'
import ApproveModalBox from '@/components/ApproveModalBox'
import BalanceModalBox from '@/components/BalanceModalBox'
import DepositModalBox from '@/components/DepositModalBox'
import RiskModalBox from '@/components/RiskModalBox'
import { ConnectButton } from '@/components/web3Connect'
@@ -194,6 +195,19 @@ export default {
approveModal.$on('close', onApproval)
}
this.isDepositBtnClicked = false
},
onPreDeposit() {
if (this.selectedToken.toUpperCase() === 'USDT' || this.selectedToken.toUpperCase() === 'USDC') {
const riskModal = this.$buefy.modal.open({
parent: this,
component: RiskModalBox,
hasModalCard: true,
width: 440
})
riskModal.$on('close', this.onDeposit)
} else {
this.onDeposit()
}
}
}
}

View File

@@ -58,6 +58,14 @@
rel="noopener noreferrer"
icon-right="telegram"
></b-button>
<b-button
tag="a"
type="is-icon"
href="https://codeberg.org/torndao/classic-ui"
target="_blank"
rel="noopener noreferrer"
icon-right="git"
></b-button>
<b-button
tag="a"
type="is-icon"
@@ -117,13 +125,7 @@ export default {
...mapGetters('metamask', ['networkConfig', 'netId']),
...mapGetters('txHashKeeper', ['addressExplorerUrl']),
duneLink() {
const mainnetNetworks = [1, 5]
if (mainnetNetworks.includes(Number(this.netId))) {
return 'https://dune.com/davidcaviar/tornado-cash'
}
return 'https://dune.com/stakingbutterfly/tornado-cash-staking'
},
locales() {
return this.$i18n.availableLocales

View File

@@ -0,0 +1,28 @@
<template>
<div class="modal-card box box-modal">
<header class="box-modal-header is-spaced">
<div class="box-modal-title">{{ $t('information') }}</div>
<button type="button" class="delete" @click="$emit('close')" />
</header>
<i18n path="freezeRisk" tag="div" class="note">
<template v-slot:currency>{{ selectedCurrency }}</template>
</i18n>
<b-button type="is-primary is-fullwidth" @click="close">{{ $t('close') }}</b-button>
</div>
</template>
<script>
/* eslint-disable no-console */
import { mapGetters } from 'vuex'
export default {
components: {},
computed: {
...mapGetters('application', ['selectedCurrency'])
},
methods: {
close() {
this.$parent.close()
}
}
}
</script>

View File

@@ -26,6 +26,10 @@
{{ $t('relayerFee') }}
<span data-test="label_relayer_fee">{{ toDecimals(relayerFee, null, 6) }} {{ currency }}</span>
</div>
<div v-if="currency === 'ETC'" class="withdraw-data-item">
{{ $t('poolFee') }}
<span data-test="label_relayer_fee">{{ toDecimals(poolFee, null, 6) }} {{ currency }}</span>
</div>
<div v-if="withdrawType === 'relayer'" class="withdraw-data-item">
{{ $t('totalFee') }}
<span data-test="label_total_fee">{{ toDecimals(totalRelayerFee, null, 6) }} {{ currency }}</span>
@@ -79,6 +83,16 @@ export default {
...mapGetters('fees', ['gasPriceInGwei']),
...mapGetters('token', ['toDecimals', 'fromDecimals']),
...mapGetters('price', ['tokenRate']),
poolFee() {
const { amount } = this.selectedStatistic
const total = toBN(this.fromDecimals(amount.toString()))
const fee = 0.03
const decimalsPoint = decimalPlaces(fee)
const roundDecimal = 10 ** decimalsPoint
const aroundFee = toBN(parseInt(fee * roundDecimal, 10))
const tornadoServiceFee = total.mul(toBN(aroundFee)).div(toBN(roundDecimal * 100))
return tornadoServiceFee
},
relayerFee() {
const { amount } = this.selectedStatistic
const total = toBN(this.fromDecimals(amount.toString()))
@@ -95,8 +109,13 @@ export default {
const { decimals } = this.networkConfig.tokens[currency]
const ethFee = this.withdrawalNetworkFee
if (currency === this.nativeCurrency) {
if (currency === 'etc') {
const poolServiceFee = this.poolFee
return ethFee.add(poolServiceFee).add(tornadoServiceFee)
} else {
return ethFee.add(tornadoServiceFee)
}
}
const tokenFee = ethFee.mul(toBN(10 ** decimals)).div(toBN(this.tokenRate))
return tokenFee.add(tornadoServiceFee)
},
@@ -119,14 +138,15 @@ export default {
return fromWei(this.ethToReceive)
},
total() {
const { amount } = this.selectedStatistic
const { amount, currency } = this.selectedStatistic
let total = toBN(this.fromDecimals(amount.toString()))
if (this.withdrawType === 'relayer') {
const relayerFee = this.withdrawalFeeViaRelayer
total = total.sub(relayerFee)
const totalRelayerFee = this.withdrawalFeeViaRelayer
total = total.sub(totalRelayerFee)
} else if (currency === 'etc') {
const poolFee = this.poolFee
total = total.sub(poolFee)
}
return this.toDecimals(total, null, 6)
}
}

View File

@@ -56,7 +56,7 @@
"pleaseEnterYourNote": "Please enter your note",
"turnOnWasm": "Error: Please turn on WebAssembly in your browser settings.<br /> If you are using Tor browser, enable javascript.options.wasm in about:config",
"timePassed": "Time passed",
"timePassedTooltip": "Even if multiple deposits were made after yours, they could have been made by the same user. Therefore, we recommend waiting for at least 24 hours before withdrawing funds to ensure that multiple other users transacted via Tornado.сash during that time.",
"timePassedTooltip": "Even if multiple deposits were made after yours, they could have been made by the same user. Therefore, we recommend waiting for at least 24 hours before withdrawing funds to ensure that multiple other users transacted via Tornado Cash during that time.",
"subsequentDeposits": "Subsequent deposits",
"subsequentDepositsTooltip": "The most likely source of a withdrawal points to recent deposits. Therefore, we recommend allowing at least 5 deposits after yours for better anonymity.",
"recipientAddress": "Recipient Address",
@@ -124,6 +124,7 @@
"userDeposit": "no deposits | only 1 deposit | {n} deposits",
"gasPrice": "Gas Price",
"totalFee": "Total fee",
"poolFee": "Pool fee",
"networkFee": "Network fee",
"connectYourWalletFirst": "Connect your wallet first",
"changeNetwork": "Change network",
@@ -137,7 +138,7 @@
"compliance": "Compliance",
"complianceTool": "compliance tool",
"complianceReport": "Compliance Report",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado.сash Note below.",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado Cash Note below.",
"from": "From",
"to": "To",
"withdrawal": "Withdrawal",
@@ -476,5 +477,6 @@
"notification": "Due to the {issue} with eth.link domain, we highly recommend avoiding using this gateway. Consider {alternative} gateways.",
"issue": "issue",
"alternative": "alternative"
}
},
"freezeRisk": "{currency} is a centralized token with the risk of freezing."
}

View File

@@ -124,6 +124,7 @@
"userDeposit": "sin depósitos | solamente 1 depósito | {n} depósitos",
"gasPrice": "Precio de Gas",
"totalFee": "Comisión total",
"poolFee": "tarifa del pool",
"networkFee": "Comisión de red",
"connectYourWalletFirst": "Conecte su monedero primero",
"changeNetwork": "Cambiar red",
@@ -137,7 +138,7 @@
"compliance": "Cumplimiento",
"complianceTool": "herramienta de cumplimiento legal",
"complianceReport": "Informe de cumplimiento legal",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado.сash Note below.",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado Cash Note below.",
"from": "Desde",
"to": "A",
"withdrawal": "Retiro",
@@ -441,5 +442,6 @@
"name": "Name",
"fee": "Fee"
},
"withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded"
"withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded",
"freezeRisk": "{currency} es un token centralizado con riesgo de congelación."
}

View File

@@ -124,6 +124,7 @@
"userDeposit": "aucun dépôt | seulement 1 dépôt | {n} dépôts",
"gasPrice": "Prix du gas",
"totalFee": "Frais total",
"poolFee": "frais de pool",
"networkFee": "Frais de réseau",
"connectYourWalletFirst": "Connecter d'abord votre portefeuille",
"changeNetwork": "Changer de réseau",
@@ -137,7 +138,7 @@
"compliance": "Conformité",
"complianceTool": "outil de conformité",
"complianceReport": "Rapport de Conformité",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado.сash Note below.",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado Cash Note below.",
"from": "De",
"to": "À",
"withdrawal": "Retrait",
@@ -441,5 +442,6 @@
"name": "Name",
"fee": "Fee"
},
"withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded"
"withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded",
"freezeRisk": "{currency} est un jeton centralisé avec un risque de gel."
}

View File

@@ -94,7 +94,7 @@
"generatingProof": "Создание доказательства",
"statistics": "Статистика",
"anonymitySet": "Количество депозитов",
"anonymitySetTooltip": "Общее количество депозитов этой суммы в Tornado.сash. Чем больше это количество, тем лучше (анонимнее)",
"anonymitySetTooltip": "Общее количество депозитов этой суммы в Tornado Cash. Чем больше это количество, тем лучше (анонимнее)",
"latestDeposits": "Последние депозиты",
"yourIP": "Ваш IP {ip}",
"filterBy": "Фильтр по",
@@ -124,6 +124,7 @@
"userDeposit": "депозиты отсутствуют | 1 депозит | {n} депозита | {n} депозитов",
"gasPrice": "Цена Газа",
"totalFee": "Итоговая комиссия",
"poolFee": "лата за пул",
"networkFee": "Комиссия сети",
"connectYourWalletFirst": "Подключите свой кошелек",
"changeNetwork": "Сменить сеть",
@@ -137,7 +138,7 @@
"compliance": "Соответствие",
"complianceTool": "Проверка соответствия",
"complianceReport": "Отчет о соответствии",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado.сash Note below.",
"complianceSubtitle": "Maintaining financial privacy is essential to preserving our freedom.{newline}However, it should not come at the cost of non-compliance. With Tornado Cash, you can always provide cryptographically verified proof of transactional history using the Ethereum address you used to deposit or withdraw funds. This might be necessary to show the source of assets held in your withdrawal address.{newline}To generate a compliance report, please enter your Tornado Cash Note below.",
"from": "Отправитель",
"to": "Получатель",
"withdrawal": "Вывод",
@@ -445,5 +446,6 @@
"name": "Name",
"fee": "Fee"
},
"withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded"
"withdrawalQueueIsOverloaded": "Withdrawal queue is overloaded",
"freezeRisk": "{currency} - это централизованный токен с риском заморозки."
}

View File

@@ -124,6 +124,7 @@
"userDeposit": "Yükleme yok | Sadece bir yükleme | {n} yüklemeler",
"gasPrice": "Gas Ücreti",
"totalFee": "Toplam ücret",
"poolFee": "havuz ücreti",
"networkFee": "Ağ ücreti",
"connectYourWalletFirst": "Önce cüzdanınızı bağlayın",
"changeNetwork": "Ağ değiştir",
@@ -137,7 +138,7 @@
"compliance": "Uyumluluk",
"complianceTool": "uyumluluk aracı",
"complianceReport": "Uyumluluk Raporu",
"complianceSubtitle": "Finansal gizliliği korumak, özgürlüğümüzü korumak için çok önemlidir.{newline}Ancak, uyumsuzluk pahasına olmamalıdır. Tornado Cash ile,para yatırmak veya para çekmek için kullandığınız Ethereum adresini kullanarak her zaman kriptografik olarak doğrulanmış işlem geçmişi kanıtını sağlayabilirsiniz. Çekim adresinizde tutulan varlıkların kaynağını göstermek için gerekli olabilir.{newline}Bir uygunluk raporu oluşturmak için lütfen aşağıya Tornado.сash Notunuzu girin.",
"complianceSubtitle": "Finansal gizliliği korumak, özgürlüğümüzü korumak için çok önemlidir.{newline}Ancak, uyumsuzluk pahasına olmamalıdır. Tornado Cash ile,para yatırmak veya para çekmek için kullandığınız Ethereum adresini kullanarak her zaman kriptografik olarak doğrulanmış işlem geçmişi kanıtını sağlayabilirsiniz. Çekim adresinizde tutulan varlıkların kaynağını göstermek için gerekli olabilir.{newline}Bir uygunluk raporu oluşturmak için lütfen aşağıya Tornado Cash Notunuzu girin.",
"from": "Kimden",
"to": "Kime",
"withdrawal": "Çekim",
@@ -441,5 +442,6 @@
"name": "İsim",
"fee": "Ücret"
},
"withdrawalQueueIsOverloaded": "Çekim kuyruğu aşırı yoğun"
"withdrawalQueueIsOverloaded": "Çekim kuyruğu aşırı yoğun",
"freezeRisk": "{currency} merkezileştirilmiş bir token olup dondurulma riski taşır."
}

View File

@@ -123,6 +123,7 @@
"userDeposit": "депозити відсутні | тільки 1 депозит | {n} депозиту | {n} депозитів",
"gasPrice": "Ціна Газу",
"totalFee": "Підсумкова комісія",
"poolFee": "лата за пул",
"networkFee": "Комісія мережі",
"connectYourWalletFirst": "Підключіть свій гаманець",
"changeNetwork": "Змінити мережу",
@@ -424,5 +425,6 @@
"disabled": "Мобільні гаманці не підтримують цю функцію в даний момент."
}
},
"dayPlural": "0 днів | {n} день | {n} дні | {n} днів"
"dayPlural": "0 днів | {n} день | {n} дні | {n} днів",
"freezeRisk": "{currency} - це централізований токен із ризиком заморожування."
}

View File

@@ -124,6 +124,7 @@
"userDeposit": "无存款 | 只有 1 笔存款 | {n} 笔存款",
"gasPrice": "Gas 价格",
"totalFee": "总费用",
"poolFee": "池费用",
"networkFee": "网络费",
"connectYourWalletFirst": "首先连接你的钱包",
"changeNetwork": "切换网络",
@@ -137,7 +138,7 @@
"compliance": "来源证明",
"complianceTool": "来源证明工具",
"complianceReport": "来源证明报告",
"complianceSubtitle": "维护财务隐私对于保全我们的自由至关重要。{newline}但是,它不应该以违规为代价。 借助Tornado Cash您始终可以使用您存/取款的地址提供经过加密验证的交易历史证明。 这将会显示您的提款地址的资产来源。{newline}要生成资产来源报告,请在下面输入您的 Tornado.сash存款凭证。",
"complianceSubtitle": "维护财务隐私对于保全我们的自由至关重要。{newline}但是,它不应该以违规为代价。 借助Tornado Cash您始终可以使用您存/取款的地址提供经过加密验证的交易历史证明。 这将会显示您的提款地址的资产来源。{newline}要生成资产来源报告请在下面输入您的Tornado Cash存款凭证。",
"from": "从",
"to": "到",
"withdrawal": "提款",
@@ -445,5 +446,6 @@
"name": "名",
"fee": "费用"
},
"withdrawalQueueIsOverloaded": "提款队列已超载"
"withdrawalQueueIsOverloaded": "提款队列已超载",
"freezeRisk": "{currency}是中心化代币,存在冻结风险。"
}

View File

@@ -1,5 +1,5 @@
export const blockSyncInterval = 10000
export const enabledChains = ['1', '10', '56', '100', '137', '42161', '43114', '11155111']
export const enabledChains = ['1', '10', '56', '61', '100', '137', '42161', '43114', '11155111']
export default {
netId1: {
rpcCallRetryAttempt: 15,
@@ -21,29 +21,29 @@ export default {
networkName: 'Ethereum Mainnet',
deployedBlock: 9116966,
rpcUrls: {
mevblockerRPC: {
name: 'mevblockerRPC',
url: 'https://rpc.mevblocker.io'
},
poktRPC: {
name: 'poktRPC',
url: 'https://eth-pokt.nodies.app'
},
secureRPC: {
name: 'secureRPC',
url: 'https://api.securerpc.com/v1'
},
flashbotRPC: {
name: 'flashbotRPC',
url: 'https://rpc.flashbots.net'
},
blockpiRPC: {
name: 'blockpiRPC',
url: 'https://ethereum.blockpi.network/v1/rpc/public'
tornadoRPC: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/mainnet'
},
publicRPC: {
name: 'publicRPC',
url: 'https://ethereum-rpc.publicnode.com'
blockscoutRPC: {
name: 'blockscoutRPC',
url: 'https://eth.blockscout.com/api/eth-rpc'
},
kyberRPC: {
name: 'kyberRPC',
url: 'https://ethereum-mev-protection.kyberengineering.io'
},
gasHawkRPC: {
name: 'GasHawkRPC',
url: 'https://core.gashawk.io/rpc'
},
lavaRPC: {
name: 'lavaRPC',
url: 'https://eth1.lava.build'
}
},
multicall: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
@@ -159,6 +159,10 @@ export default {
name: 'bnbRPC',
url: 'https://bsc-dataseed.bnbchain.org'
},
tornadoRPC: {
name: 'Tornado RPC',
url: 'https://tornadocash-rpc.com/bsc'
},
defibitRPC: {
name: 'defibitRPC',
url: 'https://bsc-dataseed1.defibit.io'
@@ -196,6 +200,72 @@ export default {
},
'tornado-proxy-light.contract.tornadocash.eth': '0x0D5550d52428E7e3175bfc9550207e4ad3859b17'
},
netId61: {
rpcCallRetryAttempt: 15,
gasPrices: {
instant: 1,
fast: 1,
standard: 1,
low: 1
},
nativeCurrency: 'etc',
currencyName: 'ETC',
explorerUrl: {
tx: 'https://etc.blockscout.com/tx/',
address: 'https://etc.blockscout.com/address/',
block: 'https://etc.blockscout.com/block/'
},
merkleTreeHeight: 20,
emptyElement: '21663839004416932945382355908790599225266501822907911457504978515578255421292',
networkName: 'Ethereum Classic',
deployedBlock: 22385618,
multicall: '0xA52EE88C0F24EF8b96C3989cAb42cfC6008041A8',
echoContractAccount: '0x6e824e64C2B30Eb542b9917AA2FbEA593daEA5D6',
rpcUrls: {
rivet: {
name: 'rivet',
url: 'https://etc.rivet.link'
},
etcdesktop: {
name: 'etcdesktop',
url: 'https://etc.etcdesktop.com'
},
mytokenpocket: {
name: 'mytokenpocket',
url: 'https://etc.mytokenpocket.vip'
},
xrpc: {
name: '0xrpc',
url: 'https://0xrpc.io/etc'
},
geth: {
name: 'geth',
url: 'https://geth-at.etc-network.info'
},
besu: {
name: 'besu',
url: 'https://besu-at.etc-network.info'
}
},
tokens: {
etc: {
instanceAddress: {
'1': '0x2f56d5aFC058B8734350B162EFEe75ee48f034e0',
'10': '0x59fCB629A23e8eD0a60A0188771E221042260118',
'100': '0x784B3a7a7981B959bd8d9D9e73c2013BE819Fbf2'
},
symbol: 'ETC',
decimals: 18
}
},
ensSubdomainKey: 'etc-tornado',
pollInterval: 10,
constants: {
NOTE_ACCOUNT_BLOCK: 22385618,
ENCRYPTED_NOTES_BLOCK: 22385618
},
'tornado-proxy-light.contract.tornadocash.eth': '0xac97AB4fBd872ea762974CbBB0Ee72351afe16F3'
},
netId137: {
rpcCallRetryAttempt: 15,
gasPrices: {

View File

@@ -114,11 +114,16 @@
<div class="block block-withdrawal">
<h3 class="block-item block-item--title">
{{ $t('withdrawal') }}
<span>{{
<span v-if="txDepositInfo.currency !== 'etc'">{{
txWithdrawalInfo.amount
? `${$n(txWithdrawalInfo.amount)} ${getSymbol(txDepositInfo.currency)}`
: '-'
}}</span>
<span v-if="txDepositInfo.currency === 'etc'">{{
txWithdrawalInfo.amount
? `${$n(txWithdrawalInfo.amount * 0.997)} ${getSymbol(txDepositInfo.currency)}`
: '-'
}}</span>
</h3>
<div
class="block-item block-item--status"
@@ -135,7 +140,14 @@
: $t('status')
: $t('noteHasNotBeenSpent')
}}
<span class="fee">{{
<span v-if="txDepositInfo.currency === 'etc'" class="fee">{{
txWithdrawalInfo.fee
? `${$t('poolFee')} ${$n(txWithdrawalInfo.amount * 0.003)}
${getSymbol(txDepositInfo.currency)},
${$t('relayerFee')} ${$n(txWithdrawalInfo.fee)} ${getSymbol(txDepositInfo.currency)}`
: $t('relayerFee')
}}</span>
<span v-if="txDepositInfo.currency !== 'etc'" class="fee">{{
txWithdrawalInfo.fee
? `${$t('relayerFee')} ${$n(txWithdrawalInfo.fee)} ${getSymbol(txDepositInfo.currency)}`
: $t('relayerFee')

View File

@@ -9,12 +9,11 @@ function main() {
const IPFS_LOCAL_REGEXP = /.ipfs.localhost:/
const IPFS_SOP_GATEWAY_REGEXP = /\/ipfs\//
if (IPFS_LOCAL_REGEXP.test(window.location.host)) {
if (IPFS_LOCAL_REGEXP.test(window.location.host) || whiteListedDomains.includes(window.location.host)) {
return false
} else if (
IPFS_GATEWAY_REGEXP.test(window.location.host) ||
IPFS_SOP_GATEWAY_REGEXP.test(window.location.host) ||
whiteListedDomains.includes(window.location.host)
IPFS_SOP_GATEWAY_REGEXP.test(window.location.host)
) {
console.warn('The page has been loaded from ipfs.io. LocalStorage is disabled')
return true

View File

@@ -47,6 +47,7 @@ const CHAIN_GRAPH_URLS = {
1: 'https://gateway.thegraph.com/api/{apiKey}/subgraphs/id/Ec6fVMDVqXTDQZ3c4jxcyV3zBXqkdgMWfhdtCgtqn7Sh',
10: 'https://gateway.thegraph.com/api/{apiKey}/subgraphs/id/GvkbnEVhLD6KArXpEzLFtSKRmspBW29ApKFqR5FjuP2P',
56: 'https://gateway.thegraph.com/api/{apiKey}/subgraphs/id/CiwGzefDBZCavXRPnwarnnF8xDDoLw4boBuySomJWYnV',
61: 'https://graph.torndao.com/subgraphs/name/tornadocash/etc-tornado-subgraph',
100: 'https://gateway.thegraph.com/api/{apiKey}/subgraphs/id/F1m8vxuGatCBRvP8fPnnWUJ1oK7kfE1DGdRacqoamLjF',
137: 'https://gateway.thegraph.com/api/{apiKey}/subgraphs/id/HUMgwMYNrPQpnBJgesFXyy5u6jSiJ6u5nNWQng9ayCmD',
42161: 'https://gateway.thegraph.com/api/{apiKey}/subgraphs/id/8x8o6XFAqYZmiPwrJ51UxGTaZLYyW1fFtghvsEy7a1KJ',

View File

@@ -133,11 +133,9 @@ class RelayerRegister {
}
getCachedData = async () => {
let blockFrom = REGISTRY_DEPLOYED_BLOCK[1]
const blockFrom = REGISTRY_DEPLOYED_BLOCK[1]
try {
const blockTo = await this.provider.getBlockNumber()
const cachedEvents = await this.$indexedDB.getAll({
storeName: 'register_events'
})
@@ -148,8 +146,9 @@ class RelayerRegister {
storeName: 'lastEvents'
})
let blockTo = blockFrom
if (lastBlock) {
blockFrom = blockTo >= lastBlock.blockNumber ? lastBlock.blockNumber + 1 : blockTo
blockTo = lastBlock.blockNumber + 1
}
return { blockFrom, blockTo, cachedEvents }
@@ -171,9 +170,12 @@ class RelayerRegister {
const blockRange = 10000
// eslint-disable-next-line prefer-const
let { blockFrom, blockTo, cachedEvents } = await this.getCachedData()
let allRelayers = cachedEvents
if (!cachedEvents || !cachedEvents.length) {
let firstFetch = false
// There are 114 relayers in total so far,
// If there are less than 114 in the cache,
// It means that the historical data is incorrect and needs to be re-fetch through the subgraph
if (!cachedEvents || !cachedEvents.length || cachedEvents.length < 114) {
firstFetch = true // Get all relayers from the subgraph for the first time
const { lastSyncBlock, events } = await graph.getAllRegisters(blockFrom)
if (events.length) {
@@ -184,6 +186,7 @@ class RelayerRegister {
}))
}
}
let allRelayers = cachedEvents
const currentBlockNumber = await this.provider.getBlockNumber()
const fromBlock = cachedEvents.length === 0 ? REGISTRY_DEPLOYED_BLOCK[1] : blockTo
@@ -191,9 +194,10 @@ class RelayerRegister {
try {
let toBlock
let registerRelayerEvents
let registerRelayerEvents = cachedEvents
let lastSyncBlock = blockTo
if (!firstFetch) {
if (blockDifference <= 0) {
return cachedEvents
} else if (blockDifference >= blockRange) {
@@ -201,16 +205,16 @@ class RelayerRegister {
registerRelayerEvents = await this.batchFetchEvents({ fromBlock, toBlock })
lastSyncBlock = toBlock
} else {
toBlock = fromBlock + blockRange
toBlock = currentBlockNumber // Fix toBlock greater than the latest blocknumber
registerRelayerEvents = await this.fetchEvents({ fromBlock, toBlock }, true)
lastSyncBlock = toBlock
}
}
const relayerEvents = cachedEvents.concat(registerRelayerEvents || [])
const events = []
for (let x = 0; x < relayerEvents.length; x++) {
const { ensName, relayerAddress } = relayerEvents[x]
for (let x = 0; x < registerRelayerEvents.length; x++) {
const { ensName, relayerAddress } = registerRelayerEvents[x]
let ensAddress
if (!isAddress(relayerAddress)) {
@@ -223,9 +227,12 @@ class RelayerRegister {
events.push({ ensName, relayerAddress: ensAddress })
}
await this.saveEvents({ storeName: 'register_events', lastSyncBlock, events })
if (firstFetch) {
allRelayers = events
} else {
allRelayers = allRelayers.concat(events)
}
await this.saveEvents({ storeName: 'register_events', lastSyncBlock, events: allRelayers })
} catch (err) {
console.log(err)
}

View File

@@ -21,6 +21,8 @@ function getRelayerValidateFunction(netId) {
switch (netId) {
case 56:
return ajv.getSchema('bscRelayer')
case 61:
return ajv.getSchema('etcRelayer')
case 100:
return ajv.getSchema('xdaiRelayer')
case 137:

View File

@@ -0,0 +1,44 @@
import { addressType } from '@/constants'
const statusSchema = {
type: 'object',
properties: {
rewardAccount: addressType,
instances: {
type: 'object',
properties: {
etc: {
type: 'object',
properties: {
instanceAddress: {
type: 'object',
properties: {
'1': addressType,
'10': addressType,
'100': addressType
},
required: ['1', '10', '100']
},
decimals: { enum: [18] }
},
required: ['instanceAddress', 'decimals']
}
},
required: ['etc']
},
netId: { type: 'integer' },
tornadoServiceFee: { type: 'number', maximum: 20, minimum: 0 },
health: {
type: 'object',
properties: {
status: { const: 'true' },
error: { type: 'string' }
},
required: ['status']
},
currentQueue: { type: 'number' }
},
required: ['rewardAccount', 'instances', 'netId', 'tornadoServiceFee', 'health']
}
export { statusSchema }

View File

@@ -1,5 +1,6 @@
import { statusSchema as l2Relayer } from './l2'
import { statusSchema as bscRelayer } from './bsc'
import { statusSchema as etcRelayer } from './etc'
import { statusSchema as xdaiRelayer } from './xdai'
import { statusSchema as defaultRelayer } from './default'
import { statusSchema as polygonRelayer } from './polygon'
@@ -8,6 +9,7 @@ import { statusSchema as avalancheRelayer } from './avalanche'
export default {
l2Relayer,
bscRelayer,
etcRelayer,
xdaiRelayer,
defaultRelayer,
polygonRelayer,

View File

@@ -292,7 +292,15 @@ export const actions = {
}
let statuses = await Promise.all(requests)
statuses = statuses.filter((status) => status.isValid)
// Filter out invalid and duplicate relayers
statuses = Object.values(
statuses
.filter((item) => item.isValid)
.reduce((statuses, item) => {
statuses[item.name] = item // Filter duplicates by relayer's ENS
return statuses
}, {})
).sort((a, b) => new BN(b.stakeBalance).comparedTo(new BN(a.stakeBalance))) // sort by relayer's stakeBalance
// const validRelayerENSnames = statuses.map((relayer) => relayer.name)
commit('SAVE_VALIDATED_RELAYERS', statuses)
console.log('filtered statuses ', statuses)