@bzxnetwork/portal
Version:
Frontend demo portal for bZx
440 lines (411 loc) • 13.9 kB
JSX
import { Fragment } from "react";
import styled from "styled-components";
import Button from "@material-ui/core/Button";
import {
fromBigNumber,
toBigNumber,
getInitialCollateralRequired
} from "../../common/utils";
import Section, { SectionLabel, Divider } from "../../common/FormSection";
import { getDecimals } from "../../common/tokens";
import Tokens from "./Tokens";
import Details from "./Details";
import Expiration from "./Expiration";
import Inputs from "./Inputs";
import CancelInputs from "./CancelInputs";
import BZxComponent from "../../common/BZxComponent";
import {
validateFillOrder,
validateCancelOrder,
submitFillOrder,
submitFillOrderWithHash,
submitCancelOrder,
submitCancelOrderWithHash
} from "./utils";
import { getOrderHash } from "../GenerateOrder/utils";
const SubmitBtn = styled(Button)`
width: 100%;
max-width: 480px;
margin-bottom: 24px;
`;
const Hash = styled.a`
font-family: monospace;
`;
const defaultToken = tokens => {
let token = tokens.filter(t => t.symbol === `DAI`);
if (token.length > 0) {
token = token[0]; // eslint-disable-line prefer-destructuring
} else {
token = tokens[0]; // eslint-disable-line prefer-destructuring
}
return token;
};
export default class FillOrder extends BZxComponent {
state = {
fillOrderAmount: 0,
collateralTokenAddress: defaultToken(this.props.tokens).address,
collateralTokenAmount: `(finish form then refresh)`,
loanTokenAvailable: 0,
overCollateralize: false
};
async componentDidMount() {
// console.log(this.props.order);
if (this.props.order.makerRole !== `0`) {
this.refreshCollateralAmountNoEvent();
}
try {
const orderHash = this.props.order.loanOrderHash
? this.props.order.loanOrderHash
: getOrderHash(this.props.order);
// console.log("orderHash: "+orderHash);
const orderDetail = await this.getSingleOrder(orderHash);
console.log(orderDetail);
if (Object.keys(orderDetail).length !== 0) {
let loanTokenAvailable =
orderDetail.loanTokenAmount -
(this.props.order.makerAddress.toLowerCase() !== this.props.accounts[0].toLowerCase() ? orderDetail.orderFilledAmount : 0) -
orderDetail.orderCancelledAmount;
if (loanTokenAvailable < 0)
loanTokenAvailable = 0;
this.setState({ loanTokenAvailable });
} else {
const cancelledAmount = await this.props.bZx.orderCancelledAmount(
orderHash
);
this.setState({ loanTokenAvailable: this.props.order.loanTokenAmount-cancelledAmount });
}
} catch (e) {} // eslint-disable-line no-empty
}
/* State setters */
setStateForCollateralAmount = async (
loanTokenAddress,
collateralTokenAddress,
oracleAddress,
loanTokenAmount,
initialMarginAmount
) => {
let collateralRequired = `(finish form then refresh)`;
if (
loanTokenAddress &&
collateralTokenAddress &&
oracleAddress &&
loanTokenAmount &&
initialMarginAmount
) {
if (toBigNumber(loanTokenAmount).gt(0) && collateralTokenAddress && collateralTokenAddress !== `0x0000000000000000000000000000000000000000`) {
this.setState({ [`collateralTokenAmount`]: `loading...` });
collateralRequired = toBigNumber(await getInitialCollateralRequired(
loanTokenAddress,
collateralTokenAddress,
oracleAddress,
toBigNumber(loanTokenAmount).toFixed(0),
toBigNumber(initialMarginAmount).toFixed(0),
this.props.bZx
));
let overCollateralize = this.props.order.makerRole === `0`
? this.state.overCollateralize
: !!+this.props.order.withdrawOnOpen;
if (overCollateralize) {
collateralRequired = collateralRequired.plus(collateralRequired.times(10 ** 20).div(initialMarginAmount));
}
collateralRequired = fromBigNumber(
collateralRequired,
10 ** getDecimals(this.props.tokens, collateralTokenAddress)
);
} else {
collateralRequired = `0`;
}
// console.log(`collateralRequired: ${collateralRequired}`);
if (collateralRequired === 0) {
collateralRequired = `(unsupported)`;
}
}
this.setState({ [`collateralTokenAmount`]: collateralRequired });
};
setStateFor = key => value => this.setState({ [key]: value });
setCollateralTokenAddress = async value => {
await this.setState({ [`collateralTokenAddress`]: value });
await this.refreshCollateralAmountNoEvent();
};
setOverCollateralize = async (e, value) => {
await this.setState({ [`overCollateralize`]: value });
await this.refreshCollateralAmountNoEvent();
};
getSingleOrder = async loanOrderHash => {
const { bZx } = this.props;
const order = await this.wrapAndRun(bZx.getSingleOrder({
loanOrderHash
}));
return order;
};
refreshCollateralAmountNoEvent = async () => {
await this.setStateForCollateralAmount(
this.props.order.loanTokenAddress,
this.props.order.makerRole === `0`
? this.state.collateralTokenAddress
: this.props.order.collateralTokenAddress,
this.props.order.oracleAddress,
this.props.order.makerRole === `0`
? toBigNumber(
this.state.fillOrderAmount,
10 **
getDecimals(this.props.tokens, this.props.order.loanTokenAddress)
)
: this.props.order.loanTokenAmount,
this.props.order.initialMarginAmount
);
};
refreshCollateralAmount = async event => {
event.preventDefault();
await this.refreshCollateralAmountNoEvent();
};
handleSubmit = async () => {
const {
order,
tokens,
oracles,
web3,
bZx,
accounts,
changeOrderTab,
resetOrder
} = this.props;
await this.setState({ isSubmitted: true });
await this.refreshCollateralAmountNoEvent();
const {
fillOrderAmount,
loanTokenAvailable,
collateralTokenAddress,
collateralTokenAmount,
overCollateralize
} = this.state;
const isFillOrderValid = await validateFillOrder(
order,
fillOrderAmount,
loanTokenAvailable,
collateralTokenAddress,
collateralTokenAmount,
tokens,
oracles,
bZx,
accounts
);
if (isFillOrderValid) {
if (!order.loanOrderHash) {
submitFillOrder(
order,
fillOrderAmount,
collateralTokenAddress,
overCollateralize,
tokens,
web3,
bZx,
accounts,
resetOrder
);
} else {
submitFillOrderWithHash(
order.loanOrderHash,
order.makerRole === `0`,
order.loanTokenAddress,
fillOrderAmount,
collateralTokenAddress,
overCollateralize,
tokens,
web3,
bZx,
accounts,
changeOrderTab
);
}
} else {
await this.setState({ isSubmitted: false });
}
};
handleCancelSubmit = async () => {
const {
order,
tokens,
web3,
bZx,
accounts,
changeOrderTab,
resetOrder
} = this.props;
await this.setState({ isSubmitted: true });
await this.refreshCollateralAmountNoEvent();
const { fillOrderAmount, loanTokenAvailable } = this.state;
const isCancelOrderValid = await validateCancelOrder(
order,
fillOrderAmount, // cancelOrderAmount
loanTokenAvailable,
tokens,
bZx,
accounts
);
if (isCancelOrderValid) {
if (!order.loanOrderHash) {
submitCancelOrder(
order,
fillOrderAmount,
tokens,
web3,
bZx,
accounts,
resetOrder
);
} else {
submitCancelOrderWithHash(
order.loanOrderHash,
order.loanTokenAddress,
fillOrderAmount,
tokens,
web3,
bZx,
accounts,
changeOrderTab
);
}
} else {
await this.setState({ isSubmitted: false });
}
};
render() {
const { order, tokens, bZx, accounts } = this.props;
const isMaker =
order.makerAddress.toLowerCase() === accounts[0].toLowerCase();
const makerRole = order.makerRole === `0` ? `lender` : `trader`;
const counterRole = order.makerRole !== `0` ? `lender` : `trader`;
return (
<Fragment>
<Section>
<SectionLabel>1. Review order info</SectionLabel>
<p>
{isMaker ? (
<Fragment>
This order was created by you for a{` `}
{counterRole} to fill.
</Fragment>
) : (
<Fragment>
This order was created by
{` `}
<Hash
href={`${bZx.etherscanURL}address/${order.makerAddress}`}
target="_blank"
rel="noopener noreferrer"
>
{order.makerAddress}
</Hash>
{` `}
for a{` `}
{counterRole} to fill.
</Fragment>
)}
</p>
<Tokens
bZx={bZx}
tokens={tokens}
role={makerRole}
loanTokenAddress={order.loanTokenAddress}
loanTokenAvailable={fromBigNumber(
this.state.loanTokenAvailable,
10 ** getDecimals(tokens, order.loanTokenAddress)
)}
interestTokenAddress={order.interestTokenAddress}
interestAmount={fromBigNumber(
order.interestAmount,
10 ** getDecimals(tokens, order.interestAmount)
)}
collateralTokenAddress={order.collateralTokenAddress}
collateralTokenAmount={this.state.collateralTokenAmount}
isMaker={isMaker}
/>
<Details
bZx={bZx}
oracles={this.props.oracles}
initialMarginAmount={order.initialMarginAmount}
maintenanceMarginAmount={order.maintenanceMarginAmount}
oracleAddress={order.oracleAddress}
signature={order.signature}
feeRecipientAddress={order.feeRecipientAddress}
lenderRelayFee={fromBigNumber(order.lenderRelayFee, 1e18)}
traderRelayFee={fromBigNumber(order.traderRelayFee, 1e18)}
/>
<Expiration
expirationUnixTimestampSec={order.expirationUnixTimestampSec}
/>
</Section>
{this.state.loanTokenAvailable ? (
<Fragment>
<Divider />
<Section>
{isMaker ? (
<Fragment>
<SectionLabel>
2. Choose cancel amount and submit
</SectionLabel>
<CancelInputs
bZx={bZx}
tokens={tokens}
fillOrderAmount={this.state.fillOrderAmount}
loanTokenAddress={order.loanTokenAddress}
setFillOrderAmount={this.setStateFor(`fillOrderAmount`)}
/>
<SubmitBtn
variant="raised"
color="primary"
onClick={this.handleCancelSubmit}
disabled={this.state.isSubmitted}
>
{this.state.isSubmitted ? `Please Wait` : `Cancel Order`}
</SubmitBtn>
</Fragment>
) : (
<Fragment>
<SectionLabel>
{makerRole === `lender`
? `2. Choose parameters and submit`
: `2. Submit fill order transaction`}
</SectionLabel>
{makerRole === `lender` && (
<Inputs
bZx={bZx}
tokens={tokens}
fillOrderAmount={this.state.fillOrderAmount}
collateralTokenAddress={this.state.collateralTokenAddress}
loanTokenAddress={order.loanTokenAddress}
setFillOrderAmount={this.setStateFor(`fillOrderAmount`)}
setCollateralTokenAddress={this.setCollateralTokenAddress}
collateralTokenAmount={this.state.collateralTokenAmount}
collateralRefresh={this.refreshCollateralAmount}
setOverCollateralize={this.setOverCollateralize}
overCollateralize={this.state.overCollateralize}
/>
)}
<SubmitBtn
variant="raised"
color="primary"
onClick={this.handleSubmit}
disabled={this.state.isSubmitted}
>
{this.state.isSubmitted ? `Please Wait` : `Fill Order`}
</SubmitBtn>
</Fragment>
)}
</Section>
</Fragment>
) : (
<Fragment>
<Section>
<p>
This order is completely filled or cancelled. There is no loan token
remaining.
</p>
</Section>
</Fragment>
)}
</Fragment>
);
}
}