This commit is contained in:
Danil Kovtonyuk 2021-10-25 19:12:11 +10:00
parent 201267a0ae
commit 71bfdfbfec
No known key found for this signature in database
GPG Key ID: E72A919BF08C3746
14 changed files with 323 additions and 175 deletions

View File

@ -95,3 +95,15 @@
background-color: #2a2a2a; background-color: #2a2a2a;
} }
} }
fieldset[disabled] {
.button {
&.is-primary {
&.is-outlined {
.trnd {
background-color: #44f1a6;
}
}
}
}
}

View File

@ -11,7 +11,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
border-radius: 6px; border-radius: 6px;
background: #1F1F1F; background: #1f1f1f;
@include mobile { @include mobile {
flex-wrap: wrap; flex-wrap: wrap;
@ -22,7 +22,6 @@
margin-top: 0; margin-top: 0;
} }
.diamond { .diamond {
margin: 1.25rem 0 1.25rem 1.25rem; margin: 1.25rem 0 1.25rem 1.25rem;
@ -53,13 +52,13 @@
} }
+ .deployed { + .deployed {
margin-top: .25rem; margin-top: 0.25rem;
} }
} }
.deployed { .deployed {
font-size: 0.813rem; font-size: 0.813rem;
color: #6B6B6B; color: #6b6b6b;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
@ -73,17 +72,19 @@
flex: none; flex: none;
width: 100%; width: 100%;
text-align: center; text-align: center;
padding: .75rem 1.25rem; padding: 0.75rem 1.25rem;
} }
.button { .button,
fieldset[disabled] & .button {
padding: 0; padding: 0;
background-color: transparent; background-color: transparent;
border: 0; border: 0;
color: $primary; color: $primary;
font-size: 0.875rem; font-size: 0.875rem;
&:focus:not(:active), &.is-focused:not(:active) { &:focus:not(:active),
&.is-focused:not(:active) {
box-shadow: none; box-shadow: none;
} }
} }

View File

@ -12,7 +12,6 @@ import { mapState } from 'vuex'
export default { export default {
computed: { computed: {
...mapState('loading', ['enabled', 'message', 'txHash']), ...mapState('loading', ['enabled', 'message', 'txHash']),
...mapState('getNetwork', ['getProviderName']),
}, },
} }
</script> </script>

View File

@ -6,12 +6,7 @@
</b-navbar-item> </b-navbar-item>
</template> </template>
<template slot="start"> <template slot="start">
<b-navbar-item <b-navbar-item href="#" target="_blank" class="decorate" rel="noreferrer">
href="https://medium.com/@tornado-cash/tornado-cash-deployment-proposal-on-xdai-216903df898c"
target="_blank"
class="decorate"
rel="noreferrer"
>
{{ $t('info') }} {{ $t('info') }}
</b-navbar-item> </b-navbar-item>
</template> </template>

View File

@ -1,10 +1,7 @@
<template> <template>
<div :id="data.isActive ? 'current' : ''" class="step"> <div :id="data.isActive ? 'current' : ''" class="step">
<div class="step-container"> <div class="step-container">
<diamond <diamond :active="!!data.deployerAddress" :waiting="isDeployed" />
:active="!!data.deployerAddress"
:waiting="!canDeploy(data.domain)"
/>
<div class="step-body"> <div class="step-body">
<h4>{{ data.title }}</h4> <h4>{{ data.title }}</h4>
<h5 v-if="data.domain" class="deployed"> <h5 v-if="data.domain" class="deployed">
@ -44,22 +41,20 @@
:label=" :label="
isNotLoggedIn isNotLoggedIn
? $t('pleaseConnectWallet') ? $t('pleaseConnectWallet')
: !canDeploy(data.domain) : isDeployed
? $t('dependsOnEns', { ens: data.dependsOn.join(', ') }) ? $t('dependsOnEns', { ens: data.dependsOn.join(', ') })
: '' : ''
" "
position="is-top" position="is-top"
multilined multilined
:size="isNotLoggedIn ? 'is-small' : 'is-large'" :size="isNotLoggedIn ? 'is-small' : 'is-large'"
:active="isNotLoggedIn || !canDeploy(data.domain)" :active="isNotLoggedIn || isDeployed"
> >
<b-button <b-button
type="is-primary" type="is-primary"
outlined outlined
icon-left="tool" icon-left="tool"
:disabled=" :disabled="isNotLoggedIn || isDeployed || data.isPending"
isNotLoggedIn || !canDeploy(data.domain) || data.isPending
"
@mousedown="(e) => e.preventDefault()" @mousedown="(e) => e.preventDefault()"
@click="onDeploy" @click="onDeploy"
> >
@ -118,6 +113,9 @@ export default {
...mapGetters('provider', ['getProviderName', 'getAccount']), ...mapGetters('provider', ['getProviderName', 'getAccount']),
...mapGetters('steps', ['canDeploy']), ...mapGetters('steps', ['canDeploy']),
...mapGetters('txStorage', ['txExplorerUrl', 'addressExplorerUrl']), ...mapGetters('txStorage', ['txExplorerUrl', 'addressExplorerUrl']),
isDeployed() {
return !this.canDeploy(this.data.domain, this.data.isL1Contract)
},
isNotLoggedIn() { isNotLoggedIn() {
return !this.getProviderName return !this.getProviderName
}, },
@ -125,7 +123,11 @@ export default {
methods: { methods: {
...mapActions('deploy', ['deployContract']), ...mapActions('deploy', ['deployContract']),
onDeploy() { onDeploy() {
this.deployContract({ action: this.data, index: this.$vnode.key }) this.deployContract({
action: this.data,
index: this.$vnode.key,
isL1: this.data.isL1Contract,
})
}, },
}, },
} }

