Skip to content

Commit

Permalink
Merge pull request #548 from madfish-solutions/v2.1.0
Browse files Browse the repository at this point in the history
V2.1.0
  • Loading branch information
sharkich authored Mar 31, 2022
2 parents 4f43112 + 3051fbc commit f401e62
Show file tree
Hide file tree
Showing 288 changed files with 9,388 additions and 441 deletions.
8 changes: 8 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ NEXT_PUBLIC_BAKERS_API_URL=https://api.baking-bad.org/v2/bakers
NEXT_PUBLIC_METADATA_API_MAINNET=https://metadata.templewallet.com/metadata
NEXT_PUBLIC_METADATA_API_TESTNET=https://hangzhou-metadata.templewallet.com/metadata
NEXT_PUBLIC_EXCHANGE_RATES_URL=https://api.templewallet.com/api/exchange-rates
NEXT_PUBLIC_MAINNET_FARMING_API_URL=https://quipuswap-staking-api-mainnet.production.madservice.xyz
NEXT_PUBLIC_HANGZHOUNET_FARMING_API_URL=https://quipuswap-staking-api-3g6ez.ondigitalocean.app
# NEXT_PUBLIC_HANGZHOUNET_FARMING_API_URL=http://localhost:4444

NEXT_PUBLIC_IPFS_GATEWAY=https://cloudflare-ipfs.com/ipfs

Expand All @@ -18,6 +21,11 @@ NEXT_PUBLIC_TESTNET_TOKENS=ipfs://QmdDevhmdEyJaArFthfKKUA2FVcte9ijNog1ekSsoMKYPt
NEXT_PUBLIC_ANALYTICS=G-XXXXXXXX
NEXT_PUBLIC_FB_PIXEL=0000000000000000

NEXT_PUBLIC_HANGZHOUNET_FARMING_CONTRACT=KT1RRh3b5oPLsd4CZdmsZAfWMKuoqizyiRpF
NEXT_PUBLIC_MAINNET_FARMING_CONTRACT=KT1RdoweZPFjttwMUsaTo1E2EWNX3WcR9nxZ
# Contract for UI fee:
NEXT_PUBLIC_FARMING_REFERRER_CONTRACT=tz1Sw2mFAUzbkm7dkGCDrbeBsJTTtV7JD8Ey

NEXT_PUBLIC_READ_ONLY_SIGNER_PK=edpkvWbk81uh1DEvdWKR4g1bjyTGhdu1mDvznPUFE2zDwNsLXrEb9K
NEXT_PUBLIC_READ_ONLY_SIGNER_PK_HASH=tz1fVQangAfb9J1hRRMP2bSB6LvASD6KpY8A

Expand Down
34 changes: 34 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI

on: [push]

jobs:
build:
name: Build, lint, and test on Node ${{ matrix.node }} and ${{ matrix.os }}

runs-on: ${{ matrix.os }}
strategy:
matrix:
node: ['14.x']
os: [ubuntu-latest]

steps:
- name: Checkout repo
uses: actions/checkout@v2

- name: Use Node ${{ matrix.node }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}

- name: Install deps and build (with cache)
uses: bahmutov/npm-install@v1

- name: Lint
run: yarn lint

- name: Test
run: yarn test --ci --coverage --maxWorkers=2

- name: Build
run: yarn build
32 changes: 32 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Release Workflow

on:
release:
# This specifies that the build will be triggered when we publish a release
types: [published]

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- uses: actions/checkout@v2
with:
# "ref" specifies the branch to check out.
# "github.event.release.target_commitish" is a global variable and specifies the branch the release targeted
ref: ${{ github.event.release.target_commitish }}
# Setup .npmrc file to publish to GitHub Packages
- uses: actions/setup-node@v2
with:
node-version: '14.x'
- run: yarn install
- run: git config --global user.name "GitHub CD bot"
- run: git config --global user.email "[email protected]"
- run: yarn version --new-version ${{ github.event.release.tag_name }}
- run: yarn build
- run: git push
env:
# The secret is passed automatically. Nothing to configure.
github-token: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# testing
/coverage
/src/coverage

# next.js
/.next/
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

Release: `v2.1.0`

## Getting Started

Run development servers for mainnet or hangzhounet:
Expand Down
10 changes: 10 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Config } from '@jest/types';

const config: Config.InitialOptions = {
preset: 'ts-jest',
testEnvironment: 'node',
rootDir: './src'
};

// eslint-disable-next-line import/no-default-export
export default config;
12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next-production-starter",
"version": "2.0.0",
"version": "2.1.0",
"private": true,
"scripts": {
"dev:mainnet": "cross-env NEXT_PUBLIC_NETWORK=mainnet DEFAULT_TOKENS_SLUGS=tez-KT193D4vozYnhGJQVtw7CoxxqphqUEEwK6Vb_0 NEXT_PUBLIC_MAINNET_BASE_URL=http://localhost:3000 NEXT_PUBLIC_HANGZHOUNET_BASE_URL=http://localhost:3002 next dev -p 3000",
Expand All @@ -12,7 +12,9 @@
"lint": "eslint ./src --ext .ts,.tsx",
"lint-fix": "eslint --fix ./src --ext .ts,.tsx",
"makemessages": "i18next 'src/**/*.{js,jsx,ts,tsx}'",
"schema": "graphql-codegen --config codegen.yml"
"schema": "graphql-codegen --config codegen.yml",
"test": "jest",
"test-watch": "jest --watch"
},
"dependencies": {
"@airgap/beacon-sdk": "^2.3.0",
Expand All @@ -38,11 +40,14 @@
"lightweight-charts": "^3.3.0",
"mem": "8.x.x",
"memoizee": "^0.4.15",
"mobx": "^6.3.13",
"mobx-react-lite": "^3.2.3",
"next": "11.0.1",
"next-i18next": "^10.0.1",
"next-react-svg": "^1.1.3",
"next-seo": "^4.26.0",
"react": "17.0.2",
"react-countdown-hook": "^1.1.1",
"react-dom": "17.0.2",
"react-final-form": "^6.5.3",
"react-final-form-listeners": "^1.0.3",
Expand All @@ -64,6 +69,7 @@
"@graphql-codegen/typescript-operations": "1.18.4",
"@graphql-codegen/typescript-react-apollo": "2.3.1",
"@types/classnames": "^2.3.1",
"@types/jest": "^27.4.1",
"@types/memoizee": "^0.4.6",
"@types/react": "^17.0.13",
"@types/react-final-form-listeners": "^1.0.0",
Expand All @@ -86,8 +92,10 @@
"eslint-plugin-sonarjs": "^0.11.0",
"husky": "4.3.8",
"i18next-parser": "^4.2.0",
"jest": "^27.5.1",
"prettier": "^2.5.1",
"sonarjs": "^1.0.0",
"ts-jest": "^27.1.3",
"typescript": "^4.5.5"
},
"husky": {
Expand Down
17 changes: 16 additions & 1 deletion public/static/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"Sell Price": "Sell Price",
"The amount of token B you receive for 1 token A, according to the current exchange rate.": "The amount of token B you receive for 1 token A, according to the current exchange rate.",
"Buy Price": "Buy Price",
"Buy": "Buy",
"The amount of token A you receive for 1 token B, according to the current exchange rate.": "The amount of token A you receive for 1 token B, according to the current exchange rate.",
"Price impact": "Price impact",
"Fee": "Fee",
Expand All @@ -50,6 +51,8 @@
"Insufficient funds": "Insufficient funds",
"Minimal value is {{min}}": "Minimal value is {{min}}",
"Maximal value is {{max}}": "Maximal value is {{max}}",
"lteLowerMessage": "The value should be greater than {{lower}}",
"gteUpperMessage": "The value should be lower that {{upper}}",
"Value has to be a number between {{min}} and {{max}}": "Value has to be a number between {{min}} and {{max}}",
"tokenDecimalsOverflowError": "The precision of {{tokenSymbol}} token can't be greater than {{decimalPlaces}} places",
"deadlineOutOfRangeError": "Deadline has to be between 1m and 30 days (43200m)",
Expand All @@ -64,5 +67,17 @@
"Donate": "Donate",
"donationSuccess": "Your donation has been successfully processed! Thank you!",
"Learn more": "Learn more",
"valueOutOfRangeError": "Value has to be a number between {{min}} and {{max}}. Note: you need at least 0.01 TEZ to be left on your wallet to pay gas fee"
"valueOutOfRangeError": "Value has to be a number between {{min}} and {{max}}. Note: you need at least 0.01 TEZ to be left on your wallet to pay gas fee",
"dayLetter": "D",
"hourLetter": "H",
"minuteLetter": "M",
"Trade": "Trade",
"Invest": "Invest",
"Divest": "Divest",
"Default": "Default",
"invalidNumberMessage": "The input value is invalid. Only valid numbers with dot or comma separator are accepted.",
"confirmation": "Confirmation",
"areYouSure": "Are you sure?",
"no": "No",
"yes": "Yes"
}
77 changes: 77 additions & 0 deletions public/static/locales/en/farm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"Farming Details": "Farming Details",
"Value Locked": "Value Locked",
"APR": "APR",
"dailyApr": "Daily",
"Current Delegate": "Current Delegate",
"Next Delegate": "Next Delegate",
"farmingEndsIn": "Ends in",
"Lock Period": "Lock Period",
"Withdrawal Fee": "Withdrawal Fee",
"Interface Fee": "Interface Fee",
"Token Contract": "Token Contract",
"Farming Contract": "Farming Contract",
"Harvest All": "Harvest all",
"Your Claimed": "Your Claimed",
"Your Claimable Rewards": "Your Claimable Rewards",
"Harvest": "Harvest",
"Earn extra income with QuipuSwap": "Earn extra income with QuipuSwap",
"Connect Wallet now!": "Connect Wallet now!",
"valueLockedTooltip": "Total amount of assets locked in the farm.",
"dailyDistributionTooltip": "A portion of the farming rewards that can be claimed/compounded daily.",
"aprTooltip": "Annual Percentage Rate. An estimation of the annual rate of return.",
"dailyAprTooltip": "Daily rate of return as the percentage of your initial stake.",
"currentDelegateTooltip": "The farm votes for this baker on the Dex pool with all deposited tokens.",
"nextDelegateTooltip": "The next candidate to become the baker chosen and voted by the farm.",
"farmingEndsInTooltip": "The amount of time until the current farming ends.",
"lockPeriodTooltip": "The minimum amount of time locked assets can not be withdrawn. If withdrawn earlier, a withdrawal fee will be applied and some portion of deposited tokens along with all earned rewards.",
"withdrawalFeeTooltip": "A fee incurred on withdrawal of assets from a running farm. The fee is charged from the deposit amount and is re-staked in the name of the farm, while accumulated rewards are exchanged to QUIPU and burnt.",
"interfaceFeeTooltip": "Percentage of earned tokens charged for providing an interface.",
"Back to the list": "Back to the list",
"yourShareTooltip": "Current value of your stake in this farm.",
"yourDelegateTooltip": "The baker you prefer to vote for with your tokens on the Dex to increase chances this baker will be chosen as the delegate for the pool.",
"feeEndsInTooltip": "Countdown till the moment when the stake can be withdrawn without paying the withdrawal fee and without burning earned rewards.",
"singleFarmRewardTooltip": "Your unclaimed farming reward from this farm.",
"select": "Select",
"fullCardTooltip": "Add Liquidity to the selected liquidity pool, stake liquidity tokens here, earn rewards.",
"tokenContract": "Token Contract",
"farmingContract": "Farming Contract",
"tvl": "TVL",
"tvlTooltip": "Total amount of assets locked in the farm.",
"apr": "APR",
"apy": "APY",
"apyTooltip": "Annual Percentage Yield. An estimated annual compounded return — expected earnings if you reinvest the reward daily. APY is indicative and should not be used as a performance measure!",
"yourBalance": "Your Balance",
"yourBalanceTooltip": "The amount of corresponding tokens on your currently synced account.",
"yourDeposit": "Your Deposit",
"yourDepositTooltip": "The amount of corresponding tokens currently staked in this pool from your currently synced account.",
"yourEarned": "Your Earned",
"yourEarnedTooltip": "Your total farming earning in this farm.",
"totalValueLocked": "Total Value Locked",
"totalValueLockedTooltip": "Total value of assets locked across all farms.",
"totalDailyReward": "Total Daily Reward",
"totalDailyRewardTooltip": "Total amount of rewards generated in the last 24h.",
"totalPendingReward": "Total Pending Reward",
"totalPendingRewardTooltip": "Total amount of rewards that have not been claimed yet.",
"totalClaimedReward": "Total Claimed Reward",
"totalClaimedRewardTooltip": "Total amount of rewards collected by users so far.",
"harvestAll": "Harvest All",
"rewardsTooltip": "Your rewards that can be claimed now across all farms.",
"stakedOnly": "Staked Only",
"activeOnly": "Active Only",
"balance": "Balance",
"deposit": "Deposit",
"earned": "Earned",
"disabled": "Farming is finished! Please withdraw all your stake and rewards.",
"pending": "Farming is paused!",
"Failed to load farming": "Failed to load farming",
"Daily Distribution": "Daily Distribution",
"Your Share": "Your Share",
"Your delegate": "Your delegate",
"Lock period ends in": "Lock period ends in",
"Stake": "Stake",
"Unstake": "Unstake",
"confirmationFirstStake": "This is the farm with lock period. You will need to wait {{days}} days {{hours}} hours to make the free withdrawal or pay {{persent}}% of your deposit and lose all your rewards if you decide to withdraw earlier.",
"confirmationUpdateStake":"If you make the new stake, your lock countdown will be reset but all rewards will be saved. Your lock countdown ends in {{days}} days {{hours}} hours {{minutes}} minutes.",
"confirmationUnstake": "If you make the withdrawal now, the {{persent}}% withdrawal fee will be charged from your deposit and all your rewards will be lost. You can wait {{days}} days {{hours}} hours to make the free withdrawal."
}
19 changes: 19 additions & 0 deletions src/api/farming/get-farming-item.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import BigNumber from 'bignumber.js';

import { FARMING_API_URL } from '@app.config';
import { FarmingItemResponse } from '@interfaces/farming.interfaces';
import { Nullable } from '@utils/types';

const FARMING_LIST_API_URL = `${FARMING_API_URL}/list`;

export const getFarmingItemApi = async (farmingId: Nullable<BigNumber>) => {
if (!farmingId) {
throw new Error('Failed to get nullable farmingId');
}

const response = await fetch(`${FARMING_LIST_API_URL}/${farmingId.toFixed()}`);

const data = (await response.json()) as FarmingItemResponse;

return data.item;
};
66 changes: 66 additions & 0 deletions src/api/farming/get-farming-list.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { TezosToolkit } from '@taquito/taquito';

import { getUserBalance } from '@api/get-user-balance';
import { FARMING_CONTRACT_ADDRESS, FARMING_API_URL } from '@app.config';
import { FarmingContractStorageWrapper } from '@interfaces/farming-contract.interface';
import { RawFarmingItem, FarmingListResponse } from '@interfaces/farming.interfaces';
import { bigNumberToString, isNull } from '@utils/helpers';
import { Nullable } from '@utils/types';

import { getUserFarmBalances } from './helpers';

const FARMING_LIST_API_URL = `${FARMING_API_URL}/list`;

const farmingListFetch = async () => {
const response = await fetch(FARMING_LIST_API_URL);
const data = (await response.json()) as FarmingListResponse;

return data.list;
};

export interface UserBalances {
myBalance: string;
depositBalance?: string;
earnBalance?: string;
}

const injectBalance = async (list: Array<RawFarmingItem>, accountPkh: string, tezos: TezosToolkit) => {
const balances: Map<string, UserBalances> = new Map();
const wrapStorage = await (
await tezos.contract.at(FARMING_CONTRACT_ADDRESS)
).storage<FarmingContractStorageWrapper>();

const storage = wrapStorage.storage;

await Promise.all(
list.map(async item => {
const { stakedToken } = item;
const { contractAddress, type, fa2TokenId } = stakedToken;

const balanceBN = await getUserBalance(tezos, accountPkh, contractAddress, type, fa2TokenId);

const balance = isNull(balanceBN) ? '0' : bigNumberToString(balanceBN);

balances.set(item.id, { myBalance: balance });
})
);

const userBalances = await getUserFarmBalances(accountPkh, storage, list);

userBalances.forEach((userBalance, key) => {
const balance = balances.get(key) as UserBalances;
balances.set(key, { ...balance, ...userBalance });
});

return list.map(item => ({ ...item, ...balances.get(item.id) }));
};

export const getFarmingListApi = async (accountPkh: Nullable<string>, tezos: Nullable<TezosToolkit>) => {
const fetchResult = await farmingListFetch();

if (isNull(accountPkh) || isNull(tezos)) {
return fetchResult;
} else {
return await injectBalance(fetchResult, accountPkh, tezos);
}
};
11 changes: 11 additions & 0 deletions src/api/farming/get-farming-stats.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { FARMING_API_URL } from '@app.config';
import { FarmingStatsResponse } from '@interfaces/farming.interfaces';

const FARMING_STATS_API_URL = `${FARMING_API_URL}/stats`;

export const getFarmingStatsApi = async () => {
const response = await fetch(FARMING_STATS_API_URL);
const data = (await response.json()) as FarmingStatsResponse;

return data.stats;
};
14 changes: 14 additions & 0 deletions src/api/farming/get-user-farming-delegate.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TezosToolkit } from '@taquito/taquito';
import BigNumber from 'bignumber.js';

import { FARMING_CONTRACT_ADDRESS } from '@app.config';
import { FarmingStorage } from '@interfaces/farming-storage.interfaces';
import { getStorageInfo } from '@utils/dapp';

export const getUserFarmingDelegate = async (tezos: TezosToolkit, accountPkh: string, id: BigNumber) => {
const {
storage: { candidates }
} = await getStorageInfo<FarmingStorage>(tezos, FARMING_CONTRACT_ADDRESS);

return (await candidates.get<string>([id, accountPkh])) ?? null;
};
Loading

2 comments on commit f401e62

@vercel
Copy link

@vercel vercel bot commented on f401e62 Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on f401e62 Mar 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.