Skip to content

Commit

Permalink
Multi delegate prod updates (#96)
Browse files Browse the repository at this point in the history
* Updated gas calculations (#92)

* Update index.js

* Update index.js

* added Compound, Claim Delegate Dialog, Claim Delegate Validator Selec… (#93)

* added Compound, Claim Delegate Dialog, Claim Delegate Validator Select Field components

* Errors Resolved

* Errors Resolved

* Errors Resolved

* Errors Resolved

* Resolved the fee issue

* Resolved the amount issue

* Resolved the amount issue

* implemented the condition where claim amount should be greater than gas fee amount

* issue resolved

* issue resolved

* issue resolved

---------

Co-authored-by: = <=>
Co-authored-by: SrikanthSoparla <srikanth.soparla@gmail.com>

* Multi-Delegate (#94)

* Created MultiDelegateButton

* Multidelegate button

* Redux Store

* multi-delegate button styling

* added multidelegate button in stake page

* mui select field with select all button

* added support for multi-delegate

* for multidelegate

* handle multi delegate and styling

* Fixed select all, works better now.

* Removed caniuse-lite and reformated the code.

* Showing active validators only.

* added multi-delegate button to homescreen and changed the style to match viewall button

* refractoring

* changed breakpoints, fixed autoscroll on select all button.

* Fixed Success Message

* Success Dialog -> Validator Image, Name, Address

* Style formatting

* Removed un-required proptypes

* Removed un-required parts

* onMouseEnter working, onMouseExit not working

* Replaced Popover with Tooltip.

* Resolved some warnings. Changed button to div.

* formatting

* minor format

* Removed unused Proptypes.

* Transitions for pages and dialog boxes (#95)

* FadeIn for pages, ScaleUp for dialogs. Added back checks for Image before rendering.

* animation fixes.

* yarn lock fixes.

---------

Co-authored-by: SrikanthSoparla <srikanth.soparla@gmail.com>

---------

Co-authored-by: Daksha Validator <87847563+dakshavalidator@users.noreply.github.com>
Co-authored-by: VasaviMahajan <83421343+VasaviMahajan@users.noreply.github.com>
Co-authored-by: Rahman <59746881+volkavich@users.noreply.github.com>
  • Loading branch information
4 people committed Aug 9, 2023
1 parent 0a06428 commit 5f11d02
Show file tree
Hide file tree
Showing 20 changed files with 1,096 additions and 38 deletions.
30 changes: 30 additions & 0 deletions src/actions/stake.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
CLAIM_REWARDS_DIALOG_HIDE,
CLAIM_REWARDS_DIALOG_SHOW,
CLAIM_REWARDS_VALIDATOR_SET,
CLAIM_DELEGATE_DIALOG_SHOW,
CLAIM_DELEGATE_DIALOG_HIDE,
CLAIM_DELEGATE_VALIDATOR_SET,
DELEGATE_DIALOG_HIDE,
DELEGATE_DIALOG_SHOW,
DELEGATE_FAILED_DIALOG_HIDE,
Expand Down Expand Up @@ -32,6 +35,7 @@ import {
VALIDATORS_FETCH_ERROR,
VALIDATORS_FETCH_IN_PROGRESS,
VALIDATORS_FETCH_SUCCESS,
SELECTED_MULTI_VALIDATORS,
} from '../constants/stake';
import Axios from 'axios';
import {
Expand Down Expand Up @@ -274,6 +278,25 @@ export const setClaimRewardsValidator = (value) => {
};
};

export const showClaimDelegateDialog = () => {
return {
type: CLAIM_DELEGATE_DIALOG_SHOW,
};
};

export const hideClaimDelegateDialog = () => {
return {
type: CLAIM_DELEGATE_DIALOG_HIDE,
};
};

export const setClaimDelegateValidator = (value) => {
return {
type: CLAIM_DELEGATE_VALIDATOR_SET,
value,
};
};

const fetchValidatorImageInProgress = () => {
return {
type: VALIDATOR_IMAGE_FETCH_IN_PROGRESS,
Expand Down Expand Up @@ -428,3 +451,10 @@ export const fetchAPR = () => (dispatch) => {
}
})();
};

export const selectMultiValidators = (value) => {
return {
type: SELECTED_MULTI_VALIDATORS,
value,
};
};
30 changes: 30 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,33 @@ html::-webkit-scrollbar-thumb,
margin: 10px;
}
}

@keyframes fadeInAnimation {
from {
opacity: 0;
}

to {
opacity: 1;
}
}

.stake .stake_content,
.proposals .proposals_content,
.home .card {
animation: fadeInAnimation ease-in-out 1s;
}

@keyframes dialogOpen {
from {
transform: scale(0.5);
}

to {
transform: scale(1);
}
}

.dialog {
animation: dialogOpen 0.1s;
}
7 changes: 6 additions & 1 deletion src/constants/stake.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ export const DELEGATED_VALIDATORS_FETCH_ERROR = 'DELEGATED_VALIDATORS_FETCH_ERRO

export const CLAIM_REWARDS_DIALOG_SHOW = 'CLAIM_REWARDS_DIALOG_SHOW';
export const CLAIM_REWARDS_DIALOG_HIDE = 'CLAIM_REWARDS_DIALOG_HIDE';

export const CLAIM_REWARDS_VALIDATOR_SET = 'CLAIM_REWARDS_VALIDATOR_SET';

export const CLAIM_DELEGATE_DIALOG_SHOW = 'CLAIM_DELEGATE_DIALOG_SHOW';
export const CLAIM_DELEGATE_DIALOG_HIDE = 'CLAIM_DELEGATE_DIALOG_HIDE';
export const CLAIM_DELEGATE_VALIDATOR_SET = 'CLAIM_DELEGATE_VALIDATOR_SET';

export const VALIDATOR_IMAGE_FETCH_IN_PROGRESS = 'VALIDATOR_IMAGE_FETCH_IN_PROGRESS';
export const VALIDATOR_IMAGE_FETCH_SUCCESS = 'VALIDATOR_IMAGE_FETCH_SUCCESS';
export const VALIDATOR_IMAGE_FETCH_ERROR = 'VALIDATOR_IMAGE_FETCH_ERROR';
Expand All @@ -45,3 +48,5 @@ export const INACTIVE_VALIDATORS_FETCH_ERROR = 'INACTIVE_VALIDATORS_FETCH_ERROR'
export const APR_FETCH_IN_PROGRESS = 'APR_FETCH_IN_PROGRESS';
export const APR_FETCH_SUCCESS = 'APR_FETCH_SUCCESS';
export const APR_FETCH_ERROR = 'APR_FETCH_ERROR';

export const SELECTED_MULTI_VALIDATORS = 'SELECTED_MULTI_VALIDATORS';
248 changes: 248 additions & 0 deletions src/containers/Home/ClaimDialog/ClaimDelegateDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import React, { useState } from 'react';
import { Button, Dialog, DialogActions, DialogContent } from '@material-ui/core';
import * as PropTypes from 'prop-types';
import {
hideClaimDelegateDialog,
setTokens,
showDelegateFailedDialog,
showDelegateProcessingDialog,
showDelegateSuccessDialog,
} from '../../../actions/stake';
import { connect } from 'react-redux';
import '../../Stake/DelegateDialog/index.css';
import { cosmoStationSign, signTxAndBroadcast } from '../../../helper';
import { showMessage } from '../../../actions/snackbar';
import { fetchRewards, fetchVestingBalance, getBalance } from '../../../actions/accounts';
import { config } from '../../../config';
import variables from '../../../utils/variables';
import CircularProgress from '../../../components/CircularProgress';
import { gas } from '../../../defaultGasValues';
import ClaimDelegateValidatorsSelectField from './ClaimDelegateValidatorSelectField';

const ClaimDelegateDialog = (props) => {
const [inProgress, setInProgress] = useState(false);

const handleClaimAll = () => {
setInProgress(true);
let gasValue = gas.claim_reward + gas.delegate;
let count = 0;
if (props.rewards && props.rewards.rewards && props.rewards.rewards.length > 1) {
props.rewards.rewards.map((item) => {
const tokens = item && item.reward && item.reward.length &&
item.reward.filter((val) => val.amount > gasValue * config.GAS_PRICE_STEP_AVERAGE);
if (tokens) {
count += tokens.length;
}
return null;
});
}
if (count) {
gasValue = count * gasValue / 1.1 + gasValue;
}

const updatedTx = {
msgs: [],
fee: {
amount: [{
amount: String(gasValue * config.GAS_PRICE_STEP_AVERAGE),
denom: config.COIN_MINIMAL_DENOM,
}],
gas: String(gasValue),
},
memo: '',
};
if (props.rewards && props.rewards.rewards &&
props.rewards.rewards.length) {
props.rewards.rewards.map((item) => {
let tokens = item && item.reward && item.reward.length &&
item.reward.find((val) => val.denom === config.COIN_MINIMAL_DENOM);
tokens = tokens && tokens.amount;
if (tokens && tokens > ((gas.claim_reward + gas.delegate) * config.GAS_PRICE_STEP_AVERAGE)) {
updatedTx.msgs.push({
typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward',
value: {
delegatorAddress: props.address,
validatorAddress: item.validator_address,
},
}, {
typeUrl: '/cosmos.staking.v1beta1.MsgDelegate',
value: {
delegatorAddress: props.address,
validatorAddress: item.validator_address,
amount: {
amount: String(Math.floor(Number(tokens))),
denom: config.COIN_MINIMAL_DENOM,
},
},
});
}
return null;
});
}

if (localStorage.getItem('of_co_wallet') === 'cosmostation') {
cosmoStationSign(updatedTx, props.address, handleFetch);
return;
}

signTxAndBroadcast(updatedTx, props.address, handleFetch);
};

const handleFetch = (error, result) => {
setInProgress(false);
if (error) {
if (error.indexOf('not yet found on the chain') > -1) {
props.pendingDialog();
return;
}
props.failedDialog();
props.showMessage(error);
return;
}
if (result) {
props.setTokens(tokens);
props.successDialog(result.transactionHash);
props.fetchRewards(props.address);
props.getBalance(props.address);
props.fetchVestingBalance(props.address);
}
};

const handleClaim = () => {
setInProgress(true);
const updatedTx = {
msgs: [{
typeUrl: '/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward',
value: {
delegatorAddress: props.address,
validatorAddress: props.value,
},
}, {
typeUrl: '/cosmos.staking.v1beta1.MsgDelegate',
value: {
delegatorAddress: props.address,
validatorAddress: props.value,
amount: {
amount: String(Math.floor(Number(delegateableTokesn))),
denom: config.COIN_MINIMAL_DENOM,
},
},
}],
fee: {
amount: [{
amount: String((gas.claim_reward + gas.delegate) * config.GAS_PRICE_STEP_AVERAGE),
denom: config.COIN_MINIMAL_DENOM,
}],
gas: String(gas.claim_reward + gas.delegate),
},
memo: '',
};

if (localStorage.getItem('of_co_wallet') === 'cosmostation') {
cosmoStationSign(updatedTx, props.address, handleFetch);
return;
}

signTxAndBroadcast(updatedTx, props.address, handleFetch);
};

const rewards = props.rewards && props.rewards.rewards &&
props.rewards.rewards.length &&
props.rewards.rewards.filter((value) => value.validator_address === props.value);

let tokens = rewards && rewards.length && rewards[0] && rewards[0].reward &&
rewards[0].reward.length && rewards[0].reward.find((val) => val.denom === config.COIN_MINIMAL_DENOM);
const delegateableTokesn = tokens && tokens.amount;
tokens = tokens && tokens.amount ? tokens.amount / 10 ** config.COIN_DECIMALS : 0;

if (props.value === 'all' && props.rewards && props.rewards.rewards &&
props.rewards.rewards.length) {
const gasValue = (gas.claim_reward + gas.delegate) * config.GAS_PRICE_STEP_AVERAGE;
let total = 0;

props.rewards.rewards.map((value) => {
let rewards = value.reward && value.reward.length &&
value.reward.find((val) => val.denom === config.COIN_MINIMAL_DENOM);
rewards = rewards && rewards.amount && rewards.amount > gasValue ? rewards.amount / 10 ** config.COIN_DECIMALS : 0;
total = rewards + total;

return total;
});
tokens = total;
}

const disable = props.value === 'none' || inProgress;

return (
<Dialog
aria-describedby="claim-dialog-description"
aria-labelledby="claim-dialog-title"
className="dialog delegate_dialog claim_dialog"
open={props.open}
onClose={props.handleClose}>
{inProgress && <CircularProgress className="full_screen"/>}
<DialogContent className="content">
<h1>Claim and Delegate Rewards</h1>
<p>Select validator</p>
<ClaimDelegateValidatorsSelectField/>
{tokens && tokens > 0
? <p>rewards: {tokens.toFixed(4)}</p>
: null}
</DialogContent>
<DialogActions className="footer">
<Button
disabled={disable}
variant="contained"
onClick={props.value === 'all' ? handleClaimAll : handleClaim}>
{inProgress
? variables[props.lang]['approval_pending']
: variables[props.lang].compound}
</Button>
</DialogActions>
</Dialog>
);
};

ClaimDelegateDialog.propTypes = {
failedDialog: PropTypes.func.isRequired,
fetchRewards: PropTypes.func.isRequired,
fetchVestingBalance: PropTypes.func.isRequired,
getBalance: PropTypes.func.isRequired,
handleClose: PropTypes.func.isRequired,
lang: PropTypes.string.isRequired,
open: PropTypes.bool.isRequired,
pendingDialog: PropTypes.func.isRequired,
rewards: PropTypes.shape({
rewards: PropTypes.array,
total: PropTypes.array,
}).isRequired,
setTokens: PropTypes.func.isRequired,
showMessage: PropTypes.func.isRequired,
successDialog: PropTypes.func.isRequired,
value: PropTypes.string.isRequired,
address: PropTypes.string,
};

const stateToProps = (state) => {
return {
address: state.accounts.address.value,
lang: state.language,
open: state.stake.claimDelegateDialog.open,
value: state.stake.claimDelegateDialog.validator,
rewards: state.accounts.rewards.result,
};
};

const actionToProps = {
handleClose: hideClaimDelegateDialog,
failedDialog: showDelegateFailedDialog,
successDialog: showDelegateSuccessDialog,
pendingDialog: showDelegateProcessingDialog,
getBalance,
fetchVestingBalance,
showMessage,
fetchRewards,
setTokens,
};

export default connect(stateToProps, actionToProps)(ClaimDelegateDialog);
Loading

0 comments on commit 5f11d02

Please sign in to comment.