View File

@ -1,39 +1,110 @@
<template> <template>
<div class="steps"> <div class="steps--container">
<step v-for="(step, index) in getData" :key="index" :data="step" /> <div v-for="layer in ['L1', 'L2']" :key="`${layer}-steps`" class="steps">
<h4 class="title is-3 has-text-centered">
{{ $t(layer.toLowerCase()) }} deployment
</h4>
<div class="steps-wrapper">
<div v-if="isLoggedIn && isDisabledSteps(layer)" class="switch-network">
<p>{{ $t(`switchTo${layer}`) }}</p>
<b-button type="is-primary" @click="changeNetwork(layer)">{{
$t(`switchNetworkTo${layer}`)
}}</b-button>
</div>
<fieldset
class="fieldset"
:disabled="isLoggedIn && isDisabledSteps(layer)"
>
<step
v-for="(step, index) in getSteps(layer)"
:key="index"
:data="step"
/>
</fieldset>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import Step from '@/components/Step' import Step from '@/components/Step'
import { mapState } from 'vuex' import { mapState, mapGetters, mapActions } from 'vuex'
export default { export default {
components: { components: {
Step, Step,
}, },
computed: { computed: {
...mapState('steps', ['steps']), ...mapState('steps', ['l1Steps', 'l2Steps']),
...mapState('airdrop', ['airdrops', 'notificationIndex']), ...mapGetters('provider', ['getNetwork', 'getProviderName']),
getData() { isLoggedIn() {
if (Array.isArray(this.airdrops)) { return !!this.getProviderName
return this.steps.map((step, index) => { },
if (step.contract === 'Airdrop.sol') { },
const dropIndex = index - this.airdrops.length + 2 methods: {
...mapActions('provider', ['switchNetwork']),
return { isDisabledSteps(layer) {
...step, const { isL1 } = this.getNetwork
airdrops: this.airdrops[dropIndex], return isL1 ? layer === 'L2' : layer === 'L1'
isActive: this.notificationIndex === dropIndex, },
} getSteps(layer) {
} return layer === 'L1' ? this.l1Steps : this.l2Steps
},
return step changeNetwork(layer) {
}) const netId = layer === 'L1' ? 1 : 100
} this.switchNetwork({ netId })
return this.steps
}, },
}, },
} }
</script> </script>
<style scoped lang="scss">
.switch-network {
display: block;
padding: 1rem 2rem;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 400;
box-shadow: 0 1px 2px 1px rgba(0, 1, 0, 0.2);
z-index: 888;
background-color: #393939;
color: #eee;
align-items: center;
position: sticky;
top: 1.25rem;
bottom: 1.25rem;
z-index: 1;
margin: 0 auto;
margin-bottom: 1.25rem;
max-width: 320px;
text-align: center;
.button {
margin-top: 1.25rem;
}
@media (min-width: 769px) {
display: flex;
max-width: 560px;
text-align: left;
.button {
margin-top: 0;
margin-left: 1.25rem;
}
}
}
.fieldset[disabled] {
cursor: not-allowed;
position: relative;
filter: grayscale(70%);
color: #5e5e5e;
::v-deep .tooltip-content {
display: none !important;
}
}
</style>

