Skip to content

Commit

Permalink
581 market fees (cryptonomex#665)
Browse files Browse the repository at this point in the history
* Update version #

* Fix cryptonomex#498: Keep scrollbars visible, restore perfect scrollbar to main exchange div

* Fix cryptonomex#589: Openledger deposit address shown as unknown

* Only store valid deposit addresses cryptonomex#589

* Fix setting of max_market_fee in asset create/update

* First pass at showing market fees in exchange cryptonomex#581

* Add a tooltip explaining the market fee
  • Loading branch information
svk31 authored Oct 30, 2017
1 parent 673bfce commit 210b944
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 29 deletions.
3 changes: 2 additions & 1 deletion app/assets/locales/locale-en.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@
"copy_password": "Click here to copy the password to your clipboard",
"sync_yes": "The current node is in sync with the blockchain",
"sync_no": "The current node is out of sync with the blockchain, try switching to another one",
"disconnected": "You are not connected to an API node, try reloading or setting a new access point in the Settings"
"disconnected": "You are not connected to an API node, try reloading or setting a new access point in the Settings",
"market_fee": "The owner of %(asset)s charges a market fee of %(percent)s%% for buy orders. This fee will be subtracted from the amount you receive when your order fills, it is not paid when placing an order."
},
"propose": "Propose",
"cancel": "Cancel",
Expand Down
2 changes: 1 addition & 1 deletion app/assets/stylesheets/vendors/_perfect-scrollbar.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
display: none;
position: absolute;
/* please don't change 'position' */
opacity: 0;
opacity: 0.6;
-webkit-transition: background-color .2s linear, opacity .2s linear;
-o-transition: background-color .2s linear, opacity .2s linear;
-moz-transition: background-color .2s linear, opacity .2s linear;
Expand Down
2 changes: 1 addition & 1 deletion app/components/Account/AccountAssetCreate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ class AccountAssetCreate extends React.Component {
break;

case "max_market_fee":
if ((new big(inputValue)).times(Math.pow(10, precision)).gt(GRAPHENE_MAX_SHARE_SUPPLY)) {
if ((new big(inputValue)).times(precision).gt(GRAPHENE_MAX_SHARE_SUPPLY)) {
errors.max_market_fee = "The number you tried to enter is too large";
return this.setState({errors});
}
Expand Down
2 changes: 1 addition & 1 deletion app/components/Account/AccountAssetUpdate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ class AccountAssetUpdate extends React.Component {

case "max_market_fee":
let marketFee = e.amount.replace(/,/g, "");
if ((new big(marketFee)).times(Math.pow(10, precision)).gt(GRAPHENE_MAX_SHARE_SUPPLY)) {
if ((new big(marketFee)).times(precision).gt(GRAPHENE_MAX_SHARE_SUPPLY)) {
updateState = false;
return this.setState({errors: {max_market_fee: "The number you tried to enter is too large"}});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ class BlockTradesBridgeDepositRequest extends React.Component {
let conversion_limit = this.getCachedOrFreshDepositLimit("conversion", conversion_input_coin_type, conversion_output_coin_type);

if (this.unMounted) return;

this.setState({
coin_info_request_state: this.coin_info_request_states.request_complete,
coins_by_type: coins_by_type,
Expand Down Expand Up @@ -719,14 +719,21 @@ class BlockTradesBridgeDepositRequest extends React.Component {
// functions for managing input addresses
getCachedInputAddress(input_coin_type, output_coin_type, memo)
{
let account_name = this.props.account.get('name');
let account_name = this.props.account.get("name");
return this.deposit_address_cache.getCachedInputAddress(this.props.gateway, account_name, input_coin_type, output_coin_type);
}

cacheInputAddress(input_coin_type, output_coin_type, address, memo)
{
let account_name = this.props.account.get('name');
this.deposit_address_cache.cacheInputAddress(this.props.gateway, account_name, input_coin_type, output_coin_type, address, memo);
let account_name = this.props.account.get("name");
this.deposit_address_cache.cacheInputAddress(
this.props.gateway,
account_name,
input_coin_type,
output_coin_type,
address,
memo
);
}

getCachedOrGeneratedInputAddress(input_coin_type, output_coin_type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,10 @@ class BlockTradesGatewayDepositRequest extends React.Component {
componentWillMount() {
let account_name = this.props.account.get("name");
let receive_address = this.deposit_address_cache.getCachedInputAddress(this.props.gateway, account_name, this.props.deposit_coin_type, this.props.receive_coin_type);
if (!receive_address) {
if (!receive_address || receive_address.address === "unknown") {
requestDepositAddress(this._getDepositObject());
} else {
this.setState({receive_address});
}
}

Expand All @@ -89,7 +91,14 @@ class BlockTradesGatewayDepositRequest extends React.Component {

addDepositAddress( receive_address ) {
let account_name = this.props.account.get("name");
this.deposit_address_cache.cacheInputAddress(this.props.gateway, account_name, this.props.deposit_coin_type, this.props.receive_coin_type, receive_address.address, receive_address.memo);
this.deposit_address_cache.cacheInputAddress(
this.props.gateway,
account_name,
this.props.deposit_coin_type,
this.props.receive_coin_type,
receive_address.address,
receive_address.memo
);
this.setState( {receive_address} );
}

Expand All @@ -114,7 +123,7 @@ class BlockTradesGatewayDepositRequest extends React.Component {
}

render() {

const isDeposit = this.props.action === "deposit";
let emptyRow = <div style={{display:"none", minHeight: 150}}></div>;
if( !this.props.account || !this.props.issuer_account || !this.props.receive_asset )
return emptyRow;
Expand Down Expand Up @@ -158,7 +167,7 @@ class BlockTradesGatewayDepositRequest extends React.Component {
receive_address = this.deposit_address_cache.getCachedInputAddress(this.props.gateway, account_name, this.props.deposit_coin_type, this.props.receive_coin_type);
}

if( !receive_address ) {
if( !receive_address) {
requestDepositAddress(this._getDepositObject());
return <div style={{margin: "3rem"}}><LoadingIndicator type="three-bounce"/></div>;
}
Expand Down Expand Up @@ -200,11 +209,11 @@ class BlockTradesGatewayDepositRequest extends React.Component {
var withdraw_memo_prefix = "";
}

if (!this.props.isAvailable) {
if (!this.props.isAvailable || (isDeposit && !this.props.deposit_account && !this.state.receive_address)) {
return <div><Translate className="txtlabel cancel" content="gateway.unavailable" component="h4" /></div>;
}

if (this.props.action === "deposit") {
if (isDeposit) {
return (
<div className="Blocktrades__gateway grid-block no-padding no-margin">
<div className="small-12 medium-5">
Expand Down
87 changes: 87 additions & 0 deletions app/components/Exchange/BuySell.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import SimpleDepositWithdraw from "../Dashboard/SimpleDepositWithdraw";
import SimpleDepositBlocktradesBridge from "../Dashboard/SimpleDepositBlocktradesBridge";
import {Asset} from "common/MarketClasses";
import ExchangeInput from "./ExchangeInput";
import assetUtils from "common/asset_utils";
import Icon from "../Icon/Icon";

class BuySell extends React.Component {

Expand Down Expand Up @@ -80,10 +82,93 @@ class BuySell extends React.Component {
if (this.props.total) total = this.props.total;

let balanceAmount = new Asset({amount: balance ? balance.get("balance") : 0, precision: balancePrecision, asset_id: this.props.balanceId});

const maxBaseMarketFee = new Asset({
amount: base.getIn(["options", "max_market_fee"]),
asset_id: base.get("asset_id"),
precision: base.get("precision")
});
const maxQuoteMarketFee = new Asset({
amount: quote.getIn(["options", "max_market_fee"]),
asset_id: quote.get("asset_id"),
precision: quote.get("precision")
});
const quoteFee = !amount ? 0 : Math.min(maxQuoteMarketFee.getAmount({real: true}), amount * quote.getIn(["options", "market_fee_percent"]) / 10000);
const baseFee = !amount ? 0 : Math.min(maxBaseMarketFee.getAmount({real: true}), total * base.getIn(["options", "market_fee_percent"]) / 10000);
const baseFlagBooleans = assetUtils.getFlagBooleans(base.getIn(["options", "flags"]), base.has("bitasset_data_id"));
const quoteFlagBooleans = assetUtils.getFlagBooleans(quote.getIn(["options", "flags"]), quote.has("bitasset_data_id"));


const hasMarketFee = baseFlagBooleans["charge_market_fee"] || quoteFlagBooleans["charge_market_fee"];
var baseMarketFee = baseFlagBooleans["charge_market_fee"] ? (
<div className="grid-block no-padding buy-sell-row">
<div className="grid-block small-3 no-margin no-overflow buy-sell-label">
<Translate content="explorer.asset.summary.market_fee" />:
</div>
<div className="grid-block small-5 no-margin no-overflow buy-sell-input">
<input disabled type="text" id="baseMarketFee" value={baseFee} autoComplete="off"/>
</div>
<div className="grid-block small-4 no-margin no-overflow buy-sell-box">
<AssetName noTip name={base.get("symbol")} />
<span
data-tip={counterpart.translate(
"tooltip.market_fee",
{
percent: base.getIn(["options", "market_fee_percent"]) / 100,
asset: base.get("symbol")
}
)
}
className="inline-block tooltip"
>
&nbsp;<Icon style={{position: "relative", top: 3}} name="question-circle" />
</span>
</div>
</div>
) : hasMarketFee ?
<div className="grid-block no-padding buy-sell-row">
<div style={{visibility: "hidden"}} className="grid-block small-3 no-margin no-overflow buy-sell-label">
<Translate content="explorer.asset.summary.market_fee" />:
</div>
</div> : null;
var quoteMarketFee = quoteFlagBooleans["charge_market_fee"] ? (
<div className="grid-block no-padding buy-sell-row">
<div className="grid-block small-3 no-margin no-overflow buy-sell-label">
<Translate content="explorer.asset.summary.market_fee" />:
</div>
<div className="grid-block small-5 no-margin no-overflow buy-sell-input">
<input disabled type="text" id="baseMarketFee" value={quoteFee} autoComplete="off"/>
</div>
<div className="grid-block small-4 no-margin no-overflow buy-sell-box">
<AssetName noTip name={quote.get("symbol")} />
<span
data-tip={counterpart.translate(
"tooltip.market_fee",
{
percent: quote.getIn(["options", "market_fee_percent"]) / 100,
asset: quote.get("symbol")
}
)
}
className="inline-block tooltip"
>
&nbsp;<Icon style={{position: "relative", top: 3}} name="question-circle" />
</span>
</div>
</div>
) : hasMarketFee ?
<div className="grid-block no-padding buy-sell-row">
<div style={{visibility: "hidden"}} className="grid-block small-3 no-margin no-overflow buy-sell-label">
<Translate content="explorer.asset.summary.market_fee" />:
</div>
</div> : null;

// if (!balanceAmount) {
// balanceAmount = 0;
// }
const isBid = type === "bid";
let marketFee = isBid && quoteMarketFee ? quoteMarketFee : !isBid && baseMarketFee ? baseMarketFee : null;
console.log("isBid", isBid, "quoteMarketFee", !!quoteMarketFee, "baseMarketFee", !!baseMarketFee);
let hasBalance = isBid ? balanceAmount.getAmount({real: true}) >= parseFloat(total) : balanceAmount.getAmount({real: true}) >= parseFloat(amount);

let buttonText = isPredictionMarket ? counterpart.translate("exchange.short") : isBid ? counterpart.translate("exchange.buy") : counterpart.translate("exchange.sell");
Expand Down Expand Up @@ -201,6 +286,8 @@ class BuySell extends React.Component {
</select>
</div>
</div>

{marketFee}
</div>
<div>
<div className="grid-content clear-fix no-padding">
Expand Down
18 changes: 13 additions & 5 deletions app/components/Exchange/Exchange.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class Exchange extends React.Component {

this._getWindowSize = debounce(this._getWindowSize.bind(this), 150);
this._checkFeeStatus = this._checkFeeStatus.bind(this);
this.psInit = true;
}

_initialState(props) {
Expand Down Expand Up @@ -148,10 +149,6 @@ class Exchange extends React.Component {
}

componentDidMount() {
let centerContainer = this.refs.center;
if (centerContainer) {
Ps.initialize(centerContainer);
}
SettingsActions.changeViewSetting.defer({
[this._getLastMarketKey()]: this.props.quoteAsset.get("symbol") + "_" + this.props.baseAsset.get("symbol")
});
Expand Down Expand Up @@ -191,10 +188,21 @@ class Exchange extends React.Component {
height: innerHeight,
width: innerWidth
});
let centerContainer = this.refs.center;
if (centerContainer) {
Ps.update(centerContainer);
}
}
}

componentWillReceiveProps(nextProps) {
if (this.refs.center && this.psInit) {
let centerContainer = this.refs.center;
if (centerContainer) {
Ps.initialize(centerContainer);
this.psInit = false;
}
}
if (
nextProps.quoteAsset !== this.props.quoteAsset ||
nextProps.baseAsset !== this.props.baseAsset ||
Expand Down Expand Up @@ -1128,7 +1136,7 @@ class Exchange extends React.Component {
showVolumeChart={showVolumeChart}
/>

<div className="grid-block vertical no-padding" id="CenterContent" ref="center">
<div className="grid-block vertical no-padding ps-container" id="CenterContent" ref="center">
{!showDepthChart ? (
<div className="grid-block shrink no-overflow" id="market-charts" >
{/* Price history chart */}
Expand Down
20 changes: 12 additions & 8 deletions app/components/Exchange/OrderBook.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,12 @@ class OrderBook extends React.Component {
<span> (<AssetName name={quoteSymbol} />)</span>
</div>
</div>
<table className="table order-table table-hover fixed-table text-right">
{!this.state.flip ? rightHeader : leftHeader}
</table>
<div className="grid-block" ref="hor_asks" style={{paddingRight: !showAllAsks ? 0 : 15, overflow: "hidden", maxHeight: 210}}>
<div style={{paddingRight: "0.6rem"}}>
<table className="table order-table table-hover fixed-table text-right">
{!this.state.flip ? rightHeader : leftHeader}
</table>
</div>
<div className="grid-block" ref="hor_asks" style={{paddingRight: "0.6rem", overflow: "hidden", maxHeight: 210}}>
<table style={{paddingBottom: 5}} className="table order-table table-hover fixed-table text-right no-overflow">
<TransitionWrapper
ref="askTransition"
Expand Down Expand Up @@ -442,10 +444,12 @@ class OrderBook extends React.Component {
<span> (<AssetName name={baseSymbol} />)</span>
</div>
</div>
<table className="table order-table table-hover fixed-table text-right">
{this.state.flip ? rightHeader : leftHeader}
</table>
<div className="grid-block" ref="hor_bids" style={{paddingRight: !showAllBids ? 0 : 15, overflow: "hidden", maxHeight: 210}}>
<div style={{paddingRight: "0.6rem"}}>
<table className="table order-table table-hover fixed-table text-right">
{this.state.flip ? rightHeader : leftHeader}
</table>
</div>
<div className="grid-block" ref="hor_bids" style={{paddingRight: "0.6rem", overflow: "hidden", maxHeight: 210}}>
<table style={{paddingBottom: 5}} className="table order-table table-hover fixed-table text-right no-overflow">
<TransitionWrapper
ref="bidTransition"
Expand Down
1 change: 1 addition & 0 deletions app/lib/common/BlockTradesDepositAddressCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class BlockTradesDepositAddressCache {

cacheInputAddress(exchange_name, account_name, input_coin_type, output_coin_type, address, memo)
{
if (!address) return;
let wallet = WalletDb.getWallet();
wallet = null;

Expand Down
4 changes: 2 additions & 2 deletions app/lib/common/blockTradesMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ export function requestDepositAddress({inputCoinType, outputCoinType, outputAddr
}, error => {
// console.log( "error: ",error );
delete depositRequests[body_string];
if (stateCallback) stateCallback({"address": "unknown", "memo": null});
if (stateCallback) stateCallback(null);
});
}, error => {
// console.log( "error: ",error );
delete depositRequests[body_string];
if (stateCallback) stateCallback({"address": "unknown", "memo": null});
if (stateCallback) stateCallback(null);
}).catch(err => {
console.log("fetch error:", err);
delete depositRequests[body_string];
Expand Down

0 comments on commit 210b944

Please sign in to comment.