You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
6.4 KiB
204 lines
6.4 KiB
import '../../css/stakes.scss'
|
|
|
|
import $ from 'jquery'
|
|
import 'bootstrap'
|
|
import _ from 'lodash'
|
|
import { subscribeChannel } from '../socket'
|
|
import { connectElements } from '../lib/redux_helpers.js'
|
|
import { createAsyncLoadStore, refreshPage } from '../lib/async_listing_load'
|
|
import Web3 from 'web3'
|
|
import { openValidatorInfoModal } from './stakes/validator_info'
|
|
import { openDelegatorsListModal } from './stakes/delegators_list'
|
|
import { openBecomeCandidateModal } from './stakes/become_candidate'
|
|
import { openRemovePoolModal } from './stakes/remove_pool'
|
|
import { openMakeStakeModal } from './stakes/make_stake'
|
|
import { openMoveStakeModal } from './stakes/move_stake'
|
|
import { openWithdrawStakeModal } from './stakes/withdraw_stake'
|
|
import { openClaimWithdrawalModal } from './stakes/claim_withdrawal'
|
|
|
|
export const initialState = {
|
|
channel: null,
|
|
web3: null,
|
|
account: null,
|
|
stakingContract: null,
|
|
blockRewardContract: null,
|
|
tokenDecimals: 0,
|
|
tokenSymbol: '',
|
|
refreshInterval: null,
|
|
lastEpochNumber: 0,
|
|
lastBlockNumber: 0,
|
|
stakingAllowed: false
|
|
}
|
|
|
|
export function reducer (state = initialState, action) {
|
|
switch (action.type) {
|
|
case 'PAGE_LOAD':
|
|
case 'ELEMENTS_LOAD': {
|
|
return Object.assign({}, state, _.omit(action, 'type'))
|
|
}
|
|
case 'CHANNEL_CONNECTED': {
|
|
return Object.assign({}, state, { channel: action.channel })
|
|
}
|
|
case 'WEB3_DETECTED': {
|
|
return Object.assign({}, state, { web3: action.web3 })
|
|
}
|
|
case 'ACCOUNT_UPDATED': {
|
|
return Object.assign({}, state, {
|
|
account: action.account,
|
|
additionalParams: Object.assign({}, state.additionalParams, {
|
|
account: action.account
|
|
})
|
|
})
|
|
}
|
|
case 'FILTERS_UPDATED': {
|
|
return Object.assign({}, state, {
|
|
additionalParams: Object.assign({}, state.additionalParams, {
|
|
filterBanned: action.filterBanned,
|
|
filterMy: action.filterMy
|
|
})
|
|
})
|
|
}
|
|
case 'RECEIVED_UPDATE': {
|
|
return Object.assign({}, state, {
|
|
lastEpochNumber: action.lastEpochNumber,
|
|
lastBlockNumber: action.lastBlockNumber,
|
|
stakingAllowed: action.stakingAllowed
|
|
})
|
|
}
|
|
case 'RECEIVED_CONTRACTS': {
|
|
return Object.assign({}, state, {
|
|
stakingContract: action.stakingContract,
|
|
blockRewardContract: action.blockRewardContract,
|
|
tokenDecimals: action.tokenDecimals,
|
|
tokenSymbol: action.tokenSymbol
|
|
})
|
|
}
|
|
default:
|
|
return state
|
|
}
|
|
}
|
|
|
|
const elements = {
|
|
'[data-page="stakes"]': {
|
|
load ($el) {
|
|
return {
|
|
refreshInterval: $el.data('refresh-interval') || null,
|
|
additionalParams: {
|
|
filterBanned: $el.find('[pool-filter-banned]').prop('checked'),
|
|
filterMy: $el.find('[pool-filter-my]').prop('checked')
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const $stakesPage = $('[data-page="stakes"]')
|
|
const $stakesTop = $('[data-selector="stakes-top"]')
|
|
if ($stakesPage.length) {
|
|
const store = createAsyncLoadStore(reducer, initialState, 'dataset.identifierPool')
|
|
connectElements({ store, elements })
|
|
|
|
const channel = subscribeChannel('stakes:staking_update')
|
|
store.dispatch({ type: 'CHANNEL_CONNECTED', channel })
|
|
|
|
channel.on('staking_update', msg => {
|
|
// hide tooltip on tooltip triggering element reloading
|
|
// due to issues with bootstrap tooltips https://github.com/twbs/bootstrap/issues/13133
|
|
const stakesTopTooltipID = $('[aria-describedby]', $stakesTop).attr('aria-describedby')
|
|
$('#' + stakesTopTooltipID).hide()
|
|
|
|
$stakesTop.html(msg.top_html)
|
|
|
|
const state = store.getState()
|
|
if (
|
|
msg.staking_allowed !== state.stakingAllowed ||
|
|
msg.epoch_number > state.lastEpochNumber ||
|
|
(state.refreshInterval && msg.block_number >= state.lastBlockNumber + state.refreshInterval)
|
|
) {
|
|
store.dispatch({
|
|
type: 'RECEIVED_UPDATE',
|
|
lastEpochNumber: msg.epoch_number,
|
|
lastBlockNumber: msg.block_number,
|
|
stakingAllowed: msg.staking_allowed
|
|
})
|
|
refreshPage(store)
|
|
}
|
|
})
|
|
|
|
channel.on('contracts', msg => {
|
|
const web3 = store.getState().web3
|
|
const stakingContract =
|
|
new web3.eth.Contract(msg.staking_contract.abi, msg.staking_contract.address)
|
|
const blockRewardContract =
|
|
new web3.eth.Contract(msg.block_reward_contract.abi, msg.block_reward_contract.address)
|
|
|
|
store.dispatch({
|
|
type: 'RECEIVED_CONTRACTS',
|
|
stakingContract,
|
|
blockRewardContract,
|
|
tokenDecimals: parseInt(msg.token_decimals),
|
|
tokenSymbol: msg.token_symbol
|
|
})
|
|
})
|
|
|
|
$(document.body)
|
|
.on('click', '.js-validator-info', event => openValidatorInfoModal(event, store))
|
|
.on('click', '.js-delegators-list', event => openDelegatorsListModal(event, store))
|
|
.on('click', '.js-become-candidate', () => openBecomeCandidateModal(store))
|
|
.on('click', '.js-remove-pool', () => openRemovePoolModal(store))
|
|
.on('click', '.js-make-stake', event => openMakeStakeModal(event, store))
|
|
.on('click', '.js-move-stake', event => openMoveStakeModal(event, store))
|
|
.on('click', '.js-withdraw-stake', event => openWithdrawStakeModal(event, store))
|
|
.on('click', '.js-claim-withdrawal', event => openClaimWithdrawalModal(event, store))
|
|
|
|
$stakesPage
|
|
.on('change', '[pool-filter-banned]', () => updateFilters(store))
|
|
.on('change', '[pool-filter-my]', () => updateFilters(store))
|
|
|
|
initializeWeb3(store)
|
|
}
|
|
|
|
function updateFilters (store) {
|
|
store.dispatch({
|
|
type: 'FILTERS_UPDATED',
|
|
filterBanned: $stakesPage.find('[pool-filter-banned]').prop('checked'),
|
|
filterMy: $stakesPage.find('[pool-filter-my]').prop('checked')
|
|
})
|
|
refreshPage(store)
|
|
}
|
|
|
|
function initializeWeb3 (store) {
|
|
if (window.ethereum) {
|
|
const web3 = new Web3(window.ethereum)
|
|
store.dispatch({ type: 'WEB3_DETECTED', web3 })
|
|
|
|
setInterval(async function () {
|
|
const accounts = await web3.eth.getAccounts()
|
|
const account = accounts[0] ? accounts[0].toLowerCase() : null
|
|
|
|
if (account !== store.getState().account) {
|
|
setAccount(account, store)
|
|
}
|
|
}, 100)
|
|
|
|
$stakesTop.on('click', '[data-selector="login-button"]', loginByMetamask)
|
|
}
|
|
}
|
|
|
|
function setAccount (account, store) {
|
|
store.dispatch({ type: 'ACCOUNT_UPDATED', account })
|
|
store.getState().channel.push('set_account', account)
|
|
refreshPage(store)
|
|
}
|
|
|
|
async function loginByMetamask (event) {
|
|
event.stopPropagation()
|
|
event.preventDefault()
|
|
|
|
try {
|
|
await window.ethereum.enable()
|
|
} catch (e) {
|
|
console.log(e)
|
|
console.error('User denied account access')
|
|
}
|
|
}
|
|
|