Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

scan: implement ui and wireup redelegate modal #1985

Merged
merged 13 commits into from
Jun 17, 2020
Merged
1 change: 1 addition & 0 deletions CHANGELOG_UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

### Scan

- (feat) [\#1985](https://github.com/bandprotocol/bandchain/pull/1985) Add redelegate button and submit transaction modal
- (impv) [\#1958](https://github.com/bandprotocol/bandchain/pull/1958) Add human-readable error when broadcast tx, fix withdraw reward msg on guanyu
- (feat) [\#1938](https://github.com/bandprotocol/bandchain/pull/1938) Add validator's image from identity
- (impv) [\#1928](https://github.com/bandprotocol/bandchain/pull/1928) Add chainID for guanyu-devnet
Expand Down
3 changes: 2 additions & 1 deletion scan/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"@cosmostation/cosmosjs": "^0.5.5",
"@glennsl/bs-json": "^5.0.2",
"@ledgerhq/hw-transport-webusb": "^5.16.0",
"@sentry/browser": "^5.16.1",
"@material-ui/core": "^4.10.2",
"@sentry/browser": "^5.16.1",
"axios": "^0.19.2",
"axios-hook": "^0.0.6",
"axios-hooks": "^1.10.0",
Expand All @@ -32,6 +32,7 @@
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-highlight": "^0.12.0",
"react-select": "^3.1.0",
"reason-apollo": "^0.18.0",
"reason-apollo-hooks": "^6.0.0",
"reason-react": ">=0.7.1",
Expand Down
33 changes: 33 additions & 0 deletions scan/src/bindings/ReactSelect.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
type react_select_option_t = {
value: string,
label: string,
};

[@bs.deriving jsConverter]
type style_t('a, 'b) = {
control: 'a => 'a,
option: 'b => 'b,
};

[@bs.obj]
external makeProps:
(
~value: react_select_option_t,
~onChange: 'a => unit,
~options: array('a),
~styles: style_t('b, 'c),
unit
) =>
_ =
"";

[@bs.module "react-select"]
external make:
React.component({
.
"value": react_select_option_t,
"onChange": 'a => unit,
"options": array('a),
"styles": style_t('b, 'c),
}) =
"default";
2 changes: 2 additions & 0 deletions scan/src/components/EnhanceTxInput.re
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ let make =
~code=false,
~placeholder="",
~inputType="text",
~autoFocus=false,
) => {
let (status, setStatus) = React.useState(_ => Untouched);

Expand All @@ -99,6 +100,7 @@ let make =
placeholder
type_=inputType
spellCheck=false
autoFocus
onChange={event => {
let newText = ReactEvent.Form.target(event)##value;
onNewText(newText);
Expand Down
9 changes: 9 additions & 0 deletions scan/src/components/modal/ValidatorStakingInfo.re
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ module StakingInfo = {
dispatchModal(OpenModal(SubmitTx(SubmitMsg.Delegate(validatorAddress))));
let undelegate = () =>
dispatchModal(OpenModal(SubmitTx(SubmitMsg.Undelegate(validatorAddress))));
let redelegate = () =>
dispatchModal(OpenModal(SubmitTx(SubmitMsg.Redelegate(validatorAddress))));
let withdrawReward = () =>
dispatchModal(OpenModal(SubmitTx(SubmitMsg.WithdrawReward(validatorAddress))));
let isReachUnbondingLimit = unbondingList |> Belt_Array.length == 7;
Expand Down Expand Up @@ -197,6 +199,13 @@ module StakingInfo = {
<Text value="Undelegate" />
</button>
<HSpacing size=Spacing.md />
<button
className={Styles.button(100)}
onClick={_ => {redelegate()}}
disabled={balanceAtStakeAmount.amount == 0. || isReachUnbondingLimit}>
tansawit marked this conversation as resolved.
Show resolved Hide resolved
<Text value="Redelegate" />
</button>
<HSpacing size=Spacing.md />
<button
className={Styles.button(150)}
onClick={_ => {withdrawReward()}}
Expand Down
203 changes: 164 additions & 39 deletions scan/src/components/modal/submitTx/RedelegateMsg.re
Original file line number Diff line number Diff line change
@@ -1,56 +1,181 @@
module Styles = {
open Css;

let info = style([display(`flex), justifyContent(`spaceBetween), alignItems(`center)]);

let validator =
style([display(`flex), flexDirection(`column), alignItems(`flexEnd), width(`px(330))]);

let warning =
style([
padding(`px(10)),
color(Colors.blue5),
backgroundColor(Colors.blue1),
border(`px(1), `solid, Colors.blue6),
borderRadius(`px(4)),
]);

let select = style([width(`px(1000)), height(`px(1))]);
};

module DstValidatorSelection = {
type control_t = {
display: string,
height: string,
width: string,
fontSize: string,
backgroundColor: string,
borderRadius: string,
boxShadow: string,
};

type option_t = {
display: string,
alignItems: string,
height: string,
fontSize: string,
paddingLeft: string,
cursor: string,
};

[@react.component]
let make = (~filteredValidators: array(BandScan.ValidatorSub.t), ~setDstValidatorOpt) => {
let (selectedValidator, setSelectedValidator) =
React.useState(_ =>
ReactSelect.{value: "None", label: "Enter or select validator to delegate to"}
);
let validatorList =
filteredValidators->Belt_Array.map(({operatorAddress, moniker}) =>
ReactSelect.{value: operatorAddress |> Address.toBech32, label: moniker}
);
<ReactSelect
options=validatorList
onChange={newOption => {
let newVal = newOption;
setSelectedValidator(_ => newVal);
tansawit marked this conversation as resolved.
Show resolved Hide resolved
setDstValidatorOpt(_ => Some(newVal.value |> Address.fromBech32));
}}
value=selectedValidator
styles={
ReactSelect.control: _ => {
display: "flex",
height: "30px",
width: "300px",
fontSize: "11px",
backgroundColor: "white",
borderRadius: "4px",
boxShadow: "0 1px 4px 0 rgba(11,29,142,0.1) inset",
},
ReactSelect.option: _ => {
fontSize: "11px",
height: "30px",
display: "flex",
alignItems: "center",
paddingLeft: "10px",
cursor: "pointer",
},
}
/>;
};
};

[@react.component]
let make = (~validator, ~setMsgsOpt) => {
let (srcValidator, setSrcValidator) = React.useState(_ => EnhanceTxInput.empty);
let (dstValidator, setDstValidator) = React.useState(_ => EnhanceTxInput.empty);
let make = (~address, ~validator, ~setMsgsOpt) => {
let validatorInfoSub = ValidatorSub.get(validator);
let validatorsSub = ValidatorSub.getList(~isActive=true, ());
let delegationSub = DelegationSub.getStakeByValiator(address, validator);

let allSub = Sub.all3(validatorInfoSub, validatorsSub, delegationSub);

let (dstValidatorOpt, setDstValidatorOpt) = React.useState(_ => None);

let (amount, setAmount) = React.useState(_ => EnhanceTxInput.empty);

React.useEffect3(
React.useEffect2(
_ => {
let msgsOpt = {
let%Opt srcValidatorValue = srcValidator.value;
let%Opt dstValidatorValue = dstValidator.value;
let%Opt dstValidator = dstValidatorOpt;
let%Opt amountValue = amount.value;
Some([|
TxCreator.Redelegate(
srcValidatorValue,
dstValidatorValue,
validator,
dstValidator,
{amount: amountValue |> Js.Float.toString, denom: "uband"},
),
|]);
};
setMsgsOpt(_ => msgsOpt);
None;
},
(srcValidator, dstValidator, amount),
(dstValidatorOpt, amount),
);
// TODO: do it later
React.null;
// <>
// <EnhanceTxInput
// width=360
// inputData=srcValidator
// setInputData=setSrcValidator
// parse=Parse.address
// msg="From"
// code=true
// />
// <VSpacing size=Spacing.md />
// <EnhanceTxInput
// width=360
// inputData=dstValidator
// setInputData=setDstValidator
// parse=Parse.address
// msg="To"
// code=true
// />
// <VSpacing size=Spacing.md />
// <EnhanceTxInput
// width=115
// inputData=amount
// setInputData=setAmount
// parse=Parse.getBandAmount
// msg="Amount (BAND)"
// code=true
// />
// </>;
<>
<VSpacing size=Spacing.lg />
<div className=Styles.info>
<Text value="Current Stake" size=Text.Lg spacing={Text.Em(0.03)} nowrap=true block=true />
{switch (allSub) {
| Data((_, _, {amount: stakedAmount})) =>
<div>
<Text
value={stakedAmount |> Coin.getBandAmountFromCoin |> Format.fPretty(~digits=6)}
code=true
size=Text.Lg
weight=Text.Semibold
/>
<Text value=" BAND" code=true />
</div>
| _ => <LoadingCensorBar width=150 height=18 />
}}
</div>
<VSpacing size=Spacing.lg />
<VSpacing size=Spacing.md />
<div className=Styles.info>
<Text value="Redelegate From" size=Text.Lg spacing={Text.Em(0.03)} nowrap=true block=true />
{switch (allSub) {
| Data(({moniker}, _, _)) =>
<div className=Styles.validator>
<Text value=moniker code=true ellipsis=true align=Text.Right />
<Text
value={"(" ++ validator->Address.toOperatorBech32 ++ ")"}
size=Text.Sm
color=Colors.blueGray5
code=true
/>
</div>
| _ => <LoadingCensorBar width=300 height=26 />
}}
</div>
<VSpacing size=Spacing.md />
<div className=Styles.info>
<Text value="Redelegate To" size=Text.Lg spacing={Text.Em(0.03)} nowrap=true block=true />
{switch (allSub) {
| Data(({operatorAddress}, validators, _)) =>
let filteredValidators =
validators->Belt_Array.keep(validator =>
validator.operatorAddress != operatorAddress && validator.commission != 100.
);
<DstValidatorSelection filteredValidators setDstValidatorOpt />;
| _ => <LoadingCensorBar width=300 height=26 />
}}
</div>
<VSpacing size=Spacing.lg />
{switch (allSub) {
| Data((_, _, {amount: stakedAmount})) =>
let maxValInUband = stakedAmount |> Coin.getUBandAmountFromCoin;
<EnhanceTxInput
width=300
inputData=amount
setInputData=setAmount
parse={Parse.getBandAmount(maxValInUband)}
maxValue={maxValInUband /. 1e6 |> Js.Float.toString}
msg="Undelegate Amount (BAND)"
tansawit marked this conversation as resolved.
Show resolved Hide resolved
placeholder="Insert unbonding amount"
evilpeach marked this conversation as resolved.
Show resolved Hide resolved
inputType="number"
code=true
autoFocus=true
/>;
| _ => <EnhanceTxInput.Loading msg="Undelegate Amount (BAND)" width=300 />
tansawit marked this conversation as resolved.
Show resolved Hide resolved
}}
<VSpacing size=Spacing.lg />
</>;
};
4 changes: 2 additions & 2 deletions scan/src/components/modal/submitTx/SubmitTxModal.re
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ module SubmitTxStep = {
let make = (~account: AccountContext.t, ~setRawTx, ~isActive, ~msg) => {
let (msgsOpt, setMsgsOpt) = React.useState(_ => None);

let gas = 200000;
let gas = 250000;
let fee = 5000.;
let (memo, setMemo) = React.useState(_ => EnhanceTxInput.{text: "", value: Some("")});

Expand All @@ -110,7 +110,7 @@ module SubmitTxStep = {
| SubmitMsg.Send(receiver) => <SendMsg address={account.address} receiver setMsgsOpt />
| Delegate(validator) => <DelegateMsg address={account.address} validator setMsgsOpt />
| Undelegate(validator) => <UndelegateMsg address={account.address} validator setMsgsOpt />
| Redelegate(validator) => <RedelegateMsg validator setMsgsOpt />
| Redelegate(validator) => <RedelegateMsg address={account.address} validator setMsgsOpt />
| WithdrawReward(validator) =>
<WithdrawRewardMsg validator setMsgsOpt address={account.address} />
}}
Expand Down
4 changes: 2 additions & 2 deletions scan/src/reusable/Text.re
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ let make =
])}>
{React.string(value)}
</span>
: <MaterialUI
: <Tooltip
title=tooltipItem
placement={tooltipPlacement |> toPlacementString}
arrow=true
Expand All @@ -201,5 +201,5 @@ let make =
])}>
{React.string(value)}
</span>
</MaterialUI>;
</Tooltip>;
};
Loading