Skip to content

Commit

Permalink
Merge pull request #1350 from madfish-solutions/v3.3.7
Browse files Browse the repository at this point in the history
V3.3.7
  • Loading branch information
keshan3262 authored Mar 2, 2023
2 parents 375c696 + a232985 commit b713817
Show file tree
Hide file tree
Showing 146 changed files with 2,115 additions and 959 deletions.
2 changes: 2 additions & 0 deletions .env.ghostnet.pord
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ REACT_APP_TTDEX_CONTRACT=KT1PnmpVWmA5CBUsA5ZAx1HoDW67mPYurAL5
REACT_APP_FARMING_CONTRACT=KT1HXQcPhPtVWiU64X4WZG9dmRBhBAkAEfT1
REACT_APP_COINFLIP_CONTRACT=KT1LYJif66XPDGgvUZdnmdyorjEYHkT9pTs5
REACT_APP_STABLESWAP_FACTORY_CONTRACT_ADDRESS=KT1GjgXdwaMjjwXcS2JURcMA53WRq9qW1nZF
REACT_APP_STABLESWAP_V2_FACTORY_ADDRESS=KT1KpS2yAfw9TYvsDWjc6AAEHNaEMNbjcMH4
REACT_APP_DEX_TWO_CONTRACT_ADDRESS=KT1GPJDTf8GZspCcanaG2KhMvGu3NJRqurat
REACT_APP_DEX_V3_FACTORY_ADDRESS=KT1RxBqWNcvWKcrVZWKS7PtjtPXfpnAkBHpF

#network and mode depends
Expand Down
1 change: 1 addition & 0 deletions .env.ghostnet.stage
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ REACT_APP_TTDEX_CONTRACT=KT1PnmpVWmA5CBUsA5ZAx1HoDW67mPYurAL5
REACT_APP_FARMING_CONTRACT=KT1HXQcPhPtVWiU64X4WZG9dmRBhBAkAEfT1
REACT_APP_COINFLIP_CONTRACT=KT1LYJif66XPDGgvUZdnmdyorjEYHkT9pTs5
REACT_APP_STABLESWAP_FACTORY_CONTRACT_ADDRESS=KT1GjgXdwaMjjwXcS2JURcMA53WRq9qW1nZF
REACT_APP_STABLESWAP_V2_FACTORY_ADDRESS=KT1KpS2yAfw9TYvsDWjc6AAEHNaEMNbjcMH4
REACT_APP_DEX_TWO_CONTRACT_ADDRESS=KT1GPJDTf8GZspCcanaG2KhMvGu3NJRqurat
REACT_APP_DEX_V3_FACTORY_ADDRESS=KT1RxBqWNcvWKcrVZWKS7PtjtPXfpnAkBHpF

Expand Down
3 changes: 3 additions & 0 deletions .env.mainnet.prod
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ REACT_APP_POOLS_URL=wss://dexes-api-mainnet.prod.templewallet.com/
REACT_APP_FARMING_API_URL=https://staking-api-mainnet.prod.quipuswap.com
REACT_APP_STABLESWAP_API_URL=https://stableswap-api-mainnet.prod.quipuswap.com
REACT_APP_LIQUIDITY_API_URL=https://liquidity-api-mainnet.prod.quipuswap.com
REACT_APP_THREE_ROUTE_API_URL=https://quipuswap.3route.io
REACT_APP_THREE_ROUTE_API_AUTH_TOKEN=***REMOVED***
REACT_APP_THREE_ROUTE_CONTRACT_ADDRESS=KT1Tuta6vbpHhZ15ixsYD3qJdhnpEAuogLQ9

