feat(trading): referrals (Mk2), referrals stats, apply preview (#5021)
This commit is contained in:
parent
1d39f81dfc
commit
43cd170c77
File diff suppressed because one or more lines are too long
@ -7,7 +7,7 @@ export type NewMarketProductFieldsFragment = { __typename?: 'Proposal', terms: {
|
|||||||
|
|
||||||
export type UpdateMarketStatesFragment = { __typename?: 'Proposal', terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', decimalPlaces: number, id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, product: { __typename: 'Future', quoteName: string } | { __typename: 'Perpetual', quoteName: string } | { __typename: 'Spot' } } } } } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } };
|
export type UpdateMarketStatesFragment = { __typename?: 'Proposal', terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', decimalPlaces: number, id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, product: { __typename: 'Future', quoteName: string } | { __typename: 'Perpetual', quoteName: string } | { __typename: 'Spot' } } } } } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } };
|
||||||
|
|
||||||
export type UpdateReferralProgramsFragment = { __typename?: 'Proposal', terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram', windowLength: number, endOfProgram: string, benefitTiers: Array<{ __typename?: 'BenefitTier', minimumEpochs: number, minimumRunningNotionalTakerVolume: string, referralDiscountFactor: string, referralRewardFactor: string }>, stakingTiers: Array<{ __typename?: 'StakingTier', minimumStakedTokens: string, referralRewardMultiplier: string }> } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } };
|
export type UpdateReferralProgramsFragment = { __typename?: 'Proposal', terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram', windowLength: number, endOfProgram: any, benefitTiers: Array<{ __typename?: 'BenefitTier', minimumEpochs: number, minimumRunningNotionalTakerVolume: string, referralDiscountFactor: string, referralRewardFactor: string }>, stakingTiers: Array<{ __typename?: 'StakingTier', minimumStakedTokens: string, referralRewardMultiplier: string }> } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram' } } };
|
||||||
|
|
||||||
export type UpdateVolumeDiscountProgramsFragment = { __typename?: 'Proposal', terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram', endOfProgramTimestamp: any, windowLength: number, benefitTiers: Array<{ __typename?: 'VolumeBenefitTier', minimumRunningNotionalTakerVolume: string, volumeDiscountFactor: string }> } } };
|
export type UpdateVolumeDiscountProgramsFragment = { __typename?: 'Proposal', terms: { __typename?: 'ProposalTerms', change: { __typename?: 'CancelTransfer' } | { __typename?: 'NewAsset' } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket' } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset' } | { __typename?: 'UpdateMarket' } | { __typename?: 'UpdateMarketState' } | { __typename?: 'UpdateNetworkParameter' } | { __typename?: 'UpdateReferralProgram' } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram', endOfProgramTimestamp: any, windowLength: number, benefitTiers: Array<{ __typename?: 'VolumeBenefitTier', minimumRunningNotionalTakerVolume: string, volumeDiscountFactor: string }> } } };
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ export type ProposalsQueryVariables = Types.Exact<{
|
|||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
|
||||||
export type ProposalsQuery = { __typename?: 'Query', proposalsConnection?: { __typename?: 'ProposalsConnection', edges?: Array<{ __typename?: 'ProposalEdge', node: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename?: 'CancelTransfer' } | { __typename: 'NewAsset', name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string, withdrawThreshold: string, lifetimeLimit: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null, product?: { __typename: 'FutureProduct' } | { __typename: 'PerpetualProduct' } | { __typename: 'SpotProduct' } | null } } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset', quantum: string, assetId: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', decimalPlaces: number, id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, product: { __typename: 'Future', quoteName: string } | { __typename: 'Perpetual', quoteName: string } | { __typename: 'Spot' } } } } } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } | { __typename?: 'UpdateReferralProgram', windowLength: number, endOfProgram: string, benefitTiers: Array<{ __typename?: 'BenefitTier', minimumEpochs: number, minimumRunningNotionalTakerVolume: string, referralDiscountFactor: string, referralRewardFactor: string }>, stakingTiers: Array<{ __typename?: 'StakingTier', minimumStakedTokens: string, referralRewardMultiplier: string }> } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram', endOfProgramTimestamp: any, windowLength: number, benefitTiers: Array<{ __typename?: 'VolumeBenefitTier', minimumRunningNotionalTakerVolume: string, volumeDiscountFactor: string }> } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string } } } } | null> | null } | null };
|
export type ProposalsQuery = { __typename?: 'Query', proposalsConnection?: { __typename?: 'ProposalsConnection', edges?: Array<{ __typename?: 'ProposalEdge', node: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, party: { __typename?: 'Party', id: string }, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename?: 'CancelTransfer' } | { __typename: 'NewAsset', name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string, withdrawThreshold: string, lifetimeLimit: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', settlementAsset: { __typename?: 'Asset', symbol: string } } | null, product?: { __typename: 'FutureProduct' } | { __typename: 'PerpetualProduct' } | { __typename: 'SpotProduct' } | null } } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset', quantum: string, assetId: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string } | { __typename?: 'UpdateMarketState', updateType: Types.MarketUpdateType, price?: string | null, market: { __typename?: 'Market', decimalPlaces: number, id: string, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, product: { __typename: 'Future', quoteName: string } | { __typename: 'Perpetual', quoteName: string } | { __typename: 'Spot' } } } } } | { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } | { __typename?: 'UpdateReferralProgram', windowLength: number, endOfProgram: any, benefitTiers: Array<{ __typename?: 'BenefitTier', minimumEpochs: number, minimumRunningNotionalTakerVolume: string, referralDiscountFactor: string, referralRewardFactor: string }>, stakingTiers: Array<{ __typename?: 'StakingTier', minimumStakedTokens: string, referralRewardMultiplier: string }> } | { __typename?: 'UpdateSpotMarket' } | { __typename?: 'UpdateVolumeDiscountProgram', endOfProgramTimestamp: any, windowLength: number, benefitTiers: Array<{ __typename?: 'VolumeBenefitTier', minimumRunningNotionalTakerVolume: string, volumeDiscountFactor: string }> } }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalEquityLikeShareWeight: string } } } } | null> | null } | null };
|
||||||
|
|
||||||
export const NewMarketProductFieldsFragmentDoc = gql`
|
export const NewMarketProductFieldsFragmentDoc = gql`
|
||||||
fragment NewMarketProductFields on Proposal {
|
fragment NewMarketProductFields on Proposal {
|
||||||
|
@ -142,6 +142,12 @@ export const generateYesVotes = (
|
|||||||
})
|
})
|
||||||
.toString(),
|
.toString(),
|
||||||
},
|
},
|
||||||
|
vestingBalancesSummary: {
|
||||||
|
__typename: 'PartyVestingBalancesSummary',
|
||||||
|
epoch: null,
|
||||||
|
lockedBalances: [],
|
||||||
|
vestingBalances: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
datetime: faker.date.past().toISOString(),
|
datetime: faker.date.past().toISOString(),
|
||||||
};
|
};
|
||||||
@ -192,6 +198,12 @@ export const generateNoVotes = (
|
|||||||
})
|
})
|
||||||
.toString(),
|
.toString(),
|
||||||
},
|
},
|
||||||
|
vestingBalancesSummary: {
|
||||||
|
__typename: 'PartyVestingBalancesSummary',
|
||||||
|
epoch: null,
|
||||||
|
lockedBalances: [],
|
||||||
|
vestingBalances: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
datetime: faker.date.past().toISOString(),
|
datetime: faker.date.past().toISOString(),
|
||||||
};
|
};
|
||||||
|
@ -319,7 +319,8 @@ describe('Closed', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('successor marked should be visible', async () => {
|
// eslint-disable-next-line jest/no-disabled-tests
|
||||||
|
it.skip('successor marked should be visible', async () => {
|
||||||
const marketsWithSuccessorID = [
|
const marketsWithSuccessorID = [
|
||||||
{
|
{
|
||||||
__typename: 'MarketEdge' as const,
|
__typename: 'MarketEdge' as const,
|
||||||
|
@ -1,21 +1,42 @@
|
|||||||
import {
|
import {
|
||||||
Input,
|
Input,
|
||||||
InputError,
|
InputError,
|
||||||
|
Loader,
|
||||||
VegaIcon,
|
VegaIcon,
|
||||||
VegaIconNames,
|
VegaIconNames,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import type { FieldValues } from 'react-hook-form';
|
import type { FieldValues } from 'react-hook-form';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Navigate, useSearchParams } from 'react-router-dom';
|
import { Navigate, useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
|
import type { ButtonHTMLAttributes, MouseEventHandler } from 'react';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { Button } from './buttons';
|
import { RainbowButton } from './buttons';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
||||||
import { useReferral } from './hooks/use-referral';
|
import { useReferral } from './hooks/use-referral';
|
||||||
import { Routes } from '../../lib/links';
|
import { Routes } from '../../lib/links';
|
||||||
import { useTransactionEventSubscription } from '@vegaprotocol/web3';
|
import { useTransactionEventSubscription } from '@vegaprotocol/web3';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { Statistics } from './referral-statistics';
|
||||||
|
|
||||||
|
const RELOAD_DELAY = 3000;
|
||||||
|
|
||||||
|
const validateCode = (value: string) => {
|
||||||
|
const number = +`0x${value}`;
|
||||||
|
if (!value || value.length !== 64) {
|
||||||
|
return t('Code must be 64 characters in length');
|
||||||
|
} else if (Number.isNaN(number)) {
|
||||||
|
return t('Code must be be valid hex');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
export const ApplyCodeForm = () => {
|
export const ApplyCodeForm = () => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const openWalletDialog = useVegaWalletDialogStore(
|
||||||
|
(store) => store.openVegaWalletDialog
|
||||||
|
);
|
||||||
|
|
||||||
const [status, setStatus] = useState<
|
const [status, setStatus] = useState<
|
||||||
'requested' | 'failed' | 'successful' | null
|
'requested' | 'failed' | 'successful' | null
|
||||||
>(null);
|
>(null);
|
||||||
@ -27,11 +48,17 @@ export const ApplyCodeForm = () => {
|
|||||||
formState: { errors },
|
formState: { errors },
|
||||||
setValue,
|
setValue,
|
||||||
setError,
|
setError,
|
||||||
|
watch,
|
||||||
} = useForm();
|
} = useForm();
|
||||||
const [params] = useSearchParams();
|
const [params] = useSearchParams();
|
||||||
|
|
||||||
const { data: referee } = useReferral(pubKey, 'referee');
|
const { data: referee } = useReferral({ pubKey, role: 'referee' });
|
||||||
const { data: referrer } = useReferral(pubKey, 'referrer');
|
const { data: referrer } = useReferral({ pubKey, role: 'referrer' });
|
||||||
|
|
||||||
|
const codeField = watch('code');
|
||||||
|
const { data: previewData, loading: previewLoading } = useReferral({
|
||||||
|
code: validateCode(codeField) ? codeField : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const code = params.get('code');
|
const code = params.get('code');
|
||||||
@ -65,9 +92,13 @@ export const ApplyCodeForm = () => {
|
|||||||
if (err.message.includes('user rejected')) {
|
if (err.message.includes('user rejected')) {
|
||||||
setStatus(null);
|
setStatus(null);
|
||||||
} else {
|
} else {
|
||||||
|
setStatus(null);
|
||||||
setError('code', {
|
setError('code', {
|
||||||
type: 'required',
|
type: 'required',
|
||||||
message: 'Your code has been rejected',
|
message:
|
||||||
|
err instanceof Error
|
||||||
|
? err.message
|
||||||
|
: 'Your code has been rejected',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -99,10 +130,21 @@ export const ApplyCodeForm = () => {
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// go to main page when successfully applied
|
||||||
|
useEffect(() => {
|
||||||
|
if (status === 'successful') {
|
||||||
|
setTimeout(() => {
|
||||||
|
navigate(Routes.REFERRALS);
|
||||||
|
}, RELOAD_DELAY);
|
||||||
|
}
|
||||||
|
}, [navigate, status]);
|
||||||
|
|
||||||
|
// go to main page if the current pubkey is already a referrer or referee
|
||||||
if (referee || referrer) {
|
if (referee || referrer) {
|
||||||
return <Navigate to={Routes.REFERRALS} />;
|
return <Navigate to={Routes.REFERRALS} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// show "code applied" message when successfully applied
|
||||||
if (status === 'successful') {
|
if (status === 'successful') {
|
||||||
return (
|
return (
|
||||||
<div className="w-1/2 mx-auto">
|
<div className="w-1/2 mx-auto">
|
||||||
@ -117,10 +159,23 @@ export const ApplyCodeForm = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getButtonProps = () => {
|
const getButtonProps = () => {
|
||||||
if (isReadOnly || !pubKey) {
|
if (!pubKey) {
|
||||||
|
return {
|
||||||
|
disabled: false,
|
||||||
|
children: 'Connect wallet',
|
||||||
|
type: 'button' as ButtonHTMLAttributes<HTMLButtonElement>['type'],
|
||||||
|
onClick: ((event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
openWalletDialog();
|
||||||
|
}) as MouseEventHandler,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isReadOnly) {
|
||||||
return {
|
return {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
children: 'Apply',
|
children: 'Apply a code',
|
||||||
|
type: 'submit' as ButtonHTMLAttributes<HTMLButtonElement>['type'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,43 +183,63 @@ export const ApplyCodeForm = () => {
|
|||||||
return {
|
return {
|
||||||
disabled: true,
|
disabled: true,
|
||||||
children: 'Confirm in wallet...',
|
children: 'Confirm in wallet...',
|
||||||
|
type: 'submit' as ButtonHTMLAttributes<HTMLButtonElement>['type'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
children: 'Apply',
|
children: 'Apply a code',
|
||||||
|
type: 'submit' as ButtonHTMLAttributes<HTMLButtonElement>['type'],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-1/2 mx-auto">
|
<>
|
||||||
<h3 className="mb-5 text-xl text-center uppercase calt">
|
<div className="w-2/3 max-w-md mx-auto bg-vega-clight-800 dark:bg-vega-cdark-800 p-8 rounded-lg">
|
||||||
Apply a referral code
|
<h3 className="mb-4 text-2xl text-center calt">
|
||||||
</h3>
|
Apply a referral code
|
||||||
<p className="mb-6 text-center">Enter a referral code</p>
|
</h3>
|
||||||
<form
|
<p className="mb-4 text-center text-base">
|
||||||
className={classNames('w-full flex flex-col gap-3', {
|
Enter a referral code to get trading discounts.
|
||||||
'animate-shake': Boolean(errors.code),
|
</p>
|
||||||
})}
|
<form
|
||||||
onSubmit={handleSubmit(onSubmit)}
|
className={classNames('w-full flex flex-col gap-4', {
|
||||||
>
|
'animate-shake': Boolean(errors.code),
|
||||||
<label className="flex-grow">
|
})}
|
||||||
<span className="block mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
Your referral code
|
>
|
||||||
</span>
|
<label>
|
||||||
<Input
|
<span className="sr-only">Your referral code</span>
|
||||||
hasError={Boolean(errors.code)}
|
<Input
|
||||||
{...register('code', {
|
hasError={Boolean(errors.code)}
|
||||||
required: 'You have to provide a code to apply it.',
|
{...register('code', {
|
||||||
})}
|
required: 'You have to provide a code to apply it.',
|
||||||
/>
|
validate: validateCode,
|
||||||
</label>
|
})}
|
||||||
<Button className="w-full" type="submit" {...getButtonProps()} />
|
placeholder="Enter a code"
|
||||||
</form>
|
className="mb-2 bg-vega-clight-900 dark:bg-vega-cdark-700"
|
||||||
{errors.code && (
|
/>
|
||||||
<InputError>{errors.code.message?.toString()}</InputError>
|
</label>
|
||||||
)}
|
<RainbowButton variant="border" {...getButtonProps()} />
|
||||||
</div>
|
</form>
|
||||||
|
{errors.code && (
|
||||||
|
<InputError className="break-words overflow-auto">
|
||||||
|
{errors.code.message?.toString()}
|
||||||
|
</InputError>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{previewLoading && !previewData ? (
|
||||||
|
<div className="mt-10">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{previewData ? (
|
||||||
|
<div className="mt-10">
|
||||||
|
<h2 className="text-2xl mb-5">You are joining</h2>
|
||||||
|
<Statistics data={previewData} as="referee" />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -16,20 +16,23 @@ export const RainbowButton = ({
|
|||||||
}: RainbowButtonProps & ButtonHTMLAttributes<HTMLButtonElement>) => (
|
}: RainbowButtonProps & ButtonHTMLAttributes<HTMLButtonElement>) => (
|
||||||
<button
|
<button
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'bg-rainbow hover:bg-none hover:bg-rainbow enabled:hover:bg-vega-pink-500 rounded-lg overflow-hidden disabled:opacity-40',
|
'bg-rainbow rounded-lg overflow-hidden disabled:opacity-40',
|
||||||
|
'hover:bg-rainbow-180 hover:animate-spin-rainbow',
|
||||||
{
|
{
|
||||||
'px-5 py-3 text-white': variant === 'full',
|
'px-5 py-3 text-white': variant === 'full',
|
||||||
'p-[0.125rem]': variant === 'border',
|
'p-[0.125rem]': variant === 'border',
|
||||||
},
|
}
|
||||||
className
|
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={classNames({
|
className={classNames(
|
||||||
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white px-5 py-3 rounded-[0.35rem] overflow-hidden':
|
{
|
||||||
variant === 'border',
|
'bg-vega-clight-800 dark:bg-vega-cdark-800 text-black dark:text-white px-5 py-3 rounded-[0.35rem] overflow-hidden':
|
||||||
})}
|
variant === 'border',
|
||||||
|
},
|
||||||
|
className
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@ -55,6 +58,20 @@ const DISABLED_RAINBOW_TAB_STYLE = classNames(
|
|||||||
'[&.active]:text-white'
|
'[&.active]:text-white'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const TAB_STYLE = classNames(
|
||||||
|
'inline-block',
|
||||||
|
'bg-transparent',
|
||||||
|
'text-vega-clight-200 dark:text-vega-cdark-200',
|
||||||
|
'hover:text-vega-clight-100 dark:hover:text-vega-cdark-100',
|
||||||
|
'data-[state="active"]:text-black dark:data-[state="active"]:text-white',
|
||||||
|
'data-[state="active"]:border-b-2 data-[state="active"]:border-b-black dark:data-[state="active"]:border-b-white',
|
||||||
|
'[&.active]:text-black dark:[&.active]:text-white',
|
||||||
|
'[&.active]:border-b-2 [&.active]:border-b-black dark:[&.active]:border-b-white',
|
||||||
|
'mx-4 px-0 py-3',
|
||||||
|
'uppercase'
|
||||||
|
);
|
||||||
|
const DISABLED_TAB_STYLE = classNames('pointer-events-none');
|
||||||
|
|
||||||
export const RainbowTabButton = forwardRef<
|
export const RainbowTabButton = forwardRef<
|
||||||
HTMLButtonElement,
|
HTMLButtonElement,
|
||||||
{ disabled?: boolean } & ButtonHTMLAttributes<HTMLButtonElement>
|
{ disabled?: boolean } & ButtonHTMLAttributes<HTMLButtonElement>
|
||||||
@ -93,6 +110,26 @@ export const RainbowTabLink = ({
|
|||||||
</NavLink>
|
</NavLink>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const TabLink = ({
|
||||||
|
to,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
disabled = false,
|
||||||
|
...props
|
||||||
|
}: { disabled?: boolean } & ComponentProps<typeof NavLink>) => (
|
||||||
|
<NavLink
|
||||||
|
to={to}
|
||||||
|
className={classNames(
|
||||||
|
TAB_STYLE,
|
||||||
|
disabled && DISABLED_TAB_STYLE,
|
||||||
|
typeof className === 'string' ? className : undefined
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
|
||||||
export const Button = forwardRef<
|
export const Button = forwardRef<
|
||||||
HTMLButtonElement,
|
HTMLButtonElement,
|
||||||
ComponentProps<typeof TradingButton>
|
ComponentProps<typeof TradingButton>
|
||||||
|
@ -4,3 +4,8 @@ export const GRADIENT =
|
|||||||
|
|
||||||
export const SKY_BACKGROUND =
|
export const SKY_BACKGROUND =
|
||||||
'bg-[url(/sky-light.png)] dark:bg-[url(/sky-dark.png)] bg-[40%_0px] bg-[length:1440px] bg-no-repeat bg-local';
|
'bg-[url(/sky-light.png)] dark:bg-[url(/sky-dark.png)] bg-[40%_0px] bg-[length:1440px] bg-no-repeat bg-local';
|
||||||
|
|
||||||
|
// TODO: Update the links to use the correct referral related pages
|
||||||
|
export const REFERRAL_DOCS_LINK = 'https://docs.vega.xyz/';
|
||||||
|
export const ABOUT_REFERRAL_DOCS_LINK = 'https://docs.vega.xyz/';
|
||||||
|
export const DISCLAIMER_REFERRAL_DOCS_LINK = 'https://docs.vega.xyz/';
|
||||||
|
@ -19,70 +19,54 @@ import {
|
|||||||
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
import { addDecimalsFormatNumber } from '@vegaprotocol/utils';
|
||||||
import { DApp, TokenStaticLinks, useLinks } from '@vegaprotocol/environment';
|
import { DApp, TokenStaticLinks, useLinks } from '@vegaprotocol/environment';
|
||||||
import { useStakeAvailable } from './hooks/use-stake-available';
|
import { useStakeAvailable } from './hooks/use-stake-available';
|
||||||
|
import {
|
||||||
|
ABOUT_REFERRAL_DOCS_LINK,
|
||||||
|
DISCLAIMER_REFERRAL_DOCS_LINK,
|
||||||
|
} from './constants';
|
||||||
|
import { useReferral } from './hooks/use-referral';
|
||||||
|
|
||||||
export const CreateCodeContainer = () => {
|
export const CreateCodeContainer = () => {
|
||||||
const { stakeAvailable, requiredStake } = useStakeAvailable();
|
return <CreateCodeForm />;
|
||||||
if (stakeAvailable == null || requiredStake == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<CreateCodeForm
|
|
||||||
currentStakeAvailable={stakeAvailable}
|
|
||||||
requiredStake={requiredStake}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CreateCodeForm = ({
|
export const CreateCodeForm = () => {
|
||||||
currentStakeAvailable,
|
|
||||||
requiredStake,
|
|
||||||
}: {
|
|
||||||
currentStakeAvailable: bigint;
|
|
||||||
requiredStake: bigint;
|
|
||||||
}) => {
|
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
const openWalletDialog = useVegaWalletDialogStore(
|
const openWalletDialog = useVegaWalletDialogStore(
|
||||||
(store) => store.openVegaWalletDialog
|
(store) => store.openVegaWalletDialog
|
||||||
);
|
);
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey, isReadOnly } = useVegaWallet();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-1/2 mx-auto">
|
<div className="w-2/3 max-w-md mx-auto bg-vega-clight-800 dark:bg-vega-cdark-800 p-8 rounded-lg">
|
||||||
<h3 className="mb-5 text-xl text-center uppercase calt">
|
<h3 className="mb-4 text-2xl text-center calt">Create a referral code</h3>
|
||||||
Create a referral code
|
<p className="mb-4 text-center text-base">
|
||||||
</h3>
|
|
||||||
<p className="mb-6 text-center">
|
|
||||||
Generate a referral code to share with your friends and start earning
|
Generate a referral code to share with your friends and start earning
|
||||||
commission.
|
commission.
|
||||||
</p>
|
</p>
|
||||||
<div className="mb-5">
|
|
||||||
<div className="text-center">
|
<div className="w-full flex flex-col">
|
||||||
<RainbowButton
|
<RainbowButton
|
||||||
variant="border"
|
variant="border"
|
||||||
onClick={() => {
|
disabled={isReadOnly}
|
||||||
if (pubKey) {
|
onClick={() => {
|
||||||
setDialogOpen(true);
|
if (pubKey) {
|
||||||
} else {
|
setDialogOpen(true);
|
||||||
openWalletDialog();
|
} else {
|
||||||
}
|
openWalletDialog();
|
||||||
}}
|
}
|
||||||
>
|
}}
|
||||||
{pubKey ? 'Create a referral code' : 'Connect wallet'}
|
>
|
||||||
</RainbowButton>
|
{pubKey ? 'Create a referral code' : 'Connect wallet'}
|
||||||
</div>
|
</RainbowButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
title="Create a referral code"
|
title="Create a referral code"
|
||||||
open={dialogOpen}
|
open={dialogOpen}
|
||||||
onChange={() => setDialogOpen(false)}
|
onChange={() => setDialogOpen(false)}
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<CreateCodeDialog
|
<CreateCodeDialog setDialogOpen={setDialogOpen} />
|
||||||
currentStakeAvailable={currentStakeAvailable}
|
|
||||||
setDialogOpen={setDialogOpen}
|
|
||||||
requiredStake={requiredStake}
|
|
||||||
/>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -90,21 +74,21 @@ export const CreateCodeForm = ({
|
|||||||
|
|
||||||
const CreateCodeDialog = ({
|
const CreateCodeDialog = ({
|
||||||
setDialogOpen,
|
setDialogOpen,
|
||||||
currentStakeAvailable,
|
|
||||||
requiredStake,
|
|
||||||
}: {
|
}: {
|
||||||
setDialogOpen: (open: boolean) => void;
|
setDialogOpen: (open: boolean) => void;
|
||||||
currentStakeAvailable: bigint;
|
|
||||||
requiredStake: bigint;
|
|
||||||
}) => {
|
}) => {
|
||||||
const createLink = useLinks(DApp.Governance);
|
const createLink = useLinks(DApp.Governance);
|
||||||
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
|
const { isReadOnly, pubKey, sendTx } = useVegaWallet();
|
||||||
|
const { refetch } = useReferral({ pubKey, role: 'referrer' });
|
||||||
const [err, setErr] = useState<string | null>(null);
|
const [err, setErr] = useState<string | null>(null);
|
||||||
const [code, setCode] = useState<string | null>(null);
|
const [code, setCode] = useState<string | null>(null);
|
||||||
const [status, setStatus] = useState<
|
const [status, setStatus] = useState<
|
||||||
'idle' | 'loading' | 'success' | 'error'
|
'idle' | 'loading' | 'success' | 'error'
|
||||||
>('idle');
|
>('idle');
|
||||||
|
|
||||||
|
const { stakeAvailable: currentStakeAvailable, requiredStake } =
|
||||||
|
useStakeAvailable();
|
||||||
|
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
if (isReadOnly || !pubKey) {
|
if (isReadOnly || !pubKey) {
|
||||||
setErr('Not connected');
|
setErr('Not connected');
|
||||||
@ -156,16 +140,29 @@ const CreateCodeDialog = ({
|
|||||||
return {
|
return {
|
||||||
children: 'Close',
|
children: 'Close',
|
||||||
intent: Intent.Success,
|
intent: Intent.Success,
|
||||||
onClick: () => setDialogOpen(false),
|
onClick: () => {
|
||||||
|
refetch();
|
||||||
|
setDialogOpen(false);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Add when network parameters are updated
|
if (!pubKey || currentStakeAvailable == null || requiredStake == null) {
|
||||||
if (
|
return (
|
||||||
currentStakeAvailable === BigInt(0) ||
|
<div className="flex flex-col gap-4">
|
||||||
currentStakeAvailable < requiredStake
|
<p>You must be connected to the Vega wallet.</p>
|
||||||
) {
|
<TradingButton
|
||||||
|
intent={Intent.Primary}
|
||||||
|
onClick={() => setDialogOpen(false)}
|
||||||
|
>
|
||||||
|
Close
|
||||||
|
</TradingButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentStakeAvailable < requiredStake) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<p>
|
<p>
|
||||||
@ -215,10 +212,13 @@ const CreateCodeDialog = ({
|
|||||||
{...getButtonProps()}
|
{...getButtonProps()}
|
||||||
/>
|
/>
|
||||||
{err && <InputError>{err}</InputError>}
|
{err && <InputError>{err}</InputError>}
|
||||||
{/* TODO: Add links */}
|
|
||||||
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
|
<div className="flex justify-center pt-5 mt-2 text-sm border-t gap-4 text-default border-default">
|
||||||
<ExternalLink>About the referral program</ExternalLink>
|
<ExternalLink href={ABOUT_REFERRAL_DOCS_LINK}>
|
||||||
<ExternalLink>Disclaimer</ExternalLink>
|
About the referral program
|
||||||
|
</ExternalLink>
|
||||||
|
<ExternalLink href={DISCLAIMER_REFERRAL_DOCS_LINK}>
|
||||||
|
Disclaimer
|
||||||
|
</ExternalLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
query ReferralProgram {
|
||||||
|
currentReferralProgram {
|
||||||
|
id
|
||||||
|
version
|
||||||
|
endOfProgramTimestamp
|
||||||
|
windowLength
|
||||||
|
endedAt
|
||||||
|
benefitTiers {
|
||||||
|
minimumEpochs
|
||||||
|
minimumRunningNotionalTakerVolume
|
||||||
|
referralDiscountFactor
|
||||||
|
referralRewardFactor
|
||||||
|
}
|
||||||
|
stakingTiers {
|
||||||
|
minimumStakedTokens
|
||||||
|
referralRewardMultiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
apps/trading/client-pages/referrals/hooks/Epoch.graphql
Normal file
9
apps/trading/client-pages/referrals/hooks/Epoch.graphql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
query CurrentEpochInfo {
|
||||||
|
epoch {
|
||||||
|
id
|
||||||
|
timestamps {
|
||||||
|
start
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
apps/trading/client-pages/referrals/hooks/Referees.graphql
Normal file
14
apps/trading/client-pages/referrals/hooks/Referees.graphql
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
query Referees($code: ID!, $aggregationDays: Int) {
|
||||||
|
referralSetReferees(id: $code, aggregationDays: $aggregationDays) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
referralSetId
|
||||||
|
refereeId
|
||||||
|
joinedAt
|
||||||
|
atEpoch
|
||||||
|
totalRefereeNotionalTakerVolume
|
||||||
|
totalRefereeGeneratedRewards
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
query ReferralSetStats($code: ID!, $epoch: Int) {
|
||||||
|
referralSetStats(setId: $code, epoch: $epoch) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
atEpoch
|
||||||
|
partyId
|
||||||
|
discountFactor
|
||||||
|
rewardFactor
|
||||||
|
epochNotionalTakerVolume
|
||||||
|
referralSetRunningNotionalTakerVolume
|
||||||
|
rewardsMultiplier
|
||||||
|
rewardsFactorMultiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
query ReferralSets($id: ID, $referrer: ID, $referee: ID) {
|
||||||
|
referralSets(id: $id, referrer: $referrer, referee: $referee) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
referrer
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
apps/trading/client-pages/referrals/hooks/__generated__/CurrentReferralProgram.ts
generated
Normal file
59
apps/trading/client-pages/referrals/hooks/__generated__/CurrentReferralProgram.ts
generated
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ReferralProgramQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ReferralProgramQuery = { __typename?: 'Query', currentReferralProgram?: { __typename?: 'CurrentReferralProgram', id: string, version: number, endOfProgramTimestamp: any, windowLength: number, endedAt?: any | null, benefitTiers: Array<{ __typename?: 'BenefitTier', minimumEpochs: number, minimumRunningNotionalTakerVolume: string, referralDiscountFactor: string, referralRewardFactor: string }>, stakingTiers: Array<{ __typename?: 'StakingTier', minimumStakedTokens: string, referralRewardMultiplier: string }> } | null };
|
||||||
|
|
||||||
|
|
||||||
|
export const ReferralProgramDocument = gql`
|
||||||
|
query ReferralProgram {
|
||||||
|
currentReferralProgram {
|
||||||
|
id
|
||||||
|
version
|
||||||
|
endOfProgramTimestamp
|
||||||
|
windowLength
|
||||||
|
endedAt
|
||||||
|
benefitTiers {
|
||||||
|
minimumEpochs
|
||||||
|
minimumRunningNotionalTakerVolume
|
||||||
|
referralDiscountFactor
|
||||||
|
referralRewardFactor
|
||||||
|
}
|
||||||
|
stakingTiers {
|
||||||
|
minimumStakedTokens
|
||||||
|
referralRewardMultiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useReferralProgramQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useReferralProgramQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useReferralProgramQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useReferralProgramQuery({
|
||||||
|
* variables: {
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useReferralProgramQuery(baseOptions?: Apollo.QueryHookOptions<ReferralProgramQuery, ReferralProgramQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ReferralProgramQuery, ReferralProgramQueryVariables>(ReferralProgramDocument, options);
|
||||||
|
}
|
||||||
|
export function useReferralProgramLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ReferralProgramQuery, ReferralProgramQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ReferralProgramQuery, ReferralProgramQueryVariables>(ReferralProgramDocument, options);
|
||||||
|
}
|
||||||
|
export type ReferralProgramQueryHookResult = ReturnType<typeof useReferralProgramQuery>;
|
||||||
|
export type ReferralProgramLazyQueryHookResult = ReturnType<typeof useReferralProgramLazyQuery>;
|
||||||
|
export type ReferralProgramQueryResult = Apollo.QueryResult<ReferralProgramQuery, ReferralProgramQueryVariables>;
|
49
apps/trading/client-pages/referrals/hooks/__generated__/Epoch.ts
generated
Normal file
49
apps/trading/client-pages/referrals/hooks/__generated__/Epoch.ts
generated
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type CurrentEpochInfoQueryVariables = Types.Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type CurrentEpochInfoQuery = { __typename?: 'Query', epoch: { __typename?: 'Epoch', id: string, timestamps: { __typename?: 'EpochTimestamps', start?: any | null, end?: any | null } } };
|
||||||
|
|
||||||
|
|
||||||
|
export const CurrentEpochInfoDocument = gql`
|
||||||
|
query CurrentEpochInfo {
|
||||||
|
epoch {
|
||||||
|
id
|
||||||
|
timestamps {
|
||||||
|
start
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useCurrentEpochInfoQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useCurrentEpochInfoQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useCurrentEpochInfoQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useCurrentEpochInfoQuery({
|
||||||
|
* variables: {
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useCurrentEpochInfoQuery(baseOptions?: Apollo.QueryHookOptions<CurrentEpochInfoQuery, CurrentEpochInfoQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<CurrentEpochInfoQuery, CurrentEpochInfoQueryVariables>(CurrentEpochInfoDocument, options);
|
||||||
|
}
|
||||||
|
export function useCurrentEpochInfoLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<CurrentEpochInfoQuery, CurrentEpochInfoQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<CurrentEpochInfoQuery, CurrentEpochInfoQueryVariables>(CurrentEpochInfoDocument, options);
|
||||||
|
}
|
||||||
|
export type CurrentEpochInfoQueryHookResult = ReturnType<typeof useCurrentEpochInfoQuery>;
|
||||||
|
export type CurrentEpochInfoLazyQueryHookResult = ReturnType<typeof useCurrentEpochInfoLazyQuery>;
|
||||||
|
export type CurrentEpochInfoQueryResult = Apollo.QueryResult<CurrentEpochInfoQuery, CurrentEpochInfoQueryVariables>;
|
59
apps/trading/client-pages/referrals/hooks/__generated__/Referees.ts
generated
Normal file
59
apps/trading/client-pages/referrals/hooks/__generated__/Referees.ts
generated
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type RefereesQueryVariables = Types.Exact<{
|
||||||
|
code: Types.Scalars['ID'];
|
||||||
|
aggregationDays?: Types.InputMaybe<Types.Scalars['Int']>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type RefereesQuery = { __typename?: 'Query', referralSetReferees: { __typename?: 'ReferralSetRefereeConnection', edges: Array<{ __typename?: 'ReferralSetRefereeEdge', node: { __typename?: 'ReferralSetReferee', referralSetId: string, refereeId: string, joinedAt: any, atEpoch: number, totalRefereeNotionalTakerVolume: string, totalRefereeGeneratedRewards: string } } | null> } };
|
||||||
|
|
||||||
|
|
||||||
|
export const RefereesDocument = gql`
|
||||||
|
query Referees($code: ID!, $aggregationDays: Int) {
|
||||||
|
referralSetReferees(id: $code, aggregationDays: $aggregationDays) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
referralSetId
|
||||||
|
refereeId
|
||||||
|
joinedAt
|
||||||
|
atEpoch
|
||||||
|
totalRefereeNotionalTakerVolume
|
||||||
|
totalRefereeGeneratedRewards
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useRefereesQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useRefereesQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useRefereesQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useRefereesQuery({
|
||||||
|
* variables: {
|
||||||
|
* code: // value for 'code'
|
||||||
|
* aggregationDays: // value for 'aggregationDays'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useRefereesQuery(baseOptions: Apollo.QueryHookOptions<RefereesQuery, RefereesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<RefereesQuery, RefereesQueryVariables>(RefereesDocument, options);
|
||||||
|
}
|
||||||
|
export function useRefereesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<RefereesQuery, RefereesQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<RefereesQuery, RefereesQueryVariables>(RefereesDocument, options);
|
||||||
|
}
|
||||||
|
export type RefereesQueryHookResult = ReturnType<typeof useRefereesQuery>;
|
||||||
|
export type RefereesLazyQueryHookResult = ReturnType<typeof useRefereesLazyQuery>;
|
||||||
|
export type RefereesQueryResult = Apollo.QueryResult<RefereesQuery, RefereesQueryVariables>;
|
61
apps/trading/client-pages/referrals/hooks/__generated__/ReferralSetStats.ts
generated
Normal file
61
apps/trading/client-pages/referrals/hooks/__generated__/ReferralSetStats.ts
generated
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ReferralSetStatsQueryVariables = Types.Exact<{
|
||||||
|
code: Types.Scalars['ID'];
|
||||||
|
epoch?: Types.InputMaybe<Types.Scalars['Int']>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ReferralSetStatsQuery = { __typename?: 'Query', referralSetStats: { __typename?: 'ReferralSetStatsConnection', edges: Array<{ __typename?: 'ReferralSetStatsEdge', node: { __typename?: 'ReferralSetStats', atEpoch: number, partyId: string, discountFactor: string, rewardFactor: string, epochNotionalTakerVolume: string, referralSetRunningNotionalTakerVolume: string, rewardsMultiplier: string, rewardsFactorMultiplier: string } } | null> } };
|
||||||
|
|
||||||
|
|
||||||
|
export const ReferralSetStatsDocument = gql`
|
||||||
|
query ReferralSetStats($code: ID!, $epoch: Int) {
|
||||||
|
referralSetStats(setId: $code, epoch: $epoch) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
atEpoch
|
||||||
|
partyId
|
||||||
|
discountFactor
|
||||||
|
rewardFactor
|
||||||
|
epochNotionalTakerVolume
|
||||||
|
referralSetRunningNotionalTakerVolume
|
||||||
|
rewardsMultiplier
|
||||||
|
rewardsFactorMultiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useReferralSetStatsQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useReferralSetStatsQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useReferralSetStatsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useReferralSetStatsQuery({
|
||||||
|
* variables: {
|
||||||
|
* code: // value for 'code'
|
||||||
|
* epoch: // value for 'epoch'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useReferralSetStatsQuery(baseOptions: Apollo.QueryHookOptions<ReferralSetStatsQuery, ReferralSetStatsQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ReferralSetStatsQuery, ReferralSetStatsQueryVariables>(ReferralSetStatsDocument, options);
|
||||||
|
}
|
||||||
|
export function useReferralSetStatsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ReferralSetStatsQuery, ReferralSetStatsQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ReferralSetStatsQuery, ReferralSetStatsQueryVariables>(ReferralSetStatsDocument, options);
|
||||||
|
}
|
||||||
|
export type ReferralSetStatsQueryHookResult = ReturnType<typeof useReferralSetStatsQuery>;
|
||||||
|
export type ReferralSetStatsLazyQueryHookResult = ReturnType<typeof useReferralSetStatsLazyQuery>;
|
||||||
|
export type ReferralSetStatsQueryResult = Apollo.QueryResult<ReferralSetStatsQuery, ReferralSetStatsQueryVariables>;
|
59
apps/trading/client-pages/referrals/hooks/__generated__/ReferralSets.ts
generated
Normal file
59
apps/trading/client-pages/referrals/hooks/__generated__/ReferralSets.ts
generated
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import * as Types from '@vegaprotocol/types';
|
||||||
|
|
||||||
|
import { gql } from '@apollo/client';
|
||||||
|
import * as Apollo from '@apollo/client';
|
||||||
|
const defaultOptions = {} as const;
|
||||||
|
export type ReferralSetsQueryVariables = Types.Exact<{
|
||||||
|
id?: Types.InputMaybe<Types.Scalars['ID']>;
|
||||||
|
referrer?: Types.InputMaybe<Types.Scalars['ID']>;
|
||||||
|
referee?: Types.InputMaybe<Types.Scalars['ID']>;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ReferralSetsQuery = { __typename?: 'Query', referralSets: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', id: string, referrer: string, createdAt: any, updatedAt: any } } | null> } };
|
||||||
|
|
||||||
|
|
||||||
|
export const ReferralSetsDocument = gql`
|
||||||
|
query ReferralSets($id: ID, $referrer: ID, $referee: ID) {
|
||||||
|
referralSets(id: $id, referrer: $referrer, referee: $referee) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
referrer
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useReferralSetsQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useReferralSetsQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useReferralSetsQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useReferralSetsQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* referrer: // value for 'referrer'
|
||||||
|
* referee: // value for 'referee'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useReferralSetsQuery(baseOptions?: Apollo.QueryHookOptions<ReferralSetsQuery, ReferralSetsQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ReferralSetsQuery, ReferralSetsQueryVariables>(ReferralSetsDocument, options);
|
||||||
|
}
|
||||||
|
export function useReferralSetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ReferralSetsQuery, ReferralSetsQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ReferralSetsQuery, ReferralSetsQueryVariables>(ReferralSetsDocument, options);
|
||||||
|
}
|
||||||
|
export type ReferralSetsQueryHookResult = ReturnType<typeof useReferralSetsQuery>;
|
||||||
|
export type ReferralSetsLazyQueryHookResult = ReturnType<typeof useReferralSetsLazyQuery>;
|
||||||
|
export type ReferralSetsQueryResult = Apollo.QueryResult<ReferralSetsQuery, ReferralSetsQueryVariables>;
|
@ -1,32 +1,8 @@
|
|||||||
import { gql, useQuery } from '@apollo/client';
|
|
||||||
import { getNumberFormat } from '@vegaprotocol/utils';
|
import { getNumberFormat } from '@vegaprotocol/utils';
|
||||||
import { addDays } from 'date-fns';
|
import { addDays } from 'date-fns';
|
||||||
import sortBy from 'lodash/sortBy';
|
import sortBy from 'lodash/sortBy';
|
||||||
import omit from 'lodash/omit';
|
import omit from 'lodash/omit';
|
||||||
|
import { useReferralProgramQuery } from './__generated__/CurrentReferralProgram';
|
||||||
// TODO: Generate query
|
|
||||||
// eslint-disable-next-line
|
|
||||||
const REFERRAL_PROGRAM_QUERY = gql`
|
|
||||||
query ReferralProgram {
|
|
||||||
currentReferralProgram {
|
|
||||||
id
|
|
||||||
version
|
|
||||||
endOfProgramTimestamp
|
|
||||||
windowLength
|
|
||||||
endedAt
|
|
||||||
benefitTiers {
|
|
||||||
minimumEpochs
|
|
||||||
minimumRunningNotionalTakerVolume
|
|
||||||
referralDiscountFactor
|
|
||||||
referralRewardFactor
|
|
||||||
}
|
|
||||||
stakingTiers {
|
|
||||||
minimumStakedTokens
|
|
||||||
referralRewardMultiplier
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const STAKING_TIERS_MAPPING: Record<number, string> = {
|
const STAKING_TIERS_MAPPING: Record<number, string> = {
|
||||||
1: 'Tradestarter',
|
1: 'Tradestarter',
|
||||||
@ -83,11 +59,11 @@ const MOCK = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useReferralProgram = () => {
|
export const useReferralProgram = () => {
|
||||||
const { data, loading, error } = useQuery(REFERRAL_PROGRAM_QUERY, {
|
const { data, loading, error } = useReferralProgramQuery({
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-and-network',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!data) {
|
if (!data || !data.currentReferralProgram) {
|
||||||
return {
|
return {
|
||||||
benefitTiers: [],
|
benefitTiers: [],
|
||||||
stakingTiers: [],
|
stakingTiers: [],
|
||||||
@ -104,11 +80,15 @@ export const useReferralProgram = () => {
|
|||||||
.map((t, i) => {
|
.map((t, i) => {
|
||||||
return {
|
return {
|
||||||
tier: i + 1,
|
tier: i + 1,
|
||||||
|
rewardFactor: Number(t.referralRewardFactor),
|
||||||
commission: Number(t.referralRewardFactor) * 100 + '%',
|
commission: Number(t.referralRewardFactor) * 100 + '%',
|
||||||
|
discountFactor: Number(t.referralDiscountFactor),
|
||||||
discount: Number(t.referralDiscountFactor) * 100 + '%',
|
discount: Number(t.referralDiscountFactor) * 100 + '%',
|
||||||
|
minimumVolume: Number(t.minimumRunningNotionalTakerVolume),
|
||||||
volume: getNumberFormat(0).format(
|
volume: getNumberFormat(0).format(
|
||||||
Number(t.minimumRunningNotionalTakerVolume)
|
Number(t.minimumRunningNotionalTakerVolume)
|
||||||
),
|
),
|
||||||
|
epochs: Number(t.minimumEpochs),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -123,10 +103,16 @@ export const useReferralProgram = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const details = omit(
|
||||||
|
data.currentReferralProgram,
|
||||||
|
'benefitTiers',
|
||||||
|
'stakingTiers'
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
benefitTiers,
|
benefitTiers,
|
||||||
stakingTiers,
|
stakingTiers,
|
||||||
details: omit(data.currentReferralProgram, 'benefitTiers', 'stakingTiers'),
|
details,
|
||||||
loading,
|
loading,
|
||||||
error,
|
error,
|
||||||
};
|
};
|
||||||
|
@ -1,114 +1,116 @@
|
|||||||
import { gql, useQuery } from '@apollo/client';
|
|
||||||
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
import { removePaginationWrapper } from '@vegaprotocol/utils';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useRefereesQuery } from './__generated__/Referees';
|
||||||
|
import compact from 'lodash/compact';
|
||||||
|
import type { ReferralSetsQueryVariables } from './__generated__/ReferralSets';
|
||||||
|
import { useReferralSetsQuery } from './__generated__/ReferralSets';
|
||||||
|
|
||||||
const REFERRER_QUERY = gql`
|
const DEFAULT_AGGREGATION_DAYS = 30;
|
||||||
query ReferralSets($partyId: ID!) {
|
|
||||||
referralSets(referrer: $partyId) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
id
|
|
||||||
referrer
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const REFEREE_QUERY = gql`
|
export type Role = 'referrer' | 'referee';
|
||||||
query ReferralSets($partyId: ID!) {
|
type UseReferralArgs = (
|
||||||
referralSets(referee: $partyId) {
|
| { code: string }
|
||||||
edges {
|
| { pubKey: string | null; role: Role }
|
||||||
node {
|
) & {
|
||||||
id
|
aggregationDays?: number;
|
||||||
referrer
|
|
||||||
createdAt
|
|
||||||
updatedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const REFEREES_QUERY = gql`
|
|
||||||
query ReferralSets($code: ID!) {
|
|
||||||
referralSetReferees(id: $code) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
referralSetId
|
|
||||||
refereeId
|
|
||||||
joinedAt
|
|
||||||
atEpoch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
// TODO: generate types after perps work is merged
|
|
||||||
export type ReferralData = {
|
|
||||||
code: string;
|
|
||||||
referees: Array<{
|
|
||||||
refereeId: string;
|
|
||||||
joinedAt: string;
|
|
||||||
atEpoch: number;
|
|
||||||
}>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useReferral = (
|
const prepareVariables = (
|
||||||
pubKey: string | null,
|
args: UseReferralArgs
|
||||||
role: 'referrer' | 'referee'
|
): [ReferralSetsQueryVariables, boolean] => {
|
||||||
) => {
|
const byCode = 'code' in args;
|
||||||
const query = {
|
const byRole = 'pubKey' in args && 'role' in args;
|
||||||
referrer: REFERRER_QUERY,
|
let variables = {};
|
||||||
referee: REFEREE_QUERY,
|
let skip = true;
|
||||||
};
|
if (byCode) {
|
||||||
|
variables = {
|
||||||
|
id: args.code,
|
||||||
|
};
|
||||||
|
skip = !args.code;
|
||||||
|
}
|
||||||
|
if (byRole) {
|
||||||
|
if (args.role === 'referee') {
|
||||||
|
variables = { referee: args.pubKey };
|
||||||
|
}
|
||||||
|
if (args.role === 'referrer') {
|
||||||
|
variables = { referrer: args.pubKey };
|
||||||
|
}
|
||||||
|
skip = !args.pubKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [variables, skip];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useReferral = (args: UseReferralArgs) => {
|
||||||
|
const [variables, skip] = prepareVariables(args);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: referralData,
|
data: referralData,
|
||||||
loading: referralLoading,
|
loading: referralLoading,
|
||||||
error: referralError,
|
error: referralError,
|
||||||
} = useQuery(query[role], {
|
refetch: referralRefetch,
|
||||||
variables: {
|
} = useReferralSetsQuery({
|
||||||
partyId: pubKey,
|
variables,
|
||||||
},
|
skip,
|
||||||
skip: !pubKey,
|
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-and-network',
|
||||||
});
|
});
|
||||||
|
|
||||||
// A user can only have 1 active referral program at a time
|
// A user can only have 1 active referral program at a time
|
||||||
const referral = referralData?.referralSets.edges.length
|
const referralSet =
|
||||||
? referralData.referralSets.edges[0].node
|
referralData?.referralSets.edges &&
|
||||||
: undefined;
|
referralData.referralSets.edges.length > 0
|
||||||
|
? referralData.referralSets.edges[0]?.node
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: refereesData,
|
data: refereesData,
|
||||||
loading: refereesLoading,
|
loading: refereesLoading,
|
||||||
error: refereesError,
|
error: refereesError,
|
||||||
} = useQuery(REFEREES_QUERY, {
|
refetch: refereesRefetch,
|
||||||
|
} = useRefereesQuery({
|
||||||
variables: {
|
variables: {
|
||||||
code: referral?.id,
|
code: referralSet?.id as string,
|
||||||
|
aggregationDays:
|
||||||
|
args.aggregationDays != null
|
||||||
|
? args.aggregationDays
|
||||||
|
: DEFAULT_AGGREGATION_DAYS,
|
||||||
},
|
},
|
||||||
skip: !referral?.id,
|
skip: !referralSet?.id,
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-and-network',
|
||||||
|
context: { isEnlargedTimeout: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
const referees = removePaginationWrapper(
|
const referees = compact(
|
||||||
refereesData?.referralSetReferees.edges
|
removePaginationWrapper(refereesData?.referralSetReferees.edges)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const refetch = useCallback(() => {
|
||||||
|
referralRefetch();
|
||||||
|
refereesRefetch();
|
||||||
|
}, [refereesRefetch, referralRefetch]);
|
||||||
|
|
||||||
|
const byReferee =
|
||||||
|
'role' in args && 'pubKey' in args && args.role === 'referee';
|
||||||
|
const referee = byReferee
|
||||||
|
? referees.find((r) => r.refereeId === args.pubKey) || null
|
||||||
|
: null;
|
||||||
|
|
||||||
const data =
|
const data =
|
||||||
referral && refereesData
|
referralSet && refereesData
|
||||||
? {
|
? {
|
||||||
code: referral.id,
|
code: referralSet.id,
|
||||||
|
role: 'role' in args ? args.role : null,
|
||||||
|
referee: referee,
|
||||||
|
referrerId: referralSet.referrer,
|
||||||
|
createdAt: referralSet.createdAt,
|
||||||
referees,
|
referees,
|
||||||
}
|
}
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: data as ReferralData | undefined,
|
data,
|
||||||
loading: referralLoading || refereesLoading,
|
loading: referralLoading || refereesLoading,
|
||||||
error: referralError || refereesError,
|
error: referralError || refereesError,
|
||||||
|
refetch,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,66 +1,44 @@
|
|||||||
import { Tile } from './tile';
|
import { CodeTile, StatTile } from './tile';
|
||||||
import {
|
import {
|
||||||
CopyWithTooltip,
|
|
||||||
Input,
|
|
||||||
VegaIcon,
|
VegaIcon,
|
||||||
VegaIconNames,
|
VegaIconNames,
|
||||||
|
truncateMiddle,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { Button, RainbowButton } from './buttons';
|
|
||||||
|
|
||||||
import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import type { ReferralData } from './hooks/use-referral';
|
|
||||||
import { useReferral } from './hooks/use-referral';
|
import { useReferral } from './hooks/use-referral';
|
||||||
import { CreateCodeContainer } from './create-code-form';
|
import { CreateCodeContainer } from './create-code-form';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { Table } from './table';
|
||||||
const CodeTile = ({
|
import {
|
||||||
code,
|
addDecimalsFormatNumber,
|
||||||
as,
|
getDateFormat,
|
||||||
}: {
|
getDateTimeFormat,
|
||||||
code: string;
|
getNumberFormat,
|
||||||
as: 'referrer' | 'referee';
|
getUserLocale,
|
||||||
}) => {
|
removePaginationWrapper,
|
||||||
return (
|
} from '@vegaprotocol/utils';
|
||||||
<Tile variant="rainbow">
|
import { useReferralSetStatsQuery } from './hooks/__generated__/ReferralSetStats';
|
||||||
<h3 className="mb-1 text-lg calt">Your referral code</h3>
|
import compact from 'lodash/compact';
|
||||||
{as === 'referrer' && (
|
import { useReferralProgram } from './hooks/use-referral-program';
|
||||||
<p className="mb-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100">
|
import { useStakeAvailable } from './hooks/use-stake-available';
|
||||||
Share this code with friends
|
import sortBy from 'lodash/sortBy';
|
||||||
</p>
|
import { useLayoutEffect, useRef, useState } from 'react';
|
||||||
)}
|
import { useCurrentEpochInfoQuery } from './hooks/__generated__/Epoch';
|
||||||
<div className="flex gap-2">
|
import BigNumber from 'bignumber.js';
|
||||||
<Input size={1} readOnly value={code} />
|
|
||||||
<CopyWithTooltip text={code}>
|
|
||||||
<Button
|
|
||||||
className="text-sm no-underline"
|
|
||||||
icon={<VegaIcon name={VegaIconNames.COPY} />}
|
|
||||||
>
|
|
||||||
<span>Copy</span>
|
|
||||||
</Button>
|
|
||||||
</CopyWithTooltip>
|
|
||||||
</div>
|
|
||||||
</Tile>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ReferralStatistics = () => {
|
export const ReferralStatistics = () => {
|
||||||
const openWalletDialog = useVegaWalletDialogStore(
|
|
||||||
(store) => store.openVegaWalletDialog
|
|
||||||
);
|
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
|
|
||||||
const { data: referee } = useReferral(pubKey, 'referee');
|
const { data: referee } = useReferral({
|
||||||
const { data: referrer } = useReferral(pubKey, 'referrer');
|
pubKey,
|
||||||
|
role: 'referee',
|
||||||
|
});
|
||||||
|
const { data: referrer } = useReferral({
|
||||||
|
pubKey,
|
||||||
|
role: 'referrer',
|
||||||
|
});
|
||||||
|
|
||||||
if (!pubKey) {
|
|
||||||
return (
|
|
||||||
<div className="text-center">
|
|
||||||
<RainbowButton variant="border" onClick={() => openWalletDialog()}>
|
|
||||||
Connect wallet
|
|
||||||
</RainbowButton>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (referee?.code) {
|
if (referee?.code) {
|
||||||
return <Statistics data={referee} as="referee" />;
|
return <Statistics data={referee} as="referee" />;
|
||||||
}
|
}
|
||||||
@ -72,42 +50,260 @@ export const ReferralStatistics = () => {
|
|||||||
return <CreateCodeContainer />;
|
return <CreateCodeContainer />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Statistics = ({
|
export const Statistics = ({
|
||||||
data,
|
data,
|
||||||
as,
|
as,
|
||||||
}: {
|
}: {
|
||||||
data: ReferralData;
|
data: NonNullable<ReturnType<typeof useReferral>['data']>;
|
||||||
as: 'referrer' | 'referee';
|
as: 'referrer' | 'referee';
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
const { data: epochData } = useCurrentEpochInfoQuery();
|
||||||
<div
|
const { stakeAvailable } = useStakeAvailable();
|
||||||
className={classNames('grid grid-cols-1 grid-rows-1 gap-5 mx-auto', {
|
const { benefitTiers } = useReferralProgram();
|
||||||
'md:w-1/2': as === 'referee',
|
const { data: statsData } = useReferralSetStatsQuery({
|
||||||
'md:w-2/3': as === 'referrer',
|
variables: {
|
||||||
})}
|
code: data.code,
|
||||||
|
},
|
||||||
|
skip: !data?.code,
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentEpoch = Number(epochData?.epoch.id);
|
||||||
|
|
||||||
|
const stats =
|
||||||
|
statsData?.referralSetStats.edges &&
|
||||||
|
compact(removePaginationWrapper(statsData.referralSetStats.edges));
|
||||||
|
const refereeInfo = data.referee;
|
||||||
|
const refereeStats = stats?.find(
|
||||||
|
(r) => r.partyId === data.referee?.refereeId
|
||||||
|
);
|
||||||
|
|
||||||
|
const statsAvailable = stats && stats.length > 0 && stats[0];
|
||||||
|
const baseCommissionValue = statsAvailable
|
||||||
|
? Number(statsAvailable.rewardFactor)
|
||||||
|
: 0;
|
||||||
|
const runningVolumeValue = statsAvailable
|
||||||
|
? Number(statsAvailable.referralSetRunningNotionalTakerVolume)
|
||||||
|
: 0;
|
||||||
|
const multiplier = statsAvailable
|
||||||
|
? Number(statsAvailable.rewardsMultiplier)
|
||||||
|
: 1;
|
||||||
|
const finalCommissionValue = !isNaN(multiplier)
|
||||||
|
? baseCommissionValue
|
||||||
|
: multiplier * baseCommissionValue;
|
||||||
|
|
||||||
|
const discountFactorValue = refereeStats?.discountFactor
|
||||||
|
? Number(refereeStats.discountFactor)
|
||||||
|
: 0;
|
||||||
|
const currentBenefitTierValue = benefitTiers.find(
|
||||||
|
(t) =>
|
||||||
|
!isNaN(discountFactorValue) &&
|
||||||
|
!isNaN(t.discountFactor) &&
|
||||||
|
t.discountFactor === discountFactorValue
|
||||||
|
);
|
||||||
|
const nextBenefitTierValue =
|
||||||
|
currentBenefitTierValue &&
|
||||||
|
benefitTiers.find((t) => t.tier === currentBenefitTierValue.tier - 1);
|
||||||
|
const epochsValue =
|
||||||
|
!isNaN(currentEpoch) && refereeInfo?.atEpoch
|
||||||
|
? currentEpoch - refereeInfo?.atEpoch
|
||||||
|
: 0;
|
||||||
|
const nextBenefitTierVolumeValue = nextBenefitTierValue
|
||||||
|
? nextBenefitTierValue.minimumVolume - runningVolumeValue
|
||||||
|
: 0;
|
||||||
|
const nextBenefitTierEpochsValue = nextBenefitTierValue
|
||||||
|
? nextBenefitTierValue.epochs - epochsValue
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
const baseCommissionTile = (
|
||||||
|
<StatTile title="Base commission rate">
|
||||||
|
{baseCommissionValue * 100}%
|
||||||
|
</StatTile>
|
||||||
|
);
|
||||||
|
const stakingMultiplierTile = (
|
||||||
|
<StatTile
|
||||||
|
title="Staking multiplier"
|
||||||
|
description={`(${addDecimalsFormatNumber(
|
||||||
|
stakeAvailable?.toString() || 0,
|
||||||
|
18
|
||||||
|
)} $VEGA staked)`}
|
||||||
>
|
>
|
||||||
<div
|
{multiplier || 'None'}
|
||||||
className={classNames('grid grid-rows-1 gap-5', {
|
</StatTile>
|
||||||
'grid-cols-2': as === 'referrer',
|
);
|
||||||
'grid-cols-1': as === 'referee',
|
const finalCommissionTile = (
|
||||||
})}
|
<StatTile title="Final commission rate">
|
||||||
>
|
{finalCommissionValue * 100}%
|
||||||
{as === 'referrer' && data?.referees && (
|
</StatTile>
|
||||||
<Tile className="py-3 h-full">
|
);
|
||||||
<div className="absolute top-1/2 left-1/2 translate-x-[-50%] translate-y-[-50%]">
|
const numberOfTradersValue = data.referees.length;
|
||||||
<h3 className="mb-1 text-6xl text-center">
|
const numberOfTradersTile = (
|
||||||
{data.referees.length}
|
<StatTile title="Number of traders">{numberOfTradersValue}</StatTile>
|
||||||
</h3>
|
);
|
||||||
<p className="text-sm text-center text-vega-clight-100 dark:text-vega-cdark-100">
|
|
||||||
{data.referees.length === 1
|
const codeTile = <CodeTile code={data?.code} />;
|
||||||
? 'Trader referred'
|
const createdAtTile = (
|
||||||
: 'Total traders referred'}
|
<StatTile title="Created at">
|
||||||
</p>
|
<span className="text-3xl">
|
||||||
</div>
|
{getDateFormat().format(new Date(data.createdAt))}
|
||||||
</Tile>
|
</span>
|
||||||
)}
|
</StatTile>
|
||||||
<CodeTile code={data?.code} as={as} />
|
);
|
||||||
|
|
||||||
|
const totalCommissionValue = data.referees
|
||||||
|
.map((r) => new BigNumber(r.totalRefereeGeneratedRewards))
|
||||||
|
.reduce((all, r) => all.plus(r), new BigNumber(0));
|
||||||
|
const totalCommissionTile = (
|
||||||
|
<StatTile title="Total commission (last 30 days)" description="(Quantum)">
|
||||||
|
{getNumberFormat(0).format(Number(totalCommissionValue))}
|
||||||
|
</StatTile>
|
||||||
|
);
|
||||||
|
|
||||||
|
const referrerTiles = (
|
||||||
|
<>
|
||||||
|
<div className="grid grid-rows-1 gap-5 grid-cols-1 md:grid-cols-3">
|
||||||
|
{baseCommissionTile}
|
||||||
|
{stakingMultiplierTile}
|
||||||
|
{finalCommissionTile}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div className="grid grid-rows-1 gap-5 grid-cols-1 sm:grid-cols-2 xl:grid-cols-4">
|
||||||
|
{codeTile}
|
||||||
|
{createdAtTile}
|
||||||
|
{numberOfTradersTile}
|
||||||
|
{totalCommissionTile}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const compactNumFormat = new Intl.NumberFormat(getUserLocale(), {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 2,
|
||||||
|
notation: 'compact',
|
||||||
|
compactDisplay: 'short',
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentBenefitTierTile = (
|
||||||
|
<StatTile title="Current tier">
|
||||||
|
{currentBenefitTierValue?.tier || '-'}
|
||||||
|
</StatTile>
|
||||||
|
);
|
||||||
|
const discountFactorTile = (
|
||||||
|
<StatTile title="Discount">{discountFactorValue * 100}%</StatTile>
|
||||||
|
);
|
||||||
|
const runningVolumeTile = (
|
||||||
|
<StatTile title="Combined volume">
|
||||||
|
{compactNumFormat.format(runningVolumeValue)}
|
||||||
|
</StatTile>
|
||||||
|
);
|
||||||
|
const epochsTile = <StatTile title="Epochs in set">{epochsValue}</StatTile>;
|
||||||
|
const nextTierVolumeTile = (
|
||||||
|
<StatTile title="Volume to next tier">
|
||||||
|
{nextBenefitTierVolumeValue <= 0
|
||||||
|
? '-'
|
||||||
|
: compactNumFormat.format(nextBenefitTierVolumeValue)}
|
||||||
|
</StatTile>
|
||||||
|
);
|
||||||
|
const nextTierEpochsTile = (
|
||||||
|
<StatTile title="Epochs to next tier">
|
||||||
|
{nextBenefitTierEpochsValue <= 0 ? '-' : nextBenefitTierEpochsValue}
|
||||||
|
</StatTile>
|
||||||
|
);
|
||||||
|
|
||||||
|
const refereeTiles = (
|
||||||
|
<>
|
||||||
|
<div className="grid grid-rows-1 gap-5 grid-cols-1 md:grid-cols-3">
|
||||||
|
{currentBenefitTierTile}
|
||||||
|
{discountFactorTile}
|
||||||
|
{codeTile}
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-rows-1 gap-5 grid-cols-1 sm:grid-cols-2 xl:grid-cols-4">
|
||||||
|
{runningVolumeTile}
|
||||||
|
{nextTierVolumeTile}
|
||||||
|
{epochsTile}
|
||||||
|
{nextTierEpochsTile}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
const tableRef = useRef<HTMLTableElement>(null);
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if ((tableRef.current?.getBoundingClientRect().height || 0) > 384) {
|
||||||
|
setCollapsed(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Stats tiles */}
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'grid grid-cols-1 grid-rows-1 gap-5 mx-auto mb-20'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{as === 'referrer' && referrerTiles}
|
||||||
|
{as === 'referee' && refereeTiles}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Referees (only for referrer view) */}
|
||||||
|
{as === 'referrer' && data.referees.length > 0 && (
|
||||||
|
<div className="mt-20 mb-20">
|
||||||
|
<h2 className="text-2xl mb-5">Referees</h2>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
collapsed && [
|
||||||
|
'relative max-h-96 overflow-hidden',
|
||||||
|
'after:w-full after:h-20 after:absolute after:bottom-0 after:left-0',
|
||||||
|
'after:bg-gradient-to-t after:from-white after:dark:from-vega-cdark-900 after:to-transparent',
|
||||||
|
]
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className={classNames(
|
||||||
|
'absolute left-1/2 bottom-0 z-10 p-2 translate-x-[-50%]',
|
||||||
|
{
|
||||||
|
hidden: !collapsed,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
onClick={() => setCollapsed(false)}
|
||||||
|
>
|
||||||
|
<VegaIcon name={VegaIconNames.CHEVRON_DOWN} size={24} />
|
||||||
|
</button>
|
||||||
|
<Table
|
||||||
|
ref={tableRef}
|
||||||
|
columns={[
|
||||||
|
{ name: 'party', displayName: 'Trader' },
|
||||||
|
{ name: 'joined', displayName: 'Date Joined' },
|
||||||
|
{ name: 'volume', displayName: 'Volume (last 30 days)' },
|
||||||
|
{
|
||||||
|
name: 'commission',
|
||||||
|
displayName: 'Commission earned (last 30 days)',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
data={sortBy(
|
||||||
|
data.referees.map((r) => ({
|
||||||
|
party: (
|
||||||
|
<span title={r.refereeId}>
|
||||||
|
{truncateMiddle(r.refereeId)}
|
||||||
|
</span>
|
||||||
|
),
|
||||||
|
joined: getDateTimeFormat().format(new Date(r.joinedAt)),
|
||||||
|
volume: Number(r.totalRefereeNotionalTakerVolume),
|
||||||
|
commission: Number(r.totalRefereeGeneratedRewards),
|
||||||
|
})),
|
||||||
|
(r) => r.volume
|
||||||
|
)
|
||||||
|
.map((r) => ({
|
||||||
|
...r,
|
||||||
|
volume: getNumberFormat(0).format(r.volume),
|
||||||
|
commission: getNumberFormat(0).format(r.commission),
|
||||||
|
}))
|
||||||
|
.reverse()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
Loader,
|
||||||
TradingAnchorButton,
|
TradingAnchorButton,
|
||||||
VegaIcon,
|
VegaIcon,
|
||||||
VegaIconNames,
|
VegaIconNames,
|
||||||
@ -6,35 +7,82 @@ import {
|
|||||||
import { HowItWorksTable } from './how-it-works-table';
|
import { HowItWorksTable } from './how-it-works-table';
|
||||||
import { LandingBanner } from './landing-banner';
|
import { LandingBanner } from './landing-banner';
|
||||||
import { TiersContainer } from './tiers';
|
import { TiersContainer } from './tiers';
|
||||||
import { RainbowTabLink } from './buttons';
|
import { TabLink } from './buttons';
|
||||||
import { Outlet } from 'react-router-dom';
|
import { Outlet } from 'react-router-dom';
|
||||||
import { Routes } from '../../lib/links';
|
import { Routes } from '../../lib/links';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { useReferral } from './hooks/use-referral';
|
import { useReferral } from './hooks/use-referral';
|
||||||
|
import { REFERRAL_DOCS_LINK } from './constants';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { usePageTitleStore } from '../../stores';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { titlefy } from '@vegaprotocol/utils';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
|
||||||
|
const Nav = () => (
|
||||||
|
<div className="flex justify-center border-b border-vega-cdark-500">
|
||||||
|
<TabLink end to={Routes.REFERRALS}>
|
||||||
|
I want a code
|
||||||
|
</TabLink>
|
||||||
|
<TabLink to={Routes.REFERRALS_APPLY_CODE}>I have a code</TabLink>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
export const Referrals = () => {
|
export const Referrals = () => {
|
||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
const { data: referee } = useReferral(pubKey, 'referee');
|
|
||||||
const { data: referrer } = useReferral(pubKey, 'referrer');
|
const {
|
||||||
|
data: referee,
|
||||||
|
loading: refereeLoading,
|
||||||
|
error: refereeError,
|
||||||
|
} = useReferral({
|
||||||
|
pubKey,
|
||||||
|
role: 'referee',
|
||||||
|
});
|
||||||
|
const {
|
||||||
|
data: referrer,
|
||||||
|
loading: referrerLoading,
|
||||||
|
error: referrerError,
|
||||||
|
} = useReferral({
|
||||||
|
pubKey,
|
||||||
|
role: 'referrer',
|
||||||
|
});
|
||||||
|
|
||||||
|
const error = refereeError || referrerError;
|
||||||
|
const loading = refereeLoading || referrerLoading;
|
||||||
|
const showNav = !loading && !error && !referrer && !referee;
|
||||||
|
|
||||||
|
const { updateTitle } = usePageTitleStore((store) => ({
|
||||||
|
updateTitle: store.updateTitle,
|
||||||
|
}));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateTitle(titlefy([t('Referrals')]));
|
||||||
|
}, [updateTitle]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LandingBanner />
|
<LandingBanner />
|
||||||
<div>
|
|
||||||
<div className="flex justify-center">
|
{showNav && <Nav />}
|
||||||
<RainbowTabLink end to={Routes.REFERRALS}>
|
<div
|
||||||
Your referrals
|
className={classNames({
|
||||||
</RainbowTabLink>
|
'py-16': showNav,
|
||||||
<RainbowTabLink
|
'h-[300px] relative': loading || error,
|
||||||
disabled={Boolean(referee || referrer)}
|
})}
|
||||||
to={Routes.REFERRALS_APPLY_CODE}
|
>
|
||||||
>
|
{loading ? (
|
||||||
Apply a code
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2">
|
||||||
</RainbowTabLink>
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
<div className="py-16 border-t border-b border-vega-cdark-500">
|
) : error ? (
|
||||||
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-center">
|
||||||
|
<p>Something went wrong</p>
|
||||||
|
<span className="text-xs">{error.message}</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TiersContainer />
|
<TiersContainer />
|
||||||
@ -47,7 +95,7 @@ export const Referrals = () => {
|
|||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<TradingAnchorButton
|
<TradingAnchorButton
|
||||||
className="mx-auto w-max"
|
className="mx-auto w-max"
|
||||||
href="https://docs.vega.xyz/"
|
href={REFERRAL_DOCS_LINK}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
Read the terms <VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
|
Read the terms <VegaIcon name={VegaIconNames.OPEN_EXTERNAL} />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
import { Tooltip, VegaIcon, VegaIconNames } from '@vegaprotocol/ui-toolkit';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import type { HTMLAttributes } from 'react';
|
import { forwardRef, type HTMLAttributes } from 'react';
|
||||||
import { BORDER_COLOR, GRADIENT } from './constants';
|
import { BORDER_COLOR, GRADIENT } from './constants';
|
||||||
|
|
||||||
type TableColumnDefinition = {
|
type TableColumnDefinition = {
|
||||||
@ -19,98 +19,108 @@ type TableProps = {
|
|||||||
|
|
||||||
const INNER_BORDER_STYLE = `border-b ${BORDER_COLOR}`;
|
const INNER_BORDER_STYLE = `border-b ${BORDER_COLOR}`;
|
||||||
|
|
||||||
export const Table = ({
|
export const Table = forwardRef<
|
||||||
columns,
|
HTMLTableElement,
|
||||||
data,
|
TableProps & HTMLAttributes<HTMLTableElement>
|
||||||
noHeader = false,
|
>(
|
||||||
noCollapse = false,
|
(
|
||||||
className,
|
{
|
||||||
...props
|
columns,
|
||||||
}: TableProps & HTMLAttributes<HTMLTableElement>) => {
|
data,
|
||||||
const header = (
|
noHeader = false,
|
||||||
<thead className={classNames({ 'max-md:hidden': !noCollapse })}>
|
noCollapse = false,
|
||||||
<tr>
|
className,
|
||||||
{columns.map(({ displayName, name, tooltip }) => (
|
...props
|
||||||
<th
|
},
|
||||||
key={name}
|
ref
|
||||||
col-id={name}
|
) => {
|
||||||
className={classNames(
|
const header = (
|
||||||
'px-5 py-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100',
|
<thead className={classNames({ 'max-md:hidden': !noCollapse })}>
|
||||||
INNER_BORDER_STYLE
|
<tr>
|
||||||
)}
|
{columns.map(({ displayName, name, tooltip }) => (
|
||||||
>
|
<th
|
||||||
<span className="flex flex-row gap-2 items-center">
|
key={name}
|
||||||
<span>{displayName}</span>
|
col-id={name}
|
||||||
{tooltip ? (
|
className={classNames(
|
||||||
<Tooltip description={tooltip}>
|
'px-5 py-3 text-sm text-vega-clight-100 dark:text-vega-cdark-100 font-normal',
|
||||||
<button className="text-vega-clight-400 dark:text-vega-cdark-400 no-underline decoration-transparent w-[12px] h-[12px] inline-flex">
|
INNER_BORDER_STYLE
|
||||||
<VegaIcon size={12} name={VegaIconNames.INFO} />
|
)}
|
||||||
</button>
|
>
|
||||||
</Tooltip>
|
<span className="flex flex-row gap-2 items-center">
|
||||||
) : null}
|
<span>{displayName}</span>
|
||||||
</span>
|
{tooltip ? (
|
||||||
</th>
|
<Tooltip description={tooltip}>
|
||||||
))}
|
<button className="text-vega-clight-400 dark:text-vega-cdark-400 no-underline decoration-transparent w-[12px] h-[12px] inline-flex">
|
||||||
</tr>
|
<VegaIcon size={12} name={VegaIconNames.INFO} />
|
||||||
</thead>
|
</button>
|
||||||
);
|
</Tooltip>
|
||||||
return (
|
) : null}
|
||||||
<table
|
</span>
|
||||||
className={classNames(
|
</th>
|
||||||
'w-full',
|
))}
|
||||||
'border-separate border rounded-md border-spacing-0',
|
</tr>
|
||||||
BORDER_COLOR,
|
</thead>
|
||||||
GRADIENT,
|
);
|
||||||
className
|
return (
|
||||||
)}
|
<table
|
||||||
{...props}
|
ref={ref}
|
||||||
>
|
className={classNames(
|
||||||
{!noHeader && header}
|
'w-full',
|
||||||
<tbody>
|
'border-separate border rounded-md border-spacing-0',
|
||||||
{data.map((d, i) => (
|
BORDER_COLOR,
|
||||||
<tr
|
GRADIENT,
|
||||||
key={i}
|
className
|
||||||
className={classNames(d['className'] as string, {
|
)}
|
||||||
'max-md:flex flex-col w-full': !noCollapse,
|
{...props}
|
||||||
})}
|
>
|
||||||
>
|
{!noHeader && header}
|
||||||
{columns.map(({ name, displayName, className }, j) => (
|
<tbody>
|
||||||
<td
|
{data.map((d, i) => (
|
||||||
className={classNames(
|
<tr
|
||||||
'px-5 py-3 text-base',
|
key={i}
|
||||||
{
|
className={classNames(d['className'] as string, {
|
||||||
'max-md:flex max-md:flex-col max-md:justify-between':
|
'max-md:flex flex-col w-full': !noCollapse,
|
||||||
!noCollapse,
|
})}
|
||||||
},
|
>
|
||||||
INNER_BORDER_STYLE,
|
{columns.map(({ name, displayName, className }, j) => (
|
||||||
{
|
<td
|
||||||
'border-none': i === data.length - 1 && noCollapse,
|
className={classNames(
|
||||||
'md:border-none': i === data.length - 1,
|
'px-5 py-3 text-base',
|
||||||
'max-md:border-none':
|
{
|
||||||
i === data.length - 1 && j === columns.length - 1,
|
'max-md:flex max-md:flex-col max-md:justify-between':
|
||||||
},
|
!noCollapse,
|
||||||
className
|
},
|
||||||
)}
|
INNER_BORDER_STYLE,
|
||||||
key={`${i}-${name}`}
|
{
|
||||||
>
|
'border-none': i === data.length - 1 && noCollapse,
|
||||||
{/** display column name in mobile view */}
|
'md:border-none': i === data.length - 1,
|
||||||
{!noCollapse &&
|
'max-md:border-none':
|
||||||
!noHeader &&
|
i === data.length - 1 && j === columns.length - 1,
|
||||||
displayName &&
|
},
|
||||||
displayName.length > 0 && (
|
className
|
||||||
<span
|
|
||||||
aria-hidden
|
|
||||||
className="md:hidden font-mono text-xs px-0 text-vega-clight-100 dark:text-vega-cdark-100"
|
|
||||||
>
|
|
||||||
{displayName}
|
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
<span>{d[name]}</span>
|
key={`${i}-${name}`}
|
||||||
</td>
|
>
|
||||||
))}
|
{/** display column name in mobile view */}
|
||||||
</tr>
|
{!noCollapse &&
|
||||||
))}
|
!noHeader &&
|
||||||
</tbody>
|
displayName &&
|
||||||
</table>
|
displayName.length > 0 && (
|
||||||
);
|
<span
|
||||||
};
|
aria-hidden
|
||||||
|
className="md:hidden font-mono text-xs px-0 text-vega-clight-100 dark:text-vega-cdark-100"
|
||||||
|
>
|
||||||
|
{displayName}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<span>{d[name]}</span>
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Table.displayName = 'Table';
|
||||||
|
@ -12,7 +12,7 @@ export const Tag = ({
|
|||||||
}: TagProps & HTMLAttributes<HTMLDivElement>) => (
|
}: TagProps & HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'mt-3 w-max border rounded-[1rem] py-[0.125rem] px-2 text-xs',
|
'w-max border rounded-[1rem] py-[0.125rem] px-2 text-xs',
|
||||||
{
|
{
|
||||||
'border-vega-yellow-500 text-vega-yellow-500': color === 'yellow',
|
'border-vega-yellow-500 text-vega-yellow-500': color === 'yellow',
|
||||||
'border-vega-green-500 text-vega-green-500': color === 'green',
|
'border-vega-green-500 text-vega-green-500': color === 'green',
|
||||||
|
@ -4,7 +4,9 @@ import { Table } from './table';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { BORDER_COLOR, GRADIENT } from './constants';
|
import { BORDER_COLOR, GRADIENT } from './constants';
|
||||||
import { Tag } from './tag';
|
import { Tag } from './tag';
|
||||||
import type { ComponentProps } from 'react';
|
import type { ComponentProps, ReactNode } from 'react';
|
||||||
|
import { ExternalLink } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { DApp, TOKEN_PROPOSALS, useLinks } from '@vegaprotocol/environment';
|
||||||
|
|
||||||
const Loading = ({ variant }: { variant: 'large' | 'inline' }) => (
|
const Loading = ({ variant }: { variant: 'large' | 'inline' }) => (
|
||||||
<div
|
<div
|
||||||
@ -38,51 +40,63 @@ const StakingTier = ({
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
'overflow-hidden',
|
'overflow-hidden',
|
||||||
'border rounded-md w-full',
|
'border rounded-md w-full',
|
||||||
|
'flex flex-row',
|
||||||
|
GRADIENT,
|
||||||
BORDER_COLOR
|
BORDER_COLOR
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div aria-hidden>
|
<div aria-hidden className="max-w-[120px]">
|
||||||
{tier < 4 && (
|
{tier < 4 && (
|
||||||
// eslint-disable-next-line @next/next/no-img-element
|
// eslint-disable-next-line @next/next/no-img-element
|
||||||
<img
|
<img
|
||||||
src={`/${tier}x.png`}
|
src={`/${tier}x.png`}
|
||||||
alt={`${referralRewardMultiplier}x multiplier`}
|
alt={`${referralRewardMultiplier}x multiplier`}
|
||||||
width={768}
|
width={240}
|
||||||
height={400}
|
height={240}
|
||||||
className="w-full"
|
className="w-full h-full"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={classNames('p-3', GRADIENT)}>
|
<div className={classNames('p-3')}>
|
||||||
<h3 className="mb-3 text-xl">{label}</h3>
|
<Tag color={color[tier]}>Multiplier {referralRewardMultiplier}x</Tag>
|
||||||
<p className="text-base text-vega-clight-100 dark:text-vega-cdark-100">
|
<h3 className="mt-1 mb-1 text-base">{label}</h3>
|
||||||
|
<p className="text-sm text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
Stake a minimum of {minimumStakedTokens} $VEGA tokens
|
Stake a minimum of {minimumStakedTokens} $VEGA tokens
|
||||||
</p>
|
</p>
|
||||||
<Tag color={color[tier]}>
|
|
||||||
Reward multiplier {referralRewardMultiplier}x
|
|
||||||
</Tag>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TiersContainer = () => {
|
export const TiersContainer = () => {
|
||||||
const { benefitTiers, stakingTiers, details, loading } = useReferralProgram();
|
const { benefitTiers, stakingTiers, details, loading, error } =
|
||||||
|
useReferralProgram();
|
||||||
|
|
||||||
const ends = details?.endOfProgramTimestamp
|
const ends = details?.endOfProgramTimestamp
|
||||||
? getDateTimeFormat().format(new Date(details.endOfProgramTimestamp))
|
? getDateTimeFormat().format(new Date(details.endOfProgramTimestamp))
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const governanceLink = useLinks(DApp.Governance);
|
||||||
|
|
||||||
|
if ((!loading && !details) || error) {
|
||||||
|
return (
|
||||||
|
<div className="text-base px-5 py-10 text-center">
|
||||||
|
We're sorry but we don't have an active referral programme
|
||||||
|
currently running. You can propose a new programme{' '}
|
||||||
|
<ExternalLink href={governanceLink(TOKEN_PROPOSALS)}>here</ExternalLink>
|
||||||
|
.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-row items-baseline justify-between mt-10 mb-5">
|
{/* Benefit tiers */}
|
||||||
|
<div className="flex flex-col items-baseline justify-between mt-10 mb-5">
|
||||||
<h2 className="text-2xl">Referral tiers</h2>
|
<h2 className="text-2xl">Referral tiers</h2>
|
||||||
{ends && (
|
{ends && (
|
||||||
<span className="text-base">
|
<span className="text-sm text-vega-clight-200 dark:text-vega-cdark-200">
|
||||||
<span className="text-vega-clight-200 dark:text-vega-cdark-200">
|
Program ends: {ends}
|
||||||
Program ends:
|
|
||||||
</span>{' '}
|
|
||||||
{ends}
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -90,14 +104,24 @@ export const TiersContainer = () => {
|
|||||||
{loading || !benefitTiers || benefitTiers.length === 0 ? (
|
{loading || !benefitTiers || benefitTiers.length === 0 ? (
|
||||||
<Loading variant="large" />
|
<Loading variant="large" />
|
||||||
) : (
|
) : (
|
||||||
<TiersTable data={benefitTiers} />
|
<TiersTable
|
||||||
|
data={benefitTiers.map((bt) => ({
|
||||||
|
...bt,
|
||||||
|
tierElement: (
|
||||||
|
<div className="rounded-full bg-vega-clight-900 dark:bg-vega-cdark-900 p-1 w-8 h-8 text-center">
|
||||||
|
{bt.tier}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Staking tiers */}
|
||||||
<div className="flex flex-row items-baseline justify-between mb-5">
|
<div className="flex flex-row items-baseline justify-between mb-5">
|
||||||
<h2 className="text-2xl">Staking multipliers</h2>
|
<h2 className="text-2xl">Staking multipliers</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col mb-20 justify-items-stretch md:flex-row gap-5">
|
<div className="mb-20 flex flex-col justify-items-stretch lg:flex-row gap-5">
|
||||||
{loading || !stakingTiers || stakingTiers.length === 0 ? (
|
{loading || !stakingTiers || stakingTiers.length === 0 ? (
|
||||||
<>
|
<>
|
||||||
<Loading variant="large" />
|
<Loading variant="large" />
|
||||||
@ -137,6 +161,7 @@ const TiersTable = ({
|
|||||||
}: {
|
}: {
|
||||||
data: Array<{
|
data: Array<{
|
||||||
tier: number;
|
tier: number;
|
||||||
|
tierElement: ReactNode;
|
||||||
commission: string;
|
commission: string;
|
||||||
discount: string;
|
discount: string;
|
||||||
volume: string;
|
volume: string;
|
||||||
@ -145,7 +170,7 @@ const TiersTable = ({
|
|||||||
return (
|
return (
|
||||||
<Table
|
<Table
|
||||||
columns={[
|
columns={[
|
||||||
{ name: 'tier', displayName: 'Tier' },
|
{ name: 'tierElement', displayName: 'Tier' },
|
||||||
{
|
{
|
||||||
name: 'commission',
|
name: 'commission',
|
||||||
displayName: 'Referrer commission',
|
displayName: 'Referrer commission',
|
||||||
@ -153,6 +178,7 @@ const TiersTable = ({
|
|||||||
},
|
},
|
||||||
{ name: 'discount', displayName: 'Referrer trading discount' },
|
{ name: 'discount', displayName: 'Referrer trading discount' },
|
||||||
{ name: 'volume', displayName: 'Min. trading volume' },
|
{ name: 'volume', displayName: 'Min. trading volume' },
|
||||||
|
{ name: 'epochs', displayName: 'Min. epochs' },
|
||||||
]}
|
]}
|
||||||
data={data.map((d) => ({
|
data={data.map((d) => ({
|
||||||
...d,
|
...d,
|
||||||
|
@ -1,39 +1,92 @@
|
|||||||
|
import {
|
||||||
|
CopyWithTooltip,
|
||||||
|
Tooltip,
|
||||||
|
VegaIcon,
|
||||||
|
VegaIconNames,
|
||||||
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import type { HTMLAttributes } from 'react';
|
import type { HTMLAttributes, ReactNode } from 'react';
|
||||||
import { BORDER_COLOR, GRADIENT } from './constants';
|
import { Button } from './buttons';
|
||||||
|
|
||||||
type TileProps = {
|
|
||||||
variant?: 'rainbow' | 'default';
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Tile = ({
|
export const Tile = ({
|
||||||
variant = 'default',
|
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
}: TileProps & HTMLAttributes<HTMLDivElement>) => {
|
}: HTMLAttributes<HTMLDivElement>) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
{
|
'rounded-lg overflow-hidden relative',
|
||||||
'bg-rainbow p-[0.125rem]': variant === 'rainbow',
|
'bg-vega-clight-800 dark:bg-vega-cdark-800 text-black dark:text-white',
|
||||||
[`border-2 ${BORDER_COLOR} p-0`]: variant === 'default',
|
'p-6',
|
||||||
},
|
className
|
||||||
'rounded-lg overflow-hidden relative'
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
{children}
|
||||||
className={classNames(
|
|
||||||
{
|
|
||||||
'bg-white dark:bg-vega-cdark-900 text-black dark:text-white rounded-[0.35rem] overflow-hidden':
|
|
||||||
variant === 'rainbow',
|
|
||||||
},
|
|
||||||
'p-6',
|
|
||||||
GRADIENT,
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type StatTileProps = {
|
||||||
|
title: string;
|
||||||
|
description?: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
};
|
||||||
|
export const StatTile = ({ title, description, children }: StatTileProps) => {
|
||||||
|
return (
|
||||||
|
<Tile>
|
||||||
|
<h3 className="mb-1 text-sm text-vega-clight-100 dark:text-vega-cdark-100 calt">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
<div className="text-5xl text-left">{children}</div>
|
||||||
|
{description && (
|
||||||
|
<div className="text-sm text-left text-vega-clight-100 dark:text-vega-cdark-100">
|
||||||
|
{description}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Tile>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FADE_OUT_STYLE = classNames(
|
||||||
|
'after:w-5 after:h-full after:absolute after:top-0 after:right-0',
|
||||||
|
'after:bg-gradient-to-l after:from-vega-clight-800 after:dark:from-vega-cdark-800 after:to-transparent'
|
||||||
|
);
|
||||||
|
|
||||||
|
export const CodeTile = ({
|
||||||
|
code,
|
||||||
|
className,
|
||||||
|
}: {
|
||||||
|
code: string;
|
||||||
|
className?: string;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<StatTile title="Your referral code">
|
||||||
|
<div className="flex gap-2 items-center justify-between">
|
||||||
|
<Tooltip
|
||||||
|
description={
|
||||||
|
<div className="break-all">
|
||||||
|
<span className="text-xl bg-rainbow bg-clip-text text-transparent">
|
||||||
|
{code}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'relative bg-rainbow bg-clip-text text-transparent text-5xl overflow-hidden',
|
||||||
|
FADE_OUT_STYLE
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{code}
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
<CopyWithTooltip text={code}>
|
||||||
|
<Button className="text-sm no-underline !py-0 !px-0 h-fit !bg-transparent">
|
||||||
|
<span className="sr-only">Copy</span>
|
||||||
|
<VegaIcon size={24} name={VegaIconNames.COPY} />
|
||||||
|
</Button>
|
||||||
|
</CopyWithTooltip>
|
||||||
|
</div>
|
||||||
|
</StatTile>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -182,7 +182,7 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => {
|
|||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
{FLAGS.REFERRALS && (
|
{FLAGS.REFERRALS && (
|
||||||
<NavbarItem>
|
<NavbarItem>
|
||||||
<NavbarLink to={Links.REFERRALS()} onClick={onClick}>
|
<NavbarLink end={false} to={Links.REFERRALS()} onClick={onClick}>
|
||||||
{t('Referrals')}
|
{t('Referrals')}
|
||||||
</NavbarLink>
|
</NavbarLink>
|
||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
@ -255,16 +255,18 @@ const NavbarLink = ({
|
|||||||
children,
|
children,
|
||||||
to,
|
to,
|
||||||
onClick,
|
onClick,
|
||||||
|
end = true,
|
||||||
}: {
|
}: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
to: string;
|
to: string;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
|
end?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<N.Link asChild={true}>
|
<N.Link asChild={true}>
|
||||||
<NavLink
|
<NavLink
|
||||||
to={to}
|
to={to}
|
||||||
end={true}
|
end={end}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'block lg:flex lg:h-full flex-col justify-center',
|
'block lg:flex lg:h-full flex-col justify-center',
|
||||||
'px-6 py-2 lg:p-0 text-lg lg:text-sm',
|
'px-6 py-2 lg:p-0 text-lg lg:text-sm',
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 614 KiB After Width: | Height: | Size: 126 KiB |
Binary file not shown.
Before Width: | Height: | Size: 572 KiB After Width: | Height: | Size: 120 KiB |
Binary file not shown.
Before Width: | Height: | Size: 574 KiB After Width: | Height: | Size: 120 KiB |
@ -24,8 +24,8 @@ module.exports = {
|
|||||||
...theme.backgroundImage,
|
...theme.backgroundImage,
|
||||||
rainbow:
|
rainbow:
|
||||||
'linear-gradient(103.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
'linear-gradient(103.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
'rainbow-shifted':
|
'rainbow-180':
|
||||||
'linear-gradient(103.47deg, #0075FF 1.68%, #8028FF 47.49%, #FF077F 100%)',
|
'linear-gradient(283.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
highlight:
|
highlight:
|
||||||
'linear-gradient(170deg, var(--tw-gradient-from), transparent var(--tw-gradient-to-position))',
|
'linear-gradient(170deg, var(--tw-gradient-from), transparent var(--tw-gradient-to-position))',
|
||||||
},
|
},
|
||||||
@ -38,10 +38,144 @@ module.exports = {
|
|||||||
'75%': { transform: 'translateX(5px)' },
|
'75%': { transform: 'translateX(5px)' },
|
||||||
'100%': { transform: 'translateX(0)' },
|
'100%': { transform: 'translateX(0)' },
|
||||||
},
|
},
|
||||||
|
'spin-rainbow-180': {
|
||||||
|
'0%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(103.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'10%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(121.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'20%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(139.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'30%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(157.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'40%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(175.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'50%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(193.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'60%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(211.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'70%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(229.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'80%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(247.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'90%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(265.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(283.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'spin-rainbow-360': {
|
||||||
|
'0%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(103.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'5%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(121.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'10%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(139.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'15%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(157.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'20%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(175.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'25%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(193.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'30%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(211.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'35%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(229.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'40%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(247.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'45%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(265.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'50%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(283.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'55%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(301.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'60%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(319.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'65%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(337.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'70%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(355.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'75%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(13.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'80%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(31.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'85%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(49.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'90%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(67.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'95%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(85.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
'100%': {
|
||||||
|
backgroundImage:
|
||||||
|
'linear-gradient(103.47deg, #FF077F 1.68%, #8028FF 47.49%, #0075FF 100%)',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
...theme.animation,
|
...theme.animation,
|
||||||
shake: 'shake 200ms linear',
|
shake: 'shake 200ms linear',
|
||||||
|
'spin-rainbow': 'spin-rainbow-180 500ms linear',
|
||||||
|
'rotate-rainbow': 'spin-rainbow-360 1000ms linear',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
291
libs/types/src/__generated__/types.ts
generated
291
libs/types/src/__generated__/types.ts
generated
@ -68,9 +68,13 @@ export type AccountEvent = {
|
|||||||
|
|
||||||
/** Filter input for historical balance queries */
|
/** Filter input for historical balance queries */
|
||||||
export type AccountFilter = {
|
export type AccountFilter = {
|
||||||
|
/** Restrict accounts to those connected to any of the types in this list. Pass an empty list for no filter. */
|
||||||
accountTypes?: InputMaybe<Array<AccountType>>;
|
accountTypes?: InputMaybe<Array<AccountType>>;
|
||||||
|
/** Restrict accounts to those holding balances in this asset ID. */
|
||||||
assetId?: InputMaybe<Scalars['ID']>;
|
assetId?: InputMaybe<Scalars['ID']>;
|
||||||
|
/** Restrict accounts to those connected to the markets in this list. Pass an empty list for no filter. */
|
||||||
marketIds?: InputMaybe<Array<Scalars['ID']>>;
|
marketIds?: InputMaybe<Array<Scalars['ID']>>;
|
||||||
|
/** Restrict accounts to those owned by the parties in this list. Pass an empty list for no filter. */
|
||||||
partyIds?: InputMaybe<Array<Scalars['ID']>>;
|
partyIds?: InputMaybe<Array<Scalars['ID']>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -510,7 +514,7 @@ export type CurrentReferralProgram = {
|
|||||||
__typename?: 'CurrentReferralProgram';
|
__typename?: 'CurrentReferralProgram';
|
||||||
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
||||||
benefitTiers: Array<BenefitTier>;
|
benefitTiers: Array<BenefitTier>;
|
||||||
/** Timestamp as RFC3339Nano, after which when the current epoch ends, the program will end and benefits will be disabled. */
|
/** Timestamp as Unix time in nanoseconds, after which when the current epoch ends, the program will end and benefits will be disabled. */
|
||||||
endOfProgramTimestamp: Scalars['Timestamp'];
|
endOfProgramTimestamp: Scalars['Timestamp'];
|
||||||
/** Timestamp as RFC3339Nano when the program ended. If present, the current program has ended and no program is currently running. */
|
/** Timestamp as RFC3339Nano when the program ended. If present, the current program has ended and no program is currently running. */
|
||||||
endedAt?: Maybe<Scalars['Timestamp']>;
|
endedAt?: Maybe<Scalars['Timestamp']>;
|
||||||
@ -1272,6 +1276,44 @@ export type Fees = {
|
|||||||
factors: FeeFactors;
|
factors: FeeFactors;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Fees that have been applied on a specific market/asset up to the given epoch. */
|
||||||
|
export type FeesStats = {
|
||||||
|
__typename?: 'FeesStats';
|
||||||
|
/** The settlement asset of the market. */
|
||||||
|
assetId: Scalars['String'];
|
||||||
|
/** The epoch for which these stats were valid. */
|
||||||
|
epoch: Scalars['Int'];
|
||||||
|
/** The total maker fees generated by all parties. */
|
||||||
|
makerFeesGenerated: Array<MakerFeesGenerated>;
|
||||||
|
/** The market the fees were paid in */
|
||||||
|
marketId: Scalars['String'];
|
||||||
|
/** The total referral discounts applied to all referee taker fees */
|
||||||
|
refereesDiscountApplied: Array<PartyAmount>;
|
||||||
|
/** The total referral rewards generated by all referee taker fees. */
|
||||||
|
referrerRewardsGenerated: Array<ReferrerRewardsGenerated>;
|
||||||
|
/** The total maker fees received by the maker side. */
|
||||||
|
totalMakerFeesReceived: Array<PartyAmount>;
|
||||||
|
/** The total referral rewards received by referrer of the referral set. */
|
||||||
|
totalRewardsReceived: Array<PartyAmount>;
|
||||||
|
/** The total volume discounts applied to all referee taker fees */
|
||||||
|
volumeDiscountApplied: Array<PartyAmount>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Fees that have been applied on a specific asset for a given party. */
|
||||||
|
export type FeesStatsForParty = {
|
||||||
|
__typename?: 'FeesStatsForParty';
|
||||||
|
/** The settlement asset of the market. */
|
||||||
|
assetId: Scalars['String'];
|
||||||
|
/** The total referral discounts applied to all referee taker fees */
|
||||||
|
refereesDiscountApplied: Scalars['String'];
|
||||||
|
/** The total maker fees received by the maker side. */
|
||||||
|
totalMakerFeesReceived: Scalars['String'];
|
||||||
|
/** The total referral rewards received by referrer of the referral set. */
|
||||||
|
totalRewardsReceived: Scalars['String'];
|
||||||
|
/** The total volume discounts applied to all referee taker fees */
|
||||||
|
volumeDiscountApplied: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter describes the conditions under which oracle data is considered of
|
* Filter describes the conditions under which oracle data is considered of
|
||||||
* interest or not.
|
* interest or not.
|
||||||
@ -1596,11 +1638,19 @@ export enum LedgerEntryField {
|
|||||||
TransferType = 'TransferType'
|
TransferType = 'TransferType'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Filter for historical entry ledger queries */
|
/** Filter for historical entry ledger queries, you must provide at least one party in FromAccountFilter, or ToAccountFilter */
|
||||||
export type LedgerEntryFilter = {
|
export type LedgerEntryFilter = {
|
||||||
|
/**
|
||||||
|
* Determines whether an entry must have accounts matching both the account_from_filter
|
||||||
|
* and the account_to_filter. If set to 'true', entries must have matches in both filters.
|
||||||
|
* If set to `false`, entries matching only the account_from_filter or the account_to_filter will also be included.
|
||||||
|
*/
|
||||||
CloseOnAccountFilters?: InputMaybe<Scalars['Boolean']>;
|
CloseOnAccountFilters?: InputMaybe<Scalars['Boolean']>;
|
||||||
|
/** Used to set values for filtering sender accounts. Party must be provided in this filter or to_account_filter, or both. */
|
||||||
FromAccountFilter?: InputMaybe<AccountFilter>;
|
FromAccountFilter?: InputMaybe<AccountFilter>;
|
||||||
|
/** Used to set values for filtering receiver accounts. Party must be provided in this filter or from_account_filter, or both. */
|
||||||
ToAccountFilter?: InputMaybe<AccountFilter>;
|
ToAccountFilter?: InputMaybe<AccountFilter>;
|
||||||
|
/** List of transfer types that is used for filtering sender and receiver accounts. */
|
||||||
TransferTypes?: InputMaybe<Array<InputMaybe<TransferType>>>;
|
TransferTypes?: InputMaybe<Array<InputMaybe<TransferType>>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1728,31 +1778,31 @@ export type LiquidityProvision = {
|
|||||||
__typename?: 'LiquidityProvision';
|
__typename?: 'LiquidityProvision';
|
||||||
/** A set of liquidity buy orders to meet the liquidity provision obligation. */
|
/** A set of liquidity buy orders to meet the liquidity provision obligation. */
|
||||||
buys: Array<LiquidityOrderReference>;
|
buys: Array<LiquidityOrderReference>;
|
||||||
/** Specified as a unit-less number that represents the amount of settlement asset of the market. */
|
/** Specified as a unitless number that represents the amount of the market's settlement asset for the commitment. */
|
||||||
commitmentAmount: Scalars['String'];
|
commitmentAmount: Scalars['String'];
|
||||||
/** RFC3339Nano time when the liquidity provision was initially created */
|
/** RFC3339Nano time when the liquidity provision was initially created */
|
||||||
createdAt: Scalars['Timestamp'];
|
createdAt: Scalars['Timestamp'];
|
||||||
/** Nominated liquidity fee factor, which is an input to the calculation of liquidity fees on the market, as per setting fees and rewarding liquidity providers. */
|
/** Provider's nominated liquidity fee factor, which is an input to the calculation of liquidity fees on the market, as per setting fees and rewarding liquidity providers. */
|
||||||
fee: Scalars['String'];
|
fee: Scalars['String'];
|
||||||
/** Unique identifier for the order (set by the system after consensus) */
|
/** Unique identifier for the provision (set by the system after consensus) */
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
/** Market for the order */
|
/** Market ID for the liquidity provision */
|
||||||
market: Market;
|
market: Market;
|
||||||
/** The party making this commitment */
|
/** The party making this commitment */
|
||||||
party: Party;
|
party: Party;
|
||||||
/** A reference for the orders created out of this liquidity provision */
|
/** A reference for the orders created to support this liquidity provision */
|
||||||
reference?: Maybe<Scalars['String']>;
|
reference?: Maybe<Scalars['String']>;
|
||||||
/** A set of liquidity sell orders to meet the liquidity provision obligation. */
|
/** A set of liquidity sell orders to meet the liquidity provision obligation. */
|
||||||
sells: Array<LiquidityOrderReference>;
|
sells: Array<LiquidityOrderReference>;
|
||||||
/** The current status of this liquidity provision */
|
/** The current status of this liquidity provision */
|
||||||
status: LiquidityProvisionStatus;
|
status: LiquidityProvisionStatus;
|
||||||
/** RFC3339Nano time of when the liquidity provision was updated */
|
/** RFC3339Nano time when the liquidity provision was updated */
|
||||||
updatedAt?: Maybe<Scalars['Timestamp']>;
|
updatedAt?: Maybe<Scalars['Timestamp']>;
|
||||||
/** The version of this liquidity provision */
|
/** The version of this liquidity provision */
|
||||||
version: Scalars['String'];
|
version: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Status of a liquidity provision order */
|
/** Status of a liquidity provision */
|
||||||
export enum LiquidityProvisionStatus {
|
export enum LiquidityProvisionStatus {
|
||||||
/** An active liquidity provision */
|
/** An active liquidity provision */
|
||||||
STATUS_ACTIVE = 'STATUS_ACTIVE',
|
STATUS_ACTIVE = 'STATUS_ACTIVE',
|
||||||
@ -1801,6 +1851,20 @@ export type LiquidityProvisionUpdate = {
|
|||||||
version: Scalars['String'];
|
version: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LiquidityProvisionWithPending = {
|
||||||
|
__typename?: 'LiquidityProvisionWithPending';
|
||||||
|
current: LiquidityProvision;
|
||||||
|
/** Liquidity provision that has been updated by the liquidity provider, and has been accepted by the network, but will not be active until the next epoch. */
|
||||||
|
pending?: Maybe<LiquidityProvision>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Edge type containing the liquidity provision and cursor information returned by a LiquidityProvisionsWithPendingConnection */
|
||||||
|
export type LiquidityProvisionWithPendingEdge = {
|
||||||
|
__typename?: 'LiquidityProvisionWithPendingEdge';
|
||||||
|
cursor: Scalars['String'];
|
||||||
|
node: LiquidityProvisionWithPending;
|
||||||
|
};
|
||||||
|
|
||||||
/** Connection type for retrieving cursor-based paginated liquidity provision information */
|
/** Connection type for retrieving cursor-based paginated liquidity provision information */
|
||||||
export type LiquidityProvisionsConnection = {
|
export type LiquidityProvisionsConnection = {
|
||||||
__typename?: 'LiquidityProvisionsConnection';
|
__typename?: 'LiquidityProvisionsConnection';
|
||||||
@ -1815,6 +1879,13 @@ export type LiquidityProvisionsEdge = {
|
|||||||
node: LiquidityProvision;
|
node: LiquidityProvision;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Connection type for retrieving cursor-based paginated liquidity provision information */
|
||||||
|
export type LiquidityProvisionsWithPendingConnection = {
|
||||||
|
__typename?: 'LiquidityProvisionsWithPendingConnection';
|
||||||
|
edges?: Maybe<Array<Maybe<LiquidityProvisionWithPendingEdge>>>;
|
||||||
|
pageInfo: PageInfo;
|
||||||
|
};
|
||||||
|
|
||||||
export type LiquiditySLAParameters = {
|
export type LiquiditySLAParameters = {
|
||||||
__typename?: 'LiquiditySLAParameters';
|
__typename?: 'LiquiditySLAParameters';
|
||||||
/** Specifies the minimum fraction of time LPs must spend 'on the book' providing their committed liquidity */
|
/** Specifies the minimum fraction of time LPs must spend 'on the book' providing their committed liquidity */
|
||||||
@ -1861,6 +1932,15 @@ export type LossSocialization = {
|
|||||||
partyId: Scalars['ID'];
|
partyId: Scalars['ID'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Maker fees generated by the trade aggressor */
|
||||||
|
export type MakerFeesGenerated = {
|
||||||
|
__typename?: 'MakerFeesGenerated';
|
||||||
|
/** Amount of maker fees paid by the taker to the maker */
|
||||||
|
makerFeesPaid: Array<PartyAmount>;
|
||||||
|
/** Party that paid the fees */
|
||||||
|
taker: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
export type MarginCalculator = {
|
export type MarginCalculator = {
|
||||||
__typename?: 'MarginCalculator';
|
__typename?: 'MarginCalculator';
|
||||||
/** The scaling factors that will be used for margin calculation */
|
/** The scaling factors that will be used for margin calculation */
|
||||||
@ -1979,6 +2059,11 @@ export type Market = {
|
|||||||
/** Liquidity monitoring parameters for the market */
|
/** Liquidity monitoring parameters for the market */
|
||||||
liquidityMonitoringParameters: LiquidityMonitoringParameters;
|
liquidityMonitoringParameters: LiquidityMonitoringParameters;
|
||||||
/** The list of the liquidity provision commitments for this market */
|
/** The list of the liquidity provision commitments for this market */
|
||||||
|
liquidityProvisions?: Maybe<LiquidityProvisionsWithPendingConnection>;
|
||||||
|
/**
|
||||||
|
* The list of the liquidity provision commitments for this market
|
||||||
|
* @deprecated Use liquidityProvisions instead
|
||||||
|
*/
|
||||||
liquidityProvisionsConnection?: Maybe<LiquidityProvisionsConnection>;
|
liquidityProvisionsConnection?: Maybe<LiquidityProvisionsConnection>;
|
||||||
/** Optional: Liquidity SLA parameters for the market */
|
/** Optional: Liquidity SLA parameters for the market */
|
||||||
liquiditySLAParameters?: Maybe<LiquiditySLAParameters>;
|
liquiditySLAParameters?: Maybe<LiquiditySLAParameters>;
|
||||||
@ -2046,6 +2131,14 @@ export type MarketdepthArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Represents a product & associated parameters that can be traded on Vega, has an associated OrderBook and Trade history */
|
||||||
|
export type MarketliquidityProvisionsArgs = {
|
||||||
|
live?: InputMaybe<Scalars['Boolean']>;
|
||||||
|
pagination?: InputMaybe<Pagination>;
|
||||||
|
partyId?: InputMaybe<Scalars['ID']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Represents a product & associated parameters that can be traded on Vega, has an associated OrderBook and Trade history */
|
/** Represents a product & associated parameters that can be traded on Vega, has an associated OrderBook and Trade history */
|
||||||
export type MarketliquidityProvisionsConnectionArgs = {
|
export type MarketliquidityProvisionsConnectionArgs = {
|
||||||
live?: InputMaybe<Scalars['Boolean']>;
|
live?: InputMaybe<Scalars['Boolean']>;
|
||||||
@ -3219,6 +3312,39 @@ export type Pagination = {
|
|||||||
last?: InputMaybe<Scalars['Int']>;
|
last?: InputMaybe<Scalars['Int']>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Liquidity fees that have been paid to a party in a specific market/asset up to the given epoch. */
|
||||||
|
export type PaidLiquidityFees = {
|
||||||
|
__typename?: 'PaidLiquidityFees';
|
||||||
|
/** The settlement asset of the market. */
|
||||||
|
assetId: Scalars['String'];
|
||||||
|
/** The epoch for which these stats were valid. */
|
||||||
|
epoch: Scalars['Int'];
|
||||||
|
/** Fees paid per party */
|
||||||
|
feesPaidPerParty: Array<PartyAmount>;
|
||||||
|
/** The market the fees were paid in */
|
||||||
|
marketId: Scalars['String'];
|
||||||
|
/** Total fees paid across all parties */
|
||||||
|
totalFeesPaid: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Connection type for retrieving cursor-based paginated paid liquidity fees statistics */
|
||||||
|
export type PaidLiquidityFeesConnection = {
|
||||||
|
__typename?: 'PaidLiquidityFeesConnection';
|
||||||
|
/** The volume discount statistics in this connection */
|
||||||
|
edges: Array<Maybe<PaidLiquidityFeesEdge>>;
|
||||||
|
/** The pagination information */
|
||||||
|
pageInfo: PageInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Edge type containing the volume discount statistics and cursor information returned by a PaidLiquidityFeesConnection */
|
||||||
|
export type PaidLiquidityFeesEdge = {
|
||||||
|
__typename?: 'PaidLiquidityFeesEdge';
|
||||||
|
/** The cursor for this volume discount statistics */
|
||||||
|
cursor: Scalars['String'];
|
||||||
|
/** The volume discount statistics */
|
||||||
|
node: PaidLiquidityFees;
|
||||||
|
};
|
||||||
|
|
||||||
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
||||||
export type Party = {
|
export type Party = {
|
||||||
__typename?: 'Party';
|
__typename?: 'Party';
|
||||||
@ -3231,7 +3357,12 @@ export type Party = {
|
|||||||
depositsConnection?: Maybe<DepositsConnection>;
|
depositsConnection?: Maybe<DepositsConnection>;
|
||||||
/** Party identifier */
|
/** Party identifier */
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
/** The list of the liquidity provision commitment for this party */
|
/** The list of the liquidity provision commitments for this party */
|
||||||
|
liquidityProvisions?: Maybe<LiquidityProvisionsWithPendingConnection>;
|
||||||
|
/**
|
||||||
|
* The list of the liquidity provision commitment for this party
|
||||||
|
* @deprecated Use liquidityProvisions instead
|
||||||
|
*/
|
||||||
liquidityProvisionsConnection?: Maybe<LiquidityProvisionsConnection>;
|
liquidityProvisionsConnection?: Maybe<LiquidityProvisionsConnection>;
|
||||||
/** Margin levels for a market */
|
/** Margin levels for a market */
|
||||||
marginsConnection?: Maybe<MarginConnection>;
|
marginsConnection?: Maybe<MarginConnection>;
|
||||||
@ -3254,6 +3385,8 @@ export type Party = {
|
|||||||
tradesConnection?: Maybe<TradeConnection>;
|
tradesConnection?: Maybe<TradeConnection>;
|
||||||
/** All transfers for a public key */
|
/** All transfers for a public key */
|
||||||
transfersConnection?: Maybe<TransferConnection>;
|
transfersConnection?: Maybe<TransferConnection>;
|
||||||
|
/** The current reward vesting summary of the party for the last epoch */
|
||||||
|
vestingBalancesSummary: PartyVestingBalancesSummary;
|
||||||
/** All votes on proposals in the Vega network by the given party */
|
/** All votes on proposals in the Vega network by the given party */
|
||||||
votesConnection?: Maybe<ProposalVoteConnection>;
|
votesConnection?: Maybe<ProposalVoteConnection>;
|
||||||
/** The list of all withdrawals initiated by the party */
|
/** The list of all withdrawals initiated by the party */
|
||||||
@ -3290,6 +3423,15 @@ export type PartydepositsConnectionArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
||||||
|
export type PartyliquidityProvisionsArgs = {
|
||||||
|
live?: InputMaybe<Scalars['Boolean']>;
|
||||||
|
marketId?: InputMaybe<Scalars['ID']>;
|
||||||
|
pagination?: InputMaybe<Pagination>;
|
||||||
|
reference?: InputMaybe<Scalars['String']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
||||||
export type PartyliquidityProvisionsConnectionArgs = {
|
export type PartyliquidityProvisionsConnectionArgs = {
|
||||||
live?: InputMaybe<Scalars['Boolean']>;
|
live?: InputMaybe<Scalars['Boolean']>;
|
||||||
@ -3364,6 +3506,12 @@ export type PartytransfersConnectionArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
||||||
|
export type PartyvestingBalancesSummaryArgs = {
|
||||||
|
assetId?: InputMaybe<Scalars['ID']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
/** Represents a party on Vega, could be an ethereum wallet address in the future */
|
||||||
export type PartyvotesConnectionArgs = {
|
export type PartyvotesConnectionArgs = {
|
||||||
pagination?: InputMaybe<Pagination>;
|
pagination?: InputMaybe<Pagination>;
|
||||||
@ -3424,6 +3572,17 @@ export type PartyEdge = {
|
|||||||
node: Party;
|
node: Party;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** A party reward locked balance. */
|
||||||
|
export type PartyLockedBalance = {
|
||||||
|
__typename?: 'PartyLockedBalance';
|
||||||
|
/** The asset locked */
|
||||||
|
asset: Asset;
|
||||||
|
/** The amount locked */
|
||||||
|
balance: Scalars['String'];
|
||||||
|
/** Epoch in which the funds will be moved to the vesting balance */
|
||||||
|
untilEpoch: Scalars['Int'];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All staking information related to a Party.
|
* All staking information related to a Party.
|
||||||
* Contains the current recognised balance by the network and
|
* Contains the current recognised balance by the network and
|
||||||
@ -3437,6 +3596,26 @@ export type PartyStake = {
|
|||||||
linkings?: Maybe<Array<StakeLinking>>;
|
linkings?: Maybe<Array<StakeLinking>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** A party's reward vesting balance. */
|
||||||
|
export type PartyVestingBalance = {
|
||||||
|
__typename?: 'PartyVestingBalance';
|
||||||
|
/** The asset being vested */
|
||||||
|
asset: Asset;
|
||||||
|
/** The amount locked */
|
||||||
|
balance: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Summary of a party's reward vesting balances. */
|
||||||
|
export type PartyVestingBalancesSummary = {
|
||||||
|
__typename?: 'PartyVestingBalancesSummary';
|
||||||
|
/** The epoch for which this summary is valid */
|
||||||
|
epoch?: Maybe<Scalars['Int']>;
|
||||||
|
/** The party's vesting balances */
|
||||||
|
lockedBalances?: Maybe<Array<PartyLockedBalance>>;
|
||||||
|
/** The party vesting balances */
|
||||||
|
vestingBalances?: Maybe<Array<PartyVestingBalance>>;
|
||||||
|
};
|
||||||
|
|
||||||
/** Create an order linked to an index rather than a price */
|
/** Create an order linked to an index rather than a price */
|
||||||
export type PeggedOrder = {
|
export type PeggedOrder = {
|
||||||
__typename?: 'PeggedOrder';
|
__typename?: 'PeggedOrder';
|
||||||
@ -4163,6 +4342,10 @@ export type Query = {
|
|||||||
estimatePosition?: Maybe<PositionEstimate>;
|
estimatePosition?: Maybe<PositionEstimate>;
|
||||||
/** Query for historic ethereum key rotations */
|
/** Query for historic ethereum key rotations */
|
||||||
ethereumKeyRotations: EthereumKeyRotationsConnection;
|
ethereumKeyRotations: EthereumKeyRotationsConnection;
|
||||||
|
/** Get fees statistics */
|
||||||
|
feesStats?: Maybe<FeesStats>;
|
||||||
|
/** Get fees statistics for a given party */
|
||||||
|
feesStatsForParty?: Maybe<Array<Maybe<FeesStatsForParty>>>;
|
||||||
/** Funding payment for perpetual markets. */
|
/** Funding payment for perpetual markets. */
|
||||||
fundingPayments: FundingPaymentConnection;
|
fundingPayments: FundingPaymentConnection;
|
||||||
/**
|
/**
|
||||||
@ -4178,7 +4361,14 @@ export type Query = {
|
|||||||
keyRotationsConnection: KeyRotationConnection;
|
keyRotationsConnection: KeyRotationConnection;
|
||||||
/** The last block process by the blockchain */
|
/** The last block process by the blockchain */
|
||||||
lastBlockHeight: Scalars['String'];
|
lastBlockHeight: Scalars['String'];
|
||||||
/** Get ledger entries by asset, market, party, account type, transfer type within the given date range. */
|
/**
|
||||||
|
* Get ledger entries by asset, market, party, account type, transfer type within the given date range.
|
||||||
|
* Note: The date range is restricted to any 5 days.
|
||||||
|
* If no start or end date is provided, only ledger entries from the last 5 days will be returned.
|
||||||
|
* If a start and end date are provided, but the end date is more than 5 days after the start date, only data up to 5 days after the start date will be returned.
|
||||||
|
* If a start date is provided but no end date, the end date will be set to 5 days after the start date.
|
||||||
|
* If no start date is provided, but the end date is, the start date will be set to 5 days before the end date.
|
||||||
|
*/
|
||||||
ledgerEntries: AggregatedLedgerEntriesConnection;
|
ledgerEntries: AggregatedLedgerEntriesConnection;
|
||||||
/** List all active liquidity providers for a specific market */
|
/** List all active liquidity providers for a specific market */
|
||||||
liquidityProviders?: Maybe<LiquidityProviderConnection>;
|
liquidityProviders?: Maybe<LiquidityProviderConnection>;
|
||||||
@ -4216,6 +4406,8 @@ export type Query = {
|
|||||||
orderByReference: Order;
|
orderByReference: Order;
|
||||||
/** Order versions (created via amendments if any) found by orderID */
|
/** Order versions (created via amendments if any) found by orderID */
|
||||||
orderVersionsConnection?: Maybe<OrderConnection>;
|
orderVersionsConnection?: Maybe<OrderConnection>;
|
||||||
|
/** List paid liquidity fees statistics */
|
||||||
|
paidLiquidityFees?: Maybe<PaidLiquidityFeesConnection>;
|
||||||
/** One or more entities that are trading on the Vega network */
|
/** One or more entities that are trading on the Vega network */
|
||||||
partiesConnection?: Maybe<PartyConnection>;
|
partiesConnection?: Maybe<PartyConnection>;
|
||||||
/** An entity that is trading on the Vega network */
|
/** An entity that is trading on the Vega network */
|
||||||
@ -4230,8 +4422,6 @@ export type Query = {
|
|||||||
protocolUpgradeProposals?: Maybe<ProtocolUpgradeProposalConnection>;
|
protocolUpgradeProposals?: Maybe<ProtocolUpgradeProposalConnection>;
|
||||||
/** Flag indicating whether the data-node is ready to begin the protocol upgrade */
|
/** Flag indicating whether the data-node is ready to begin the protocol upgrade */
|
||||||
protocolUpgradeStatus?: Maybe<ProtocolUpgradeStatus>;
|
protocolUpgradeStatus?: Maybe<ProtocolUpgradeStatus>;
|
||||||
/** Get referrer fee and discount stats */
|
|
||||||
referralFeeStats?: Maybe<ReferralSetFeeStats>;
|
|
||||||
referralSetReferees: ReferralSetRefereeConnection;
|
referralSetReferees: ReferralSetRefereeConnection;
|
||||||
/** Get referral set statistics */
|
/** Get referral set statistics */
|
||||||
referralSetStats: ReferralSetStatsConnection;
|
referralSetStats: ReferralSetStatsConnection;
|
||||||
@ -4410,6 +4600,24 @@ export type QueryethereumKeyRotationsArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||||
|
export type QueryfeesStatsArgs = {
|
||||||
|
assetId?: InputMaybe<Scalars['ID']>;
|
||||||
|
epoch?: InputMaybe<Scalars['Int']>;
|
||||||
|
marketId?: InputMaybe<Scalars['ID']>;
|
||||||
|
partyId?: InputMaybe<Scalars['ID']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||||
|
export type QueryfeesStatsForPartyArgs = {
|
||||||
|
assetId?: InputMaybe<Scalars['ID']>;
|
||||||
|
fromEpoch?: InputMaybe<Scalars['Int']>;
|
||||||
|
partyId: Scalars['ID'];
|
||||||
|
toEpoch?: InputMaybe<Scalars['Int']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||||
export type QueryfundingPaymentsArgs = {
|
export type QueryfundingPaymentsArgs = {
|
||||||
marketId?: InputMaybe<Scalars['ID']>;
|
marketId?: InputMaybe<Scalars['ID']>;
|
||||||
@ -4557,6 +4765,15 @@ export type QueryorderVersionsConnectionArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||||
|
export type QuerypaidLiquidityFeesArgs = {
|
||||||
|
assetId?: InputMaybe<Scalars['ID']>;
|
||||||
|
epoch?: InputMaybe<Scalars['Int']>;
|
||||||
|
marketId?: InputMaybe<Scalars['ID']>;
|
||||||
|
partyIDs?: InputMaybe<Array<Scalars['String']>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||||
export type QuerypartiesConnectionArgs = {
|
export type QuerypartiesConnectionArgs = {
|
||||||
id?: InputMaybe<Scalars['ID']>;
|
id?: InputMaybe<Scalars['ID']>;
|
||||||
@ -4600,18 +4817,9 @@ export type QueryprotocolUpgradeProposalsArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
|
||||||
export type QueryreferralFeeStatsArgs = {
|
|
||||||
assetId?: InputMaybe<Scalars['ID']>;
|
|
||||||
epoch?: InputMaybe<Scalars['Int']>;
|
|
||||||
marketId?: InputMaybe<Scalars['ID']>;
|
|
||||||
referee?: InputMaybe<Scalars['ID']>;
|
|
||||||
referrer?: InputMaybe<Scalars['ID']>;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Queries allow a caller to read data and filter data via GraphQL. */
|
/** Queries allow a caller to read data and filter data via GraphQL. */
|
||||||
export type QueryreferralSetRefereesArgs = {
|
export type QueryreferralSetRefereesArgs = {
|
||||||
|
aggregationDays?: InputMaybe<Scalars['Int']>;
|
||||||
id?: InputMaybe<Scalars['ID']>;
|
id?: InputMaybe<Scalars['ID']>;
|
||||||
pagination?: InputMaybe<Pagination>;
|
pagination?: InputMaybe<Pagination>;
|
||||||
referee?: InputMaybe<Scalars['ID']>;
|
referee?: InputMaybe<Scalars['ID']>;
|
||||||
@ -4773,8 +4981,8 @@ export type ReferralProgram = {
|
|||||||
__typename?: 'ReferralProgram';
|
__typename?: 'ReferralProgram';
|
||||||
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
||||||
benefitTiers: Array<BenefitTier>;
|
benefitTiers: Array<BenefitTier>;
|
||||||
/** Timestamp as RFC3339, after which when the current epoch ends, the programs will end and benefits will be disabled. */
|
/** Timestamp as Unix time in nanoseconds, after which when the current epoch ends, the program will end and benefits will be disabled. */
|
||||||
endOfProgramTimestamp: Scalars['String'];
|
endOfProgramTimestamp: Scalars['Timestamp'];
|
||||||
/** Unique ID generated from the proposal that created this program. */
|
/** Unique ID generated from the proposal that created this program. */
|
||||||
id: Scalars['ID'];
|
id: Scalars['ID'];
|
||||||
/**
|
/**
|
||||||
@ -4820,25 +5028,6 @@ export type ReferralSetEdge = {
|
|||||||
node: ReferralSet;
|
node: ReferralSet;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Referral rewards and discounts that have been applied on a specific market/asset up to the given epoch. */
|
|
||||||
export type ReferralSetFeeStats = {
|
|
||||||
__typename?: 'ReferralSetFeeStats';
|
|
||||||
/** The settlement asset of the market. */
|
|
||||||
assetId: Scalars['String'];
|
|
||||||
/** The epoch for which these stats were valid. */
|
|
||||||
epoch: Scalars['Int'];
|
|
||||||
/** The market the fees were paid in */
|
|
||||||
marketId: Scalars['String'];
|
|
||||||
/** The total referral discounts applied to all referee taker fees */
|
|
||||||
refereesDiscountApplied: Array<PartyAmount>;
|
|
||||||
/** The total referral rewards generated by all referee taker fees. */
|
|
||||||
referrerRewardsGenerated: Array<ReferrerRewardsGenerated>;
|
|
||||||
/** The total referral rewards paid to the referrer of the referral set. */
|
|
||||||
totalRewardsPaid: Array<PartyAmount>;
|
|
||||||
/** The total volume discounts applied to all referee taker fees */
|
|
||||||
volumeDiscountApplied: Array<PartyAmount>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Data relating to referees that have joined a referral set */
|
/** Data relating to referees that have joined a referral set */
|
||||||
export type ReferralSetReferee = {
|
export type ReferralSetReferee = {
|
||||||
__typename?: 'ReferralSetReferee';
|
__typename?: 'ReferralSetReferee';
|
||||||
@ -4850,6 +5039,10 @@ export type ReferralSetReferee = {
|
|||||||
refereeId: Scalars['ID'];
|
refereeId: Scalars['ID'];
|
||||||
/** Unique ID of the referral set the referee joined. */
|
/** Unique ID of the referral set the referee joined. */
|
||||||
referralSetId: Scalars['ID'];
|
referralSetId: Scalars['ID'];
|
||||||
|
/** Total rewards generated from the referee over the aggregation period, default is 30 days. */
|
||||||
|
totalRefereeGeneratedRewards: Scalars['String'];
|
||||||
|
/** Total notional volume of the referee's aggressive trades over the aggregation period, default is 30 days. */
|
||||||
|
totalRefereeNotionalTakerVolume: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Connection type for retrieving cursor-based paginated information about the referral set referees */
|
/** Connection type for retrieving cursor-based paginated information about the referral set referees */
|
||||||
@ -4926,6 +5119,8 @@ export type Reward = {
|
|||||||
asset: Asset;
|
asset: Asset;
|
||||||
/** Epoch for which this reward was distributed */
|
/** Epoch for which this reward was distributed */
|
||||||
epoch: Epoch;
|
epoch: Epoch;
|
||||||
|
/** The epoch when the reward is released */
|
||||||
|
lockedUntilEpoch: Epoch;
|
||||||
/** The market ID for which this reward is paid if any */
|
/** The market ID for which this reward is paid if any */
|
||||||
marketId: Scalars['ID'];
|
marketId: Scalars['ID'];
|
||||||
/** Party receiving the reward */
|
/** Party receiving the reward */
|
||||||
@ -6151,8 +6346,8 @@ export type UpdateReferralProgram = {
|
|||||||
__typename?: 'UpdateReferralProgram';
|
__typename?: 'UpdateReferralProgram';
|
||||||
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
||||||
benefitTiers: Array<BenefitTier>;
|
benefitTiers: Array<BenefitTier>;
|
||||||
/** Timestamp as RFC3339, after which when the current epoch ends, the programs will end and benefits will be disabled. */
|
/** Timestamp as Unix time in nanoseconds, after which when the current epoch ends, the program will end and benefits will be disabled. */
|
||||||
endOfProgramTimestamp: Scalars['String'];
|
endOfProgramTimestamp: Scalars['Timestamp'];
|
||||||
/**
|
/**
|
||||||
* Defined staking tiers in increasing order. First element will give Tier 1,
|
* Defined staking tiers in increasing order. First element will give Tier 1,
|
||||||
* second element will give Tier 2, and so on. Determines the level of
|
* second element will give Tier 2, and so on. Determines the level of
|
||||||
@ -6190,7 +6385,7 @@ export type UpdateVolumeDiscountProgram = {
|
|||||||
__typename?: 'UpdateVolumeDiscountProgram';
|
__typename?: 'UpdateVolumeDiscountProgram';
|
||||||
/** The benefit tiers for the program */
|
/** The benefit tiers for the program */
|
||||||
benefitTiers: Array<VolumeBenefitTier>;
|
benefitTiers: Array<VolumeBenefitTier>;
|
||||||
/** The end time of the program */
|
/** Timestamp as Unix time in nanoseconds, after which program ends. */
|
||||||
endOfProgramTimestamp: Scalars['Timestamp'];
|
endOfProgramTimestamp: Scalars['Timestamp'];
|
||||||
/** The window length to consider for the volume discount program */
|
/** The window length to consider for the volume discount program */
|
||||||
windowLength: Scalars['Int'];
|
windowLength: Scalars['Int'];
|
||||||
@ -6219,7 +6414,7 @@ export type VolumeDiscountProgram = {
|
|||||||
__typename?: 'VolumeDiscountProgram';
|
__typename?: 'VolumeDiscountProgram';
|
||||||
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
/** Defined tiers in increasing order. First element will give Tier 1, second element will give Tier 2, etc. */
|
||||||
benefitTiers: Array<VolumeBenefitTier>;
|
benefitTiers: Array<VolumeBenefitTier>;
|
||||||
/** Timestamp as Unix time in nanoseconds, after which when the current epoch ends, the programs will end and benefits will be disabled. */
|
/** Timestamp as Unix time in nanoseconds, after which when the current epoch ends, the program will end and benefits will be disabled. */
|
||||||
endOfProgramTimestamp: Scalars['Timestamp'];
|
endOfProgramTimestamp: Scalars['Timestamp'];
|
||||||
/** Timestamp as RFC3339Nano when the program ended. If present, the current program has ended and no program is currently running. */
|
/** Timestamp as RFC3339Nano when the program ended. If present, the current program has ended and no program is currently running. */
|
||||||
endedAt?: Maybe<Scalars['Timestamp']>;
|
endedAt?: Maybe<Scalars['Timestamp']>;
|
||||||
|
Loading…
Reference in New Issue
Block a user