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;
}
}
fieldset[disabled] {
.button {
&.is-primary {
&.is-outlined {
.trnd {
background-color: #44f1a6;
}
}
}
}
}

View File

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

View File

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

View File

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

View File

@ -1,10 +1,7 @@
<template>
<div :id="data.isActive ? 'current' : ''" class="step">
<div class="step-container">
<diamond
:active="!!data.deployerAddress"
:waiting="!canDeploy(data.domain)"
/>
<diamond :active="!!data.deployerAddress" :waiting="isDeployed" />
<div class="step-body">
<h4>{{ data.title }}</h4>
<h5 v-if="data.domain" class="deployed">
@ -44,22 +41,20 @@
:label="
isNotLoggedIn
? $t('pleaseConnectWallet')
: !canDeploy(data.domain)
: isDeployed
? $t('dependsOnEns', { ens: data.dependsOn.join(', ') })
: ''
"
position="is-top"
multilined
:size="isNotLoggedIn ? 'is-small' : 'is-large'"
:active="isNotLoggedIn || !canDeploy(data.domain)"
:active="isNotLoggedIn || isDeployed"
>
<b-button
type="is-primary"
outlined
icon-left="tool"
:disabled="
isNotLoggedIn || !canDeploy(data.domain) || data.isPending
"
:disabled="isNotLoggedIn || isDeployed || data.isPending"
@mousedown="(e) => e.preventDefault()"
@click="onDeploy"
>
@ -118,6 +113,9 @@ export default {
...mapGetters('provider', ['getProviderName', 'getAccount']),
...mapGetters('steps', ['canDeploy']),
...mapGetters('txStorage', ['txExplorerUrl', 'addressExplorerUrl']),
isDeployed() {
return !this.canDeploy(this.data.domain, this.data.isL1Contract)
},
isNotLoggedIn() {
return !this.getProviderName
},
@ -125,7 +123,11 @@ export default {
methods: {
...mapActions('deploy', ['deployContract']),
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>
<div class="steps">
<step v-for="(step, index) in getData" :key="index" :data="step" />
<div class="steps--container">
<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>
</template>
<script>
import Step from '@/components/Step'
import { mapState } from 'vuex'
import { mapState, mapGetters, mapActions } from 'vuex'
export default {
components: {
Step,
},
computed: {
...mapState('steps', ['steps']),
...mapState('airdrop', ['airdrops', 'notificationIndex']),
getData() {
if (Array.isArray(this.airdrops)) {
return this.steps.map((step, index) => {
if (step.contract === 'Airdrop.sol') {
const dropIndex = index - this.airdrops.length + 2
return {
...step,
airdrops: this.airdrops[dropIndex],
isActive: this.notificationIndex === dropIndex,
}
}
return step
})
}
return this.steps
...mapState('steps', ['l1Steps', 'l2Steps']),
...mapGetters('provider', ['getNetwork', 'getProviderName']),
isLoggedIn() {
return !!this.getProviderName
},
},
methods: {
...mapActions('provider', ['switchNetwork']),
isDisabledSteps(layer) {
const { isL1 } = this.getNetwork
return isL1 ? layer === 'L2' : layer === 'L1'
},
getSteps(layer) {
return layer === 'L1' ? this.l1Steps : this.l2Steps
},
changeNetwork(layer) {
const netId = layer === 'L1' ? 1 : 100
this.switchNetwork({ netId })
},
},
}
</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",
"deployedBy": "Deployed by: {link}",
"startNow": "Start now",
"completedTasks": "Completed Tasks: {progress}",
"pageSubtitle": "Follow these simple steps to become part of deployment of Tornado.Cash protocol on xDAI Chain.",
"l1": "Layer 1",
"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",
"contractDeployed": "Contract successfully deployed",
"transactionFailed": "Transaction was failed",
@ -26,6 +28,8 @@
"viewOnEtherscan": "View on Etherscan",
"pleaseConnectWallet": "Please connect your wallet first",
"dependsOnEns": "This action depends on {ens}",
"xDaiOnly": "Please switch your wallet to xDAI Chain",
"switchNetwork": "Switch to xDAI"
"switchToL1": "Please switch your wallet to Ethereum Mainnet for L1 deployment.",
"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 = {
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: {
rpcCallRetryAttempt: 15,
gasPrices: {
@ -20,6 +40,7 @@ const networkConfig = {
},
},
pollInterval: 200,
isL1: false,
},
}

View File

@ -1,7 +1,7 @@
<template>
<div>
<h1 class="title has-text-centered">
Tornado.cash <span>xDAI</span> Deployment
Tornado.cash <span>Pool</span> Deployment
</h1>
<h2 class="subtitle has-text-centered">{{ $t('pageSubtitle') }}</h2>
@ -17,11 +17,11 @@
</div>
<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>
<span>{{ deployedCount }}</span>
<span>{{ getNetwork.isL1 ? deployedL1Count : deployedL2Count }}</span>
</template>
</i18n>
<div class="tornado-discoverer image is-16by9"></div>
<steps ref="steps" />
@ -37,7 +37,8 @@ export default {
Steps,
},
computed: {
...mapGetters('steps', ['deployedCount']),
...mapGetters('steps', ['deployedL1Count', 'deployedL2Count']),
...mapGetters('provider', ['getNetwork']),
},
methods: {
scrollTo(element) {

File diff suppressed because one or more lines are too long

View File

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

View File

@ -14,20 +14,33 @@ export default {
async initProvider({ commit, state, getters, dispatch }, { name, network }) {
try {
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(
'notice/addNotice',
{
notice: {
title: 'xDaiOnly',
title: 'switchToL1',
type: 'danger',
callback: () => dispatch('switchNetwork', { netId: 100 }),
message: 'switchNetwork',
callback: () => dispatch('switchNetwork', { netId: 1 }),
message: 'switchNetworkToL1',
},
},
{ 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)

View File

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

View File

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