#sentry
REACT_APP_SENTRY_DSN=***REMOVED***
Expand Down
3 changes: 3 additions & 0 deletions .env.mainnet.stage
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ REACT_APP_POOLS_URL=wss://dexes-api-mainnet.stage.madfish.xyz/
REACT_APP_FARMING_API_URL=https://staking-api-mainnet.stage.madfish.xyz
REACT_APP_STABLESWAP_API_URL=https://stableswap-api-mainnet.stage.madfish.xyz
REACT_APP_LIQUIDITY_API_URL=https://liquidity-api-mainnet.stage.madfish.xyz
REACT_APP_THREE_ROUTE_API_URL=https://quipuswap.3route.io
REACT_APP_THREE_ROUTE_API_AUTH_TOKEN=***REMOVED***
REACT_APP_THREE_ROUTE_CONTRACT_ADDRESS=KT1Tuta6vbpHhZ15ixsYD3qJdhnpEAuogLQ9

#TZKT
REACT_APP_TZKT_API=https://api.ghostnet.tzkt.io/v1
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "quipuswap-webapp-2",
"version": "3.3.6",
"version": "3.3.7",
"private": true,
"scripts": {
"pre-build": "node -v && npm -v && yarn -v && node ./scripts/build.js",
Expand All @@ -25,7 +25,7 @@
"@craco/craco": "^6.4.3",
"@percy/cli": "^1.7.2",
"@quipuswap/sdk": "^3.0.3",
"@quipuswap/tokens-whitelist": "^1.1.12",
"@quipuswap/tokens-whitelist": "^1.1.13",
"@sentry/react": "^7.11.1",
"@sentry/tracing": "^7.11.1",
"@taquito/beacon-wallet": "15.0.1",
Expand Down
9 changes: 8 additions & 1 deletion src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import MainnetWhitelistTokens from '@quipuswap/tokens-whitelist/tokens/quipuswap

import { FarmVersion } from '@modules/farming/interfaces';
import { PoolType } from '@modules/liquidity/interfaces';
import { isExist } from '@shared/helpers/type-checks';
import { ConnectType, QSNetwork, QSNetworkType, SupportedNetworks } from '@shared/types';

import { NETWORK_ID, TEMPLEWALLET_API_URL, TZKT_API } from './environment';
import { NETWORK_ID, STABLESWAP_V2_FACTORY_ADDRESS, TEMPLEWALLET_API_URL, TZKT_API } from './environment';

export const QUIPUSWAP_DOMAIN_NAME = 'quipuswap.com';

Expand Down Expand Up @@ -131,3 +132,9 @@ export const HOT_POOLS: Array<{ id: string; type: PoolType }> = [
// Coinflip
export const COINFLIP_CONTRACT_DECIMALS = 18;
export const COINFLIP_TOKEN_DECIMALS = 6;

// 3route
export const THREE_ROUTE_APP_ID = 3;

// Stableswap
export const STABLESWAP_V2_IS_AVAILABLE = isExist(STABLESWAP_V2_FACTORY_ADDRESS);
3 changes: 3 additions & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ export const USD_DECIMALS = 2;

export const MAX_ITEMS_PER_PAGE = 5;
export const MAX_HOPS_COUNT = 3;
export const PRICE_IMPACT_WARNING_THRESHOLD = 10;

export const DATA_TEST_ID_PROP_NAME = 'data-test-id';

export const NO_WITHDRAWAL_FEE_VALUE = 0;

Expand Down
4 changes: 4 additions & 0 deletions src/config/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,14 @@ export const COINFLIP_CONTRACT_ADDRESS = process.env.REACT_APP_COINFLIP_CONTRACT
export const DEX_TWO_CONTRACT_ADDRESS = process.env.REACT_APP_DEX_TWO_CONTRACT_ADDRESS!;
export const DEX_V3_FACTORY_ADDRESS = process.env.REACT_APP_DEX_V3_FACTORY_ADDRESS!;
export const STABLESWAP_FACTORY_CONTRACT_ADDRESS = process.env.REACT_APP_STABLESWAP_FACTORY_CONTRACT_ADDRESS!;
export const STABLESWAP_V2_FACTORY_ADDRESS = process.env.REACT_APP_STABLESWAP_V2_FACTORY_ADDRESS;

export const TEMPLEWALLET_API_URL = process.env.REACT_APP_TEMPLEWALLET_API_URL!;
export const METADATA_API = process.env.REACT_APP_METADATA_API_URL!;
export const DEX_POOL_URL = process.env.REACT_APP_POOLS_URL!;
export const THREE_ROUTE_API_URL = process.env.REACT_APP_THREE_ROUTE_API_URL;
export const THREE_ROUTE_API_AUTH_TOKEN = process.env.REACT_APP_THREE_ROUTE_API_AUTH_TOKEN;
export const THREE_ROUTE_CONTRACT_ADDRESS = process.env.REACT_APP_THREE_ROUTE_CONTRACT_ADDRESS;

export const FARMING_API_URL = process.env.REACT_APP_FARMING_API_URL!;
export const STABLESWAP_API_URL = process.env.REACT_APP_STABLESWAP_API_URL!;
Expand Down
Binary file added src/images/create-new-stable-pool-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/create-new-stable-pool-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 2 additions & 3 deletions src/modules/farming/api/backend/youves-farming.api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FARMING_ITEM_API_URL_V2, FARMING_ITEM_API_URL_V3 } from '@config/constants';
import { jsonFetch } from '@shared/api';

import { FarmVersion } from '../../interfaces';

Expand All @@ -16,8 +17,6 @@ export class BackendYouvesFarmingApi {
}
}
static async getYouvesFarmingItem(id: string, version: FarmVersion) {
const youvesFarmRaw = await fetch(`${this.getFarmItemUrl(version)}/${id}`);

return await youvesFarmRaw.json();
return await jsonFetch(`${this.getFarmItemUrl(version)}/${id}`);
}
}
5 changes: 2 additions & 3 deletions src/modules/farming/api/get-farming-item.api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FARMING_LIST_API_URL, FARMING_LIST_API_URL_V2, FARMING_LIST_API_URL_V3 } from '@config/constants';
import { jsonFetch } from '@shared/api';
import { Nullable } from '@shared/types';