View File

@ -16,8 +16,10 @@
"deploy": "Deploy", "deploy": "Deploy",
"deployedBy": "Deployed by: {link}", "deployedBy": "Deployed by: {link}",
"startNow": "Start now", "startNow": "Start now",
"completedTasks": "Completed Tasks: {progress}", "l1": "Layer 1",
"pageSubtitle": "Follow these simple steps to become part of deployment of Tornado.Cash protocol on xDAI Chain.", "l2": "Layer 2",
"completedTasks": "Completed {layer} Tasks: {progress}",
"pageSubtitle": "Follow these simple steps to become part of deployment of Tornado.Cash Pool protocol.",
"alreadyDeployed": "Already deployed", "alreadyDeployed": "Already deployed",
"contractDeployed": "Contract successfully deployed", "contractDeployed": "Contract successfully deployed",
"transactionFailed": "Transaction was failed", "transactionFailed": "Transaction was failed",
@ -26,6 +28,8 @@
"viewOnEtherscan": "View on Etherscan", "viewOnEtherscan": "View on Etherscan",
"pleaseConnectWallet": "Please connect your wallet first", "pleaseConnectWallet": "Please connect your wallet first",
"dependsOnEns": "This action depends on {ens}", "dependsOnEns": "This action depends on {ens}",
"xDaiOnly": "Please switch your wallet to xDAI Chain", "switchToL1": "Please switch your wallet to Ethereum Mainnet for L1 deployment.",
"switchNetwork": "Switch to xDAI" "switchToL2": "Please switch your wallet to xDAI Chain for L2 deployment.",
"switchNetworkToL1": "Switch to Mainnet",
"switchNetworkToL2": "Switch to xDAI"
} }

View File

@ -1,4 +1,24 @@
const networkConfig = { const networkConfig = {
netId1: {
rpcCallRetryAttempt: 15,
gasPrices: { instant: 80, fast: 50, standard: 25, low: 8 },
currencyName: 'ETH',
explorerUrl: {
tx: 'https://etherscan.io/tx/',
address: 'https://etherscan.io/address/',
},
networkName: 'Mainnet',
rpcUrls: {
Infura: {
name: 'Infura',
url: 'https://mainnet.infura.io/v3/2884a3281c1d4ae8952e25c84d76bced',
},
MyCrypto: { name: 'MyCrypto', url: 'https://api.mycryptoapi.com/eth' },
},
pollInterval: 60,
isL1: true,
},
netId100: { netId100: {
rpcCallRetryAttempt: 15, rpcCallRetryAttempt: 15,
gasPrices: { gasPrices: {
@ -20,6 +40,7 @@ const networkConfig = {
}, },
}, },
pollInterval: 200, pollInterval: 200,
isL1: false,
}, },
} }

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<h1 class="title has-text-centered"> <h1 class="title has-text-centered">
Tornado.cash <span>xDAI</span> Deployment Tornado.cash <span>Pool</span> Deployment
</h1> </h1>
<h2 class="subtitle has-text-centered">{{ $t('pageSubtitle') }}</h2> <h2 class="subtitle has-text-centered">{{ $t('pageSubtitle') }}</h2>
@ -17,11 +17,11 @@
</div> </div>
<i18n tag="h3" class="title is-14px mt-6" path="completedTasks"> <i18n tag="h3" class="title is-14px mt-6" path="completedTasks">
<template v-slot:layer>{{ $t(getNetwork.isL1 ? 'l1' : 'l2') }}</template>
<template v-slot:progress> <template v-slot:progress>
<span>{{ deployedCount }}</span> <span>{{ getNetwork.isL1 ? deployedL1Count : deployedL2Count }}</span>
</template> </template>
</i18n> </i18n>
<div class="tornado-discoverer image is-16by9"></div> <div class="tornado-discoverer image is-16by9"></div>
<steps ref="steps" /> <steps ref="steps" />
@ -37,7 +37,8 @@ export default {
Steps, Steps,
}, },
computed: { computed: {
...mapGetters('steps', ['deployedCount']), ...mapGetters('steps', ['deployedL1Count', 'deployedL2Count']),
...mapGetters('provider', ['getNetwork']),
}, },
methods: { methods: {
scrollTo(element) { scrollTo(element) {

File diff suppressed because one or more lines are too long

View File

@ -25,7 +25,7 @@ const mutations = {}
const actions = { const actions = {
async deployContract( async deployContract(
{ state, dispatch, getters, rootGetters, commit, rootState }, { state, dispatch, getters, rootGetters, commit, rootState },
{ action, index } { action, index, isL1 }
) { ) {
try { try {
dispatch('loading/enable', {}, { root: true }) dispatch('loading/enable', {}, { root: true })
@ -69,12 +69,17 @@ const actions = {
], ],
from: ethAccount, from: ethAccount,
} }
const gasEstimate =
action.domain === 'deployer.contract.tornadocash.eth' const deployerContracts = [
? numberToHex(1e6) 'deployerL1.contract.tornadocash.eth',
: await dispatch('provider/sendRequest', callParamsEstimate, { 'deployerL2.contract.tornadocash.eth',
root: true, ]
})
const gasEstimate = deployerContracts.includes(action.domain)
? numberToHex(1e6)
: await dispatch('provider/sendRequest', callParamsEstimate, {
root: true,
})
const gasWithBuffer = Math.ceil(hexToNumber(gasEstimate) * 1.1) const gasWithBuffer = Math.ceil(hexToNumber(gasEstimate) * 1.1)
const callParams = { const callParams = {
method: 'eth_sendTransaction', method: 'eth_sendTransaction',
@ -106,7 +111,7 @@ const actions = {
dispatch('loading/disable', {}, { root: true }) dispatch('loading/disable', {}, { root: true })
dispatch( dispatch(
'steps/setPendingState', 'steps/setPendingState',
{ status: true, stepIndex: index }, { status: true, stepIndex: index, isL1 },
{ root: true } { root: true }
) )
@ -172,7 +177,7 @@ const actions = {
dispatch('loading/disable', {}, { root: true }) dispatch('loading/disable', {}, { root: true })
dispatch( dispatch(
'steps/setPendingState', 'steps/setPendingState',
{ status: false, stepIndex: index }, { status: false, stepIndex: index, isL1 },
{ root: true } { root: true }
) )
} }

View File

@ -14,20 +14,33 @@ export default {
async initProvider({ commit, state, getters, dispatch }, { name, network }) { async initProvider({ commit, state, getters, dispatch }, { name, network }) {
try { try {
const account = await this.$provider.initProvider(getters.getProvider) const account = await this.$provider.initProvider(getters.getProvider)
if (window.ethereum.chainId !== '0x64') { const supportedNetworks = [numberToHex(1), numberToHex(100)]
if (!supportedNetworks.includes(window.ethereum.chainId)) {
await dispatch( await dispatch(
'notice/addNotice', 'notice/addNotice',
{ {
notice: { notice: {
title: 'xDaiOnly', title: 'switchToL1',
type: 'danger', type: 'danger',
callback: () => dispatch('switchNetwork', { netId: 100 }), callback: () => dispatch('switchNetwork', { netId: 1 }),
message: 'switchNetwork', message: 'switchNetworkToL1',
}, },
}, },
{ root: true } { root: true }
) )
throw new Error('Connect to xDai') await dispatch(
'notice/addNotice',
{
notice: {
title: 'switchToL2',
type: 'danger',
callback: () => dispatch('switchNetwork', { netId: 100 }),
message: 'switchNetworkToL2',
},
},
{ root: true }
)
throw new Error('Connect to L1 or L2')
} }
commit(SET_PROVIDER_NAME, name) commit(SET_PROVIDER_NAME, name)

View File

@ -1,8 +1,8 @@
export default () => ({ export default () => ({
account: null, account: null,
network: { network: {
name: 'xdai', name: 'mainnet',
id: 100, id: 1,
}, },
provider: { provider: {
name: '', name: '',

View File

@ -1,44 +1,76 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import deploymentActions from '../static/deploymentActions.json' import deploymentActions from '../static/deploymentActions.json'
const l1Steps = deploymentActions.actions.filter(
({ isL1Contract }) => isL1Contract
)
const l2Steps = deploymentActions.actions.filter(
({ isL1Contract }) => !isL1Contract
)
const state = () => { const state = () => {
return { return {
steps: deploymentActions.actions, l1Steps,
l2Steps,
} }
} }
const getters = { const getters = {
deployedCount: (state) => { deployedL1Count: (state, getters) => {
const deployed = state.steps.filter((step) => !!step.deployerAddress).length return getters.deployedCount(true)
const all = state.steps.length },
deployedL2Count: (state, getters) => {
return getters.deployedCount(false)
},
steps: (state) => (isL1) => {
return isL1 ? state.l1Steps : state.l2Steps
},
deployedCount: (state, getters) => (isL1) => {
const steps = getters.steps(isL1)
const deployed = steps.filter((step) => !!step.deployerAddress).length
const all = steps.length
return `${deployed}/${all}` return `${deployed}/${all}`
}, },
canDeploy: (state) => (domain) => { canDeploy: (state, getters) => (domain, isL1) => {
const { dependsOn } = state.steps.find((s) => s.domain === domain) const steps = getters.steps(isL1)
return dependsOn.every( const { dependsOn } = steps.find((s) => s.domain === domain)
(d) => !!state.steps.find((s) => s.domain === d).deployerAddress return dependsOn.every((d) => {
) return Boolean(steps.find((s) => s.domain === d)?.deployerAddress)
})
}, },
} }
const SET_DEPLOYER = 'SET_DEPLOYER' const SET_DEPLOYER = 'SET_DEPLOYER'
const SET_PENDING_STATE = 'SET_PENDING_STATE' const SET_PENDING_STATE = 'SET_PENDING_STATE'
const mutations = { const mutations = {
[SET_DEPLOYER](state, { stepIndex, deployerAddress, deployTransaction }) { [SET_DEPLOYER](
this._vm.$set(state.steps[stepIndex], 'deployerAddress', deployerAddress) state,
{ stepIndex, deployerAddress, deployTransaction, isL1 }
) {
const steps = isL1 ? 'l1Steps' : 'l2Steps'
this._vm.$set(state[steps][stepIndex], 'deployerAddress', deployerAddress)
this._vm.$set( this._vm.$set(
state.steps[stepIndex], state[steps][stepIndex],
'deployTransaction', 'deployTransaction',
deployTransaction deployTransaction
) )
}, },
[SET_PENDING_STATE](state, { status, stepIndex }) { [SET_PENDING_STATE](state, { status, stepIndex, isL1 }) {
this._vm.$set(state.steps[stepIndex], 'isPending', status) const steps = isL1 ? 'l1Steps' : 'l2Steps'
this._vm.$set(state[steps][stepIndex], 'isPending', status)
}, },
} }
const actions = { const actions = {
async fetchDeploymentStatus({ state, dispatch, commit, rootGetters }) { async fetchDeploymentStatus({
state,
getters,
dispatch,
commit,
rootGetters,
}) {
const { isL1 } = rootGetters['provider/getNetwork']
const steps = getters.steps(isL1)
const deployContract = rootGetters['deploy/deployerContract'](false) const deployContract = rootGetters['deploy/deployerContract'](false)
const events = await deployContract.getPastEvents('Deployed', { const events = await deployContract.getPastEvents('Deployed', {
fromBlock: 0, fromBlock: 0,
@ -46,7 +78,7 @@ const actions = {
}) })
for (const event of events) { for (const event of events) {
const step = state.steps.find( const step = steps.find(
(s) => s.expectedAddress === event.returnValues.addr (s) => s.expectedAddress === event.returnValues.addr
) )
@ -54,9 +86,10 @@ const actions = {
continue continue
} }
commit(SET_DEPLOYER, { commit(SET_DEPLOYER, {
stepIndex: state.steps.indexOf(step), stepIndex: steps.indexOf(step),
deployerAddress: event.returnValues.sender, deployerAddress: event.returnValues.sender,
deployTransaction: event.transactionHash, deployTransaction: event.transactionHash,
isL1,
}) })
} }
}, },
@ -70,8 +103,8 @@ const actions = {
} }
}, 15000) }, 15000)
}, },
setPendingState({ commit }, { status, stepIndex }) { setPendingState({ commit }, payload) {
commit(SET_PENDING_STATE, { status, stepIndex }) commit(SET_PENDING_STATE, payload)
}, },
} }
export default { export default {