Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 5 additions & 8 deletions .env.dev
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@

REACT_APP_COMETA_API_URL='https://api.testnet.cometa.farm/'
REACT_APP_BENEFICIARY_ADDR='3ONHOKYJGYREOUEP52JP7YMZDR77ZHM7B4KOJ3AMPSYOJTINL5W5YOX2HM'
REACT_APP_FARM_CREATION_FEE='200'
REACT_APP_FARM_FLAT_ALGO_CREATION_FEE='5'
REACT_APP_COMETA_API_URL='https://api.cometa.farm/'
REACT_APP_BENEFICIARY_ADDR='METAFG5UBD74CKQFIIABWMMQXR45J7BAP3KV6BVR3V7LDPNAEKNEVLMBRE'
REACT_APP_FARM_CREATION_FEE='100'
REACT_APP_FARM_FLAT_ALGO_CREATION_FEE='100'
REACH_CONNECTOR_MODE=ALGO-browser

# TODO: Make it configurable between deployments/builds (e.g. put it in .env.local and set this as actual env variables in deployments)
ALGO_NETWORK=TestNet
ALGO_NETWORK=MainNet

ALGO_TOKEN=''

Expand All @@ -19,5 +18,3 @@ ALGO_INDEXER_PORT=$ALGO_PORT
ALGO_INDEXER_SERVER="https://${ALGO_NETWORK}-idx.algonode.cloud"

REACT_APP_ALAMMEX_API_KEY='9a1c1fe8-b49a-4d18-b393-4777e557ff74'

API_CONTRACTS_MAX_COUNT=10
23 changes: 23 additions & 0 deletions .env.testnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

REACT_APP_COMETA_API_URL='https://api.testnet.cometa.farm/'
REACT_APP_BENEFICIARY_ADDR='3ONHOKYJGYREOUEP52JP7YMZDR77ZHM7B4KOJ3AMPSYOJTINL5W5YOX2HM'
REACT_APP_FARM_CREATION_FEE='200'
REACT_APP_FARM_FLAT_ALGO_CREATION_FEE='5'
REACH_CONNECTOR_MODE=ALGO-browser

# TODO: Make it configurable between deployments/builds (e.g. put it in .env.local and set this as actual env variables in deployments)
ALGO_NETWORK=TestNet

ALGO_TOKEN=''

ALGO_SERVER="https://${ALGO_NETWORK}-api.algonode.cloud"
ALGO_PORT=443

ALGO_INDEXER_TOKEN=$ALGO_TOKEN

ALGO_INDEXER_PORT=$ALGO_PORT
ALGO_INDEXER_SERVER="https://${ALGO_NETWORK}-idx.algonode.cloud"

REACT_APP_ALAMMEX_API_KEY='9a1c1fe8-b49a-4d18-b393-4777e557ff74'

API_CONTRACTS_MAX_COUNT=10
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"build": "GENERATE_SOURCEMAP=false node scripts/build.js",
"prod": "env-cmd -f .env.prod yarn build",
"dev": "env-cmd -f .env.dev yarn build",
"testnet": "env-cmd -f .env.testnet yarn build",
"test": "node scripts/test.js",
"postinstall": "husky install",
"lint": "xo src",
Expand Down
138 changes: 42 additions & 96 deletions src/Farm/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,28 @@ import { ascend, descend, min, Ord, sort, zip, zipWith } from 'ramda';
import {
Asset,
AssetId,
assetId,
buildContractsStore,
ContractState,
Amount,
Priced,
assetLoaded,
allAssetsLoaded,
registerAsset,
registerPricedAsset,
$algoUsdPrice,
fetchAsset,
ALGO_ASSET,
fetchAlgoPriceFx,
$pricedAssets,
$networkTime,
Contract,
FarmType,
hasLocalState,
Time,
$meanRoundDuration,
$pricedAlgo,
} from '../common/store';
import { getPricedLpInfo, getPricedLpInfos, PricedLpInfo } from '../providers/flexApiProvider';
import { nonConcurrent } from '../common/store/utils';
import { AllDefined, Backend } from '../types';
import { LPTokenInfo, DexProvider, makeDex, PoolInfo } from '../dexes';
import { LPTokenInfo, DexProvider } from '../dexes';
import { fromSmallestUnits, YEAR } from '../common/lib';
import { getLpState } from '../providers/apiProvider';
import { calculateAlgoReward, convertAmountToUSD, getPoolState } from './PoolList/Pool/utils';
import { PoolState } from './PoolList/Pool/types';
import { ColumnType } from './PoolList/PoolList';
Expand All @@ -42,76 +39,36 @@ const FARM_BACKENDS = {
'17.2.5': farmBackend_17_2_5 as Backend,
};

// TODO: this function is a huge costyl
export function detectAssetProvider({ name }: { name: string }): DexProvider {
if (name.includes('TinymanPool2.0')) {
return 'T3';
}
name = name.toLowerCase();
if (name.includes('tinyman')) {
return 'T2';
}
if (name.includes('humble')) {
return 'H2';
}
if (name.includes('liquidity') || name.includes('pact')) {
return 'PT';
}

return 'MOCK';
}

export async function getLPTokenInfoBackend(asset: Asset, provider: DexProvider): Promise<Priced<LPTokenInfo>> {
const lpState = await getLpState(asset.id);
function formatPricedLPInfo(lpInfo: PricedLpInfo, asset: Asset): Priced<LPTokenInfo> {
return {
...asset,
poolId: lpState.id,
asset1: lpState.asset1_id,
asset2: lpState.asset2_id,
poolId: lpInfo.id,
asset1: lpInfo.asset1_id,
asset2: lpInfo.asset2_id,
liquidityAsset: asset.id,
asset1Reserve: BigInt(lpState.asset1_reserve),
asset2Reserve: BigInt(lpState.asset2_reserve),
totalLiquidity: BigInt(lpState.issued_tokens),
poolDex: provider,
dexFeeApr: 0, // TODO
price: lpState.token_price_usd,
priceInAlgo: lpState.token_price,
asset1Reserve: BigInt(lpInfo.asset1_reserve_micros),
asset2Reserve: BigInt(lpInfo.asset2_reserve_micros),
totalLiquidity: BigInt(lpInfo.issued_tokens_micros),
poolDex: lpInfo.dex_provider,
dexFeeApr: lpInfo.swap_fee_apr || 0, // TODO
price: lpInfo.token_price_usd,
priceInAlgo: lpInfo.token_price_algo,
};
}

export async function getLPTokenInfo(
asset: Asset,
algoPrice: number | null,
provider?: DexProvider
): Promise<Priced<LPTokenInfo>> {
if (provider === undefined) {
provider = detectAssetProvider(asset);
}
if (provider === 'PT') {
// Pact pools fix
return await getLPTokenInfoBackend(asset, provider);
}

if (algoPrice === null) {
algoPrice = await fetchAlgoPriceFx();
}
export async function getLPTokenInfoBackend(asset: Asset): Promise<Priced<LPTokenInfo>> {
const lpInfo = await getPricedLpInfo(asset.id);
return formatPricedLPInfo(lpInfo, asset);
}

const dex = makeDex(provider);
const poolInfo = await dex.getPoolByAddress(asset.creator).catch(() => dex.getPoolByAddress(asset.reserve));

const firstAsset = await fetchAsset(poolInfo.asset1);
let fstAssetPrice;
if (poolInfo.asset1 === 0) {
fstAssetPrice = algoPrice;
} else {
const algoPool = await dex.getPoolByAssets(firstAsset, ALGO_ASSET);
const priceInAlgo = (await algoPool.getSwap(firstAsset, BigInt(10 ** firstAsset.decimals), 0.01)).price;
fstAssetPrice = algoPrice * priceInAlgo;
export async function getManyLPInfosBackend(): Promise<Priced<LPTokenInfo>[]> {
const lpInfos = await getPricedLpInfos();
const processedInfos = [];
for (const lpInfo of lpInfos) {
const asset = await fetchAsset(lpInfo.token_id);
processedInfos.push(formatPricedLPInfo(lpInfo, asset));
}
const asset1Reserve = fromSmallestUnits(firstAsset, poolInfo.asset1Reserve);
const totalLiquidity = fromSmallestUnits(asset, poolInfo.totalLiquidity);
const price = (asset1Reserve / totalLiquidity) * fstAssetPrice * 2;
return { ...asset, ...poolInfo, price, priceInAlgo: price / algoPrice };
return processedInfos;
}

const BIG_NUM = BigInt('1000000000000000000');
Expand Down Expand Up @@ -176,21 +133,20 @@ type LPTokenStore = Map<number, Priced<LPTokenInfo>>;

export const $lpTokenInfos = createStore<LPTokenStore>(Map());

export const getLPTokenInfoFx = createEffect(
export const getLPTokenInfosFx = createEffect(
nonConcurrent(
async ({
asset,
provider,
algoPrice,
}: {
asset: Asset;
provider: DexProvider | undefined;
algoPrice: number | null;
}) => getLPTokenInfo(asset, algoPrice, provider)
async ({ lpTokenIds, algoPrice }: { lpTokenIds: AssetId[]; algoPrice: number | null }) =>
await getManyLPInfosBackend()
)
);

$lpTokenInfos.on(getLPTokenInfoFx.done, (state, { params, result }) => state.set(assetId(params.asset), result));
$lpTokenInfos.on(getLPTokenInfosFx.done, (state, { result }) => {
let newState = state;
for (const lpTokenInfo of result) {
newState = newState.set(lpTokenInfo.id, lpTokenInfo);
}
return newState;
});

const $lpTokenIds = createStore(Set<AssetId>()).on($farmPools, (state, pools) => {
const newIds = Set(pools.filter((pool) => pool.state !== null).map((pool) => pool.state!.initial.stakeToken));
Expand All @@ -199,26 +155,16 @@ const $lpTokenIds = createStore(Set<AssetId>()).on($farmPools, (state, pools) =>

// Automatically fetch LP token infos when general info about them gets fetched the first time
sample({
clock: assetLoaded,
source: { lpTokens: $lpTokenIds, algoPrice: $algoUsdPrice },
filter: ({ lpTokens }, asset) => lpTokens.has(asset.id),
fn: ({ algoPrice }, asset) => ({ asset, algoPrice, provider: undefined }),
target: getLPTokenInfoFx,
clock: allAssetsLoaded,
source: { lpTokens: $lpTokenIds, algoPrice: $pricedAlgo.map((algo) => algo?.price ?? null) },
fn: ({ lpTokens, algoPrice }) => ({ lpTokenIds: lpTokens.toArray(), algoPrice }),
target: getLPTokenInfosFx,
});

$farmPools.watch((farms) => {
const farmStates = farms.map((farm) => farm.state).filter((s): s is ContractState<'farm'> => s !== null);
for (const s of farmStates) {
registerAsset(s.initial.stakeToken);
registerPricedAsset(s.initial.rewardToken);
}
});

$stakePools.watch((farms) => {
const farmStates = farms.map((farm) => farm.state).filter((s): s is ContractState<'farm'> => s !== null);
for (const s of farmStates) {
registerPricedAsset(s.initial.stakeToken);
registerPricedAsset(s.initial.rewardToken);
}
});

Expand Down Expand Up @@ -332,7 +278,7 @@ export function createAprs<T extends FarmType>(
$pools,
$networkTime,
$meanRoundDuration,
$algoUsdPrice,
$pricedAlgo,
$stakeTokens,
$farmRewardTokens,
(pools, time, meanRoundDuration, algoPrice, stakingTokens, farmRewardTokens) =>
Expand Down Expand Up @@ -375,7 +321,7 @@ export function createAprs<T extends FarmType>(

const algoRewardAPR =
totalStakedUSD && algoPrice
? ((algoRewardPerBlock * algoPrice * blocksInAYear) / totalStakedUSD) * 100
? ((algoRewardPerBlock * algoPrice.price * blocksInAYear) / totalStakedUSD) * 100
: 0;

const feesAPR = ((stakeTokenInfo as Priced<LPTokenInfo>).dexFeeApr ?? 0) * 100;
Expand Down
18 changes: 18 additions & 0 deletions src/Farm/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,21 @@ export const useWalletPersistedState = <InitialValueType>(

return usePersistedState<InitialValueType>(walletAddr ? `${walletAddr}-${key}` : undefined, initialValue);
};

export function detectAssetProvider({ name }: { name: string }): DexProvider {
if (name.includes('TinymanPool2.0')) {
return 'T3';
}
name = name.toLowerCase();
if (name.includes('tinyman')) {
return 'T2';
}
if (name.includes('humble')) {
return 'H2';
}
if (name.includes('liquidity') || name.includes('pact')) {
return 'PT';
}

return 'MOCK';
}
6 changes: 3 additions & 3 deletions src/LaaS/store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { buildContractsStore, ContractType, registerPricedAsset } from '../common/store';
import { buildContractsStore } from '../common/store';
import { backend as laasBackend } from '../cometa-laas-tmp/wrapper';

// TODO shall we support multiple backends?
Expand All @@ -13,8 +13,8 @@ export const initializeLaasPool = initializeContract;

$contractStatesWithCache.watch((states) =>
states.valueSeq().forEach((s) => {
registerPricedAsset(s.initial.aToken);
registerPricedAsset(s.initial.bToken);
// registerPricedAsset(s.initial.aToken);
// registerPricedAsset(s.initial.bToken);
})
);

Expand Down
4 changes: 2 additions & 2 deletions src/Menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import logo from '../imgs/logo.png';
import meta_logo from '../imgs/meta_token.svg';
import algo_logo from '../imgs/algo_token.svg';
import burger from '../imgs/burger.svg';
import { $algoUsdPrice, $pricedAssets, Asset, Priced } from '../common/store';
import { $pricedAlgo, $pricedAssets, Asset, Priced } from '../common/store';
import { ConnectWallet } from '../wallet/ConnectWallet';
import { ALGONET, isMobile, META_TOKEN_ID, TESTNET } from '../AppContext';
import { getTokenLink } from '../Farm/PoolList/Pool/utils';
Expand Down Expand Up @@ -70,7 +70,7 @@ function BurgerMenu({ ALGOPrice, METAPrice }: { ALGOPrice: number | null; METAPr
}

export function Menu() {
const ALGOPrice = useUnit($algoUsdPrice);
const ALGOPrice = useUnit($pricedAlgo)?.price ?? null;
const METAPrice = useStoreMap($pricedAssets, (as) => as.get(META_TOKEN_ID, null));
const [isBurgerOpen, setIsBurgerOpen] = useState(false);

Expand Down
4 changes: 2 additions & 2 deletions src/Stake/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { backend as distribution_17_0_4 } from 'metalabs-distribution-17_0_4';
import { backend as distribution_17_0_5 } from 'metalabs-distribution-17_0_5';

import { combine, Store } from 'effector';
import { buildContractsStore, registerPricedAsset, $networkTime, $pricedAssets, Contract } from '../common/store';
import { buildContractsStore, $networkTime, $pricedAssets, Contract } from '../common/store';
import {
$stakePools,
$farmStakeTokens,
Expand Down Expand Up @@ -42,7 +42,7 @@ export const $allStakePools = combine(

$contractStatesWithCache.watch((states) =>
states.valueSeq().forEach((s) => {
registerPricedAsset(s.initial.token);
// registerPricedAsset(s.initial.token);
})
);

Expand Down
14 changes: 1 addition & 13 deletions src/Swap/Swap.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,17 @@
import React, { useEffect, useRef, useState } from 'react';
import { useUnit } from 'effector-react';
import { Account } from '@reach-sh/stdlib/ALGO';
import { useModal } from 'react-hooks-use-modal';
import { func } from 'prop-types';
import { DeflexQuote } from '@deflex/deflex-sdk-js';
import { theme } from '../theme';
import { ALGONET, deflexClient, MAINNET, META_TOKEN_ID, reach, TESTNET } from '../AppContext';
import {
$account,
$balances,
Amount,
Asset,
AssetId,
fetchAsset,
fetchAssetPriceFx,
refreshAccountInfo,
} from '../common/store';
import { $account, $balances, Amount, Asset, AssetId, fetchAsset, refreshAccountInfo } from '../common/store';

import { logEvent, LogName } from '../logEvent';
import { PacmanButton } from '../Components/PacmanButton/PacmanButton';
import {
algoexplorerTxLink,
fromSmallestUnits,
getSmallestUnits,
parseTxs,
SentTxError,
signAndPostTxnGroups,
} from '../common/lib';
Expand Down
Loading