import { FarmingItemResponse, FarmVersion } from '../interfaces';
Expand All @@ -24,7 +25,5 @@ export const getFarmingItemApi = async (farmingId: Nullable<string>, version: Fa
throw new Error('Failed to get nullable farmingId');
}

const response = await fetch(`${getUrl(version, old)}/${farmingId}`);

return (await response.json()) as FarmingItemResponse;
return await jsonFetch<FarmingItemResponse>(`${getUrl(version, old)}/${farmingId}`);
};
7 changes: 2 additions & 5 deletions src/modules/farming/api/get-farming-list-common.api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import { FARMING_COMMON_LIST_API_URL } from '@config/constants';
import { jsonFetch } from '@shared/api';

export const getFarmingListCommonApi = async () => {
const farmingListCommonRaw = await fetch(FARMING_COMMON_LIST_API_URL);

return await farmingListCommonRaw.json();
};
export const getFarmingListCommonApi = async () => await jsonFetch(FARMING_COMMON_LIST_API_URL);
7 changes: 2 additions & 5 deletions src/modules/farming/api/get-farming-stats.api.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { FARMING_STATS_API_URL } from '@config/constants';
import { jsonFetch } from '@shared/api';

import { FarmingStatsResponse } from '../interfaces';

export const getFarmingStatsApi = async () => {
const response = await fetch(FARMING_STATS_API_URL);

return (await response.json()) as FarmingStatsResponse;
};
export const getFarmingStatsApi = async () => await jsonFetch<FarmingStatsResponse>(FARMING_STATS_API_URL);
2 changes: 1 addition & 1 deletion src/modules/farming/hooks/blockchain/use-do-harvest-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const useDoHarvestAll = () => {
defined(rootStore.authStore.accountPkh)
);

await confirmOperation(operation.opHash, { message: t('farm|Stake successful') });
await confirmOperation(operation.opHash, { message: t('farm|Harvest successful') });
amplitudeService.logEvent('HARVEST_ALL_SUCCESS', logData);
} catch (error) {
showErrorToast(error as Error);
Expand Down
15 changes: 6 additions & 9 deletions src/modules/farming/hooks/loaders/use-get-youves-farming-item.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { useCallback } from 'react';

import { useNavigate } from 'react-router-dom';

import { AppRootRoutes } from '@app.router';
import { DELAY_BEFORE_DATA_UPDATE } from '@config/constants';
import { useReady } from '@providers/use-dapp';
import { isExist, isNotFoundError, sleep } from '@shared/helpers';
import { isExist, sleep } from '@shared/helpers';
import { Optional } from '@shared/types';
import { useToasts } from '@shared/utils';

Expand All @@ -16,10 +13,10 @@ export const useGetYouvesFarmingItem = () => {
const { showErrorToast } = useToasts();
const farmingYouvesItemStore = useFarmingYouvesItemStore();
const isReady = useReady();
const navigate = useNavigate();

const getFarmingItem = useCallback(
async (id: Optional<string>, version: FarmVersion) => {
let itemStoreWasLoaded = false;
try {
if (!isReady || !isExist(id)) {
return;
Expand All @@ -28,17 +25,17 @@ export const useGetYouvesFarmingItem = () => {
farmingYouvesItemStore.setFarmingId(id);
farmingYouvesItemStore.setFarmingVersion(version);
await farmingYouvesItemStore.itemStore.load();
itemStoreWasLoaded = true;
await farmingYouvesItemStore.stakesStore.load();
await farmingYouvesItemStore.contractBalanceStore.load();
await farmingYouvesItemStore.updatePendingRewards();
} catch (error) {
showErrorToast(error as Error);
if (isNotFoundError(error as Error)) {
navigate(`${AppRootRoutes.NotFound}/${id}`);
if (itemStoreWasLoaded) {
showErrorToast(error as Error);
}
}
},
[isReady, showErrorToast, farmingYouvesItemStore, navigate]
[isReady, showErrorToast, farmingYouvesItemStore]
);

const delayedGetFarmingItem = useCallback(
Expand Down
11 changes: 7 additions & 4 deletions src/modules/farming/pages/item/use-farming-item-page.vm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { useFarmingItemStore } from '@modules/farming/hooks';
import { useGetFarmingItem } from '@modules/farming/hooks/loaders/use-get-farming-item';
import { useAccountPkh, useReady } from '@providers/use-dapp';
import { DashPlug } from '@shared/components';
import { getTokensNames, isNull, isUndefined, useRedirectionCallback } from '@shared/helpers';
import { getTokensNames, isNotFoundError, isNull, isUndefined, useRedirectionCallback } from '@shared/helpers';
import { useToasts } from '@shared/utils';
import { useTranslation } from '@translation';

import { FarmVersion } from '../../interfaces';
Expand All @@ -21,6 +22,7 @@ export const useFarmingItemPageViewModel = () => {
const { getFarmingItem } = useGetFarmingItem();
const accountPkh = useAccountPkh();
const { id: rawStakeId } = useParams();
const { showErrorToast } = useToasts();
const redirectToNotFoundPage = useRedirectionCallback(makeNotFoundPageUrl);

/*
Expand Down Expand Up @@ -59,11 +61,12 @@ export const useFarmingItemPageViewModel = () => {
const isLoading = dataLoading || !dataInitialized || !dAppReady;

useEffect(() => {
// TODO: https://madfish.atlassian.net/browse/QUIPU-701
if (itemApiError) {
if (itemApiError && isNotFoundError(itemApiError)) {
redirectToNotFoundPage();
} else if (itemApiError) {
showErrorToast(itemApiError);
}
}, [itemApiError, redirectToNotFoundPage]);
}, [itemApiError, redirectToNotFoundPage, showErrorToast]);

const getTitle = () => {
if (farmingItem) {
Expand Down
17 changes: 14 additions & 3 deletions src/modules/farming/pages/youves-item/use-youves-item-page.vm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,17 @@ import { useParams } from 'react-router-dom';
import { useFarmingYouvesItemStore } from '@modules/farming/hooks';
import { useGetYouvesFarmingItem } from '@modules/farming/hooks/loaders/use-get-youves-farming-item';
import { useReady } from '@providers/use-dapp';
import { getTokensNames, isEmptyArray, isNull, isUndefined, useRedirectionCallback } from '@shared/helpers';
import {
getTokensNames,
isEmptyArray,
isNotFoundError,
isNull,
isUndefined,
useRedirectionCallback
} from '@shared/helpers';
import { useAuthStore } from '@shared/hooks';
import { Nullable, Token } from '@shared/types';
import { useToasts } from '@shared/utils';
import { useTranslation } from '@translation';

import { makeNotFoundPageUrl, mapFarmVersion } from '../../helpers';
Expand All @@ -21,6 +29,7 @@ export const useYouvesItemPageViewModel = (): { title: string } => {
const prevAccountPkhRef = useRef<Nullable<string>>(accountPkh);

const { id, version } = useParams();
const { showErrorToast } = useToasts();
const redirectToNotFoundPage = useRedirectionCallback(makeNotFoundPageUrl);

const { getFarmingItem } = useGetYouvesFarmingItem();
Expand All @@ -41,10 +50,12 @@ export const useYouvesItemPageViewModel = (): { title: string } => {
}, [getFarmingItem, dAppReady, id, version, accountPkh]);

useEffect(() => {
if (itemApiError) {
if (itemApiError && isNotFoundError(itemApiError)) {
redirectToNotFoundPage();
} else if (itemApiError) {
showErrorToast(itemApiError);
}
}, [itemApiError, redirectToNotFoundPage]);
}, [itemApiError, redirectToNotFoundPage, showErrorToast]);

/*
Liveable Rewards.
Expand Down
8 changes: 3 additions & 5 deletions src/modules/liquidity/api/blockchain/v3-liquidity-pool.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from '@config/constants';
import { DEX_V3_FACTORY_ADDRESS } from '@config/environment';
import { WTEZ_TOKEN } from '@config/tokens';
import { jsonFetch } from '@shared/api';
import { getContract, getStorageInfo } from '@shared/dapp';
import {
bigNumberToString,
Expand Down Expand Up @@ -97,11 +98,8 @@ export namespace V3LiquidityPoolApi {
};
};

export const getLiquidityV3Item = async (id: BigNumber) => {
const response = await fetch(`${LIQUIDITY_V3_ITEM_API_URL}/${id.toFixed()}`);

return await response.json();
};
export const getLiquidityV3Item = async (id: BigNumber) =>
await jsonFetch(`${LIQUIDITY_V3_ITEM_API_URL}/${id.toFixed()}`);

export const claimFees = async (
tezos: TezosToolkit,
Expand Down
5 changes: 2 additions & 3 deletions src/modules/liquidity/api/get-dex-two-liquidity-item.api.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { LIQUIDITY_DEX_TWO_ITEM_API_URL } from '@config/constants';
import { jsonFetch } from '@shared/api';

export const getDexTwoLiquidityItemApi = async (tokenPairSlug: string) => {
if (!tokenPairSlug) {
throw Error('tokenPairSlug is required');
}

const response = await fetch(`${LIQUIDITY_DEX_TWO_ITEM_API_URL}/${tokenPairSlug}`);

return await response.json();
return await jsonFetch(`${LIQUIDITY_DEX_TWO_ITEM_API_URL}/${tokenPairSlug}`);
};
8 changes: 3 additions & 5 deletions src/modules/liquidity/api/get-liquidity-list.api.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { LIQUIDITY_LIST_API_URL } from '@config/constants';
import { jsonFetch } from '@shared/api';

import { LiquidityItemResponse } from '../interfaces';

export const getLiquidityListApi = async (): Promise<{ list: Array<LiquidityItemResponse> }> => {
const response = await fetch(LIQUIDITY_LIST_API_URL);

return (await response.json()) as { list: Array<LiquidityItemResponse> };
};
export const getLiquidityListApi = async () =>
await jsonFetch<{ list: Array<LiquidityItemResponse> }>(LIQUIDITY_LIST_API_URL);
7 changes: 2 additions & 5 deletions src/modules/liquidity/api/get-liquidity-stats.api.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { LIQUIDITY_STATS_API_URL } from '@config/constants';
import { jsonFetch } from '@shared/api';

import { NewLiquidityStatsResponse } from '../types';

export const getLiquidityStatsApi = async () => {
const response = await fetch(LIQUIDITY_STATS_API_URL);

return (await response.json()) as NewLiquidityStatsResponse;
};
export const getLiquidityStatsApi = async () => await jsonFetch<NewLiquidityStatsResponse>(LIQUIDITY_STATS_API_URL);
31 changes: 18 additions & 13 deletions src/modules/liquidity/helpers/filter.helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,27 @@ import { BigNumber } from 'bignumber.js';
import { getTokenSlug, isExist } from '@shared/helpers';
import { Nullable, Token } from '@shared/types';

import { Categories } from '../interfaces';
import { PoolType, PoolTypeOptionEnum } from '../interfaces';
import { LiquidityItemModel } from '../models';

const filterByCategory =
(enable: boolean, category: Categories) =>
const poolTypesByOptions = {
[PoolTypeOptionEnum.ALL]: [
PoolType.TEZ_TOKEN,
PoolType.TOKEN_TOKEN,
PoolType.DEX_TWO,
PoolType.UNISWAP,
PoolType.STABLESWAP
],
[PoolTypeOptionEnum.V1]: [PoolType.TOKEN_TOKEN, PoolType.TEZ_TOKEN],
[PoolTypeOptionEnum.V2]: [PoolType.DEX_TWO],
[PoolTypeOptionEnum.V3]: [PoolType.UNISWAP],
[PoolTypeOptionEnum.STABLESWAP]: [PoolType.STABLESWAP]
};

export const filterByPoolType =
(poolTypeOption: PoolTypeOptionEnum) =>
({ item }: LiquidityItemModel) =>
enable ? item.poolLabels.includes(category) : true;

export const filterByStableSwap = (showStable: boolean) => filterByCategory(showStable, Categories.Stable);
export const filterByBridget = (showBridged: boolean) => filterByCategory(showBridged, Categories.Bridge);
export const filterByQuipu = (showQuipu: boolean) => filterByCategory(showQuipu, Categories.QuipuSwap);
export const filterByTezotopia = (showTezotopia: boolean) => filterByCategory(showTezotopia, Categories.Tezotopia);
export const filterByBTC = (showBTC: boolean) => filterByCategory(showBTC, Categories.BTC);
// TODO Tezotopia -> DexTwo
export const filterByDexTwo = (showDexTwo: boolean) => filterByCategory(showDexTwo, Categories.Tezotopia);
export const filterByV3 = (showDexTwo: boolean) => filterByCategory(showDexTwo, Categories.V3);
poolTypesByOptions[poolTypeOption].includes(item.type);

export const filterByDust =
(showDust: boolean, dustThreshold: BigNumber) =>
Expand Down
1 change: 1 addition & 0 deletions src/modules/liquidity/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './icon-enum';
export * from './liquidity-item.interface';
export * from './liquidity-token-info.interface';
export * from './pool-type-enum';
export * from './pool-type-option-enum';
Loading

0 comments on commit b713817

Please sign in to comment.