From 2b4736c585f541fcd7dce2c817a32d94191d966b Mon Sep 17 00:00:00 2001 From: asiaznik Date: Wed, 18 Oct 2023 16:20:16 +0200 Subject: [PATCH] feat: preview, ux changes --- .../proposal/__generated__/Proposal.ts | 4 +- .../proposals/__generated__/Proposals.ts | 4 +- .../referrals/apply-code-form.tsx | 103 ++++++++++++------ .../referrals/create-code-form.tsx | 10 +- .../referrals/hooks/Referee.graphql | 12 -- .../referrals/hooks/Referees.graphql | 6 +- .../referrals/hooks/ReferralFeesStats.graphql | 32 ++++++ .../referrals/hooks/ReferralSetStats.graphql | 2 + .../referrals/hooks/ReferralSets.graphql | 12 ++ .../referrals/hooks/Referrer.graphql | 12 -- .../referrals/hooks/__generated__/Referee.ts | 55 ---------- .../referrals/hooks/__generated__/Referees.ts | 10 +- .../hooks/__generated__/ReferralFeesStats.ts | 76 +++++++++++++ .../hooks/__generated__/ReferralSetStats.ts | 4 +- .../hooks/__generated__/ReferralSets.ts | 59 ++++++++++ .../referrals/hooks/__generated__/Referrer.ts | 55 ---------- .../referrals/hooks/use-referral-program.ts | 6 +- .../referrals/hooks/use-referral.ts | 98 +++++++++++------ .../referrals/referral-statistics.tsx | 89 ++++++++------- .../client-pages/referrals/referrals.tsx | 30 ++++- apps/trading/client-pages/referrals/tiers.tsx | 18 ++- libs/types/src/__generated__/types.ts | 74 +++++++++++-- 22 files changed, 497 insertions(+), 274 deletions(-) delete mode 100644 apps/trading/client-pages/referrals/hooks/Referee.graphql create mode 100644 apps/trading/client-pages/referrals/hooks/ReferralFeesStats.graphql create mode 100644 apps/trading/client-pages/referrals/hooks/ReferralSets.graphql delete mode 100644 apps/trading/client-pages/referrals/hooks/Referrer.graphql delete mode 100644 apps/trading/client-pages/referrals/hooks/__generated__/Referee.ts create mode 100644 apps/trading/client-pages/referrals/hooks/__generated__/ReferralFeesStats.ts create mode 100644 apps/trading/client-pages/referrals/hooks/__generated__/ReferralSets.ts delete mode 100644 apps/trading/client-pages/referrals/hooks/__generated__/Referrer.ts diff --git a/apps/governance/src/routes/proposals/proposal/__generated__/Proposal.ts b/apps/governance/src/routes/proposals/proposal/__generated__/Proposal.ts index 6468c4df0..974d2a19c 100644 --- a/apps/governance/src/routes/proposals/proposal/__generated__/Proposal.ts +++ b/apps/governance/src/routes/proposals/proposal/__generated__/Proposal.ts @@ -7,7 +7,7 @@ export type NewMarketProductFieldFragment = { __typename?: 'Proposal', terms: { export type UpdateMarketStateFragment = { __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 UpdateReferralProgramFragment = { __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 UpdateReferralProgramFragment = { __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 UpdateVolumeDiscountProgramFragment = { __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 }> } } }; @@ -20,7 +20,7 @@ export type ProposalQueryVariables = Types.Exact<{ }>; -export type ProposalQuery = { __typename?: 'Query', proposal?: { __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, lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array | null, positionDecimalPlaces: number, linearSlippageFactor: string, quadraticSlippageFactor: string, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null, product?: { __typename: 'FutureProduct' } | { __typename: 'PerpetualProduct' } | { __typename: 'SpotProduct' } | null }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } } } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset', quantum: string, assetId: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | { __typename?: 'UpdatePerpetualProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecPerpetualBinding', settlementDataProperty: string, settlementScheduleProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename?: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | null } | { __typename?: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } } | { __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 }; +export type ProposalQuery = { __typename?: 'Query', proposal?: { __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, lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'NewFreeform' } | { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array | null, positionDecimalPlaces: number, linearSlippageFactor: string, quadraticSlippageFactor: string, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null, product?: { __typename: 'FutureProduct' } | { __typename: 'PerpetualProduct' } | { __typename: 'SpotProduct' } | null }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } } } | { __typename?: 'NewSpotMarket' } | { __typename?: 'NewTransfer' } | { __typename?: 'UpdateAsset', quantum: string, assetId: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename?: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | { __typename?: 'UpdatePerpetualProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } | { __typename?: 'EthCallSpec' } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecPerpetualBinding', settlementDataProperty: string, settlementScheduleProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename?: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | null } | { __typename?: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } } | { __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 }; export const NewMarketProductFieldFragmentDoc = gql` fragment NewMarketProductField on Proposal { diff --git a/apps/governance/src/routes/proposals/proposals/__generated__/Proposals.ts b/apps/governance/src/routes/proposals/proposals/__generated__/Proposals.ts index 4b25637d9..0a8c107bd 100644 --- a/apps/governance/src/routes/proposals/proposals/__generated__/Proposals.ts +++ b/apps/governance/src/routes/proposals/proposals/__generated__/Proposals.ts @@ -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 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 }> } } }; @@ -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` fragment NewMarketProductFields on Proposal { diff --git a/apps/trading/client-pages/referrals/apply-code-form.tsx b/apps/trading/client-pages/referrals/apply-code-form.tsx index f439805d2..9c52e18ee 100644 --- a/apps/trading/client-pages/referrals/apply-code-form.tsx +++ b/apps/trading/client-pages/referrals/apply-code-form.tsx @@ -1,6 +1,7 @@ import { Input, InputError, + Loader, VegaIcon, VegaIconNames, } from '@vegaprotocol/ui-toolkit'; @@ -16,9 +17,21 @@ import { useReferral } from './hooks/use-referral'; import { Routes } from '../../lib/links'; import { useTransactionEventSubscription } from '@vegaprotocol/web3'; import { clearTimeout } from 'timers'; +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 = () => { const navigate = useNavigate(); const openWalletDialog = useVegaWalletDialogStore( @@ -36,11 +49,17 @@ export const ApplyCodeForm = () => { formState: { errors }, setValue, setError, + watch, } = useForm(); const [params] = useSearchParams(); - const { data: referee } = useReferral(pubKey, 'referee'); - const { data: referrer } = useReferral(pubKey, 'referrer'); + const { data: referee } = useReferral({ pubKey, role: 'referee' }); + const { data: referrer } = useReferral({ pubKey, role: 'referrer' }); + + const codeField = watch('code'); + const { data: previewData, loading: previewLoading } = useReferral({ + code: validateCode(codeField) ? codeField : undefined, + }); useEffect(() => { const code = params.get('code'); @@ -121,14 +140,16 @@ export const ApplyCodeForm = () => { }, RELOAD_DELAY); } return () => { - clearTimeout(to); + if (to) clearTimeout(to); }; }, [navigate, status]); + // go to main page if the current pubkey is already a referrer or referee if (referee || referrer) { return ; } + // show "code applied" message when successfully applied if (status === 'successful') { return (
@@ -179,35 +200,51 @@ export const ApplyCodeForm = () => { }; return ( -
-

Apply a referral code

-

- Enter a referral code to get trading discounts. -

-
- - - - {errors.code && ( - - {errors.code.message?.toString()} - - )} -
+ <> +
+

+ Apply a referral code +

+

+ Enter a referral code to get trading discounts. +

+
+ + + + {errors.code && ( + + {errors.code.message?.toString()} + + )} +
+ {previewLoading && !previewData ? ( +
+ +
+ ) : null} + {previewData ? ( +
+

You are joining

+ +
+ ) : null} + ); }; diff --git a/apps/trading/client-pages/referrals/create-code-form.tsx b/apps/trading/client-pages/referrals/create-code-form.tsx index d6fd5689d..c57e1d8f3 100644 --- a/apps/trading/client-pages/referrals/create-code-form.tsx +++ b/apps/trading/client-pages/referrals/create-code-form.tsx @@ -23,6 +23,7 @@ import { ABOUT_REFERRAL_DOCS_LINK, DISCLAIMER_REFERRAL_DOCS_LINK, } from './constants'; +import { useReferral } from './hooks/use-referral'; export const CreateCodeContainer = () => { return ; @@ -33,7 +34,7 @@ export const CreateCodeForm = () => { const openWalletDialog = useVegaWalletDialogStore( (store) => store.openVegaWalletDialog ); - const { pubKey } = useVegaWallet(); + const { pubKey, isReadOnly } = useVegaWallet(); return (
@@ -46,6 +47,7 @@ export const CreateCodeForm = () => {
{ if (pubKey) { setDialogOpen(true); @@ -77,6 +79,7 @@ const CreateCodeDialog = ({ }) => { const createLink = useLinks(DApp.Governance); const { isReadOnly, pubKey, sendTx } = useVegaWallet(); + const { refetch } = useReferral({ pubKey, role: 'referrer' }); const [err, setErr] = useState(null); const [code, setCode] = useState(null); const [status, setStatus] = useState< @@ -137,7 +140,10 @@ const CreateCodeDialog = ({ return { children: 'Close', intent: Intent.Success, - onClick: () => setDialogOpen(false), + onClick: () => { + refetch(); + setDialogOpen(false); + }, }; } }; diff --git a/apps/trading/client-pages/referrals/hooks/Referee.graphql b/apps/trading/client-pages/referrals/hooks/Referee.graphql deleted file mode 100644 index 7f14ea3e4..000000000 --- a/apps/trading/client-pages/referrals/hooks/Referee.graphql +++ /dev/null @@ -1,12 +0,0 @@ -query Referee($partyId: ID!) { - referralSets(referee: $partyId) { - edges { - node { - id - referrer - createdAt - updatedAt - } - } - } -} diff --git a/apps/trading/client-pages/referrals/hooks/Referees.graphql b/apps/trading/client-pages/referrals/hooks/Referees.graphql index e92c37f1b..9050131bb 100644 --- a/apps/trading/client-pages/referrals/hooks/Referees.graphql +++ b/apps/trading/client-pages/referrals/hooks/Referees.graphql @@ -1,11 +1,13 @@ -query Referees($code: ID!) { - referralSetReferees(id: $code) { +query Referees($code: ID!, $aggregationDays: Int) { + referralSetReferees(id: $code, aggregationDays: $aggregationDays) { edges { node { referralSetId refereeId joinedAt atEpoch + totalRefereeNotionalTakerVolume + totalRefereeGeneratedRewards } } } diff --git a/apps/trading/client-pages/referrals/hooks/ReferralFeesStats.graphql b/apps/trading/client-pages/referrals/hooks/ReferralFeesStats.graphql new file mode 100644 index 000000000..84aa0aa0f --- /dev/null +++ b/apps/trading/client-pages/referrals/hooks/ReferralFeesStats.graphql @@ -0,0 +1,32 @@ +query ReferralFeesStats( + $marketId: ID + $assetId: ID + $partyId: ID + $epoch: Int +) { + feesStats( + marketId: $marketId + assetId: $assetId + partyId: $partyId + epoch: $epoch + ) { + marketId + assetId + epoch + totalRewardsPaid { + partyId + amount + } + referrerRewardsGenerated { + referrerId + generatedReward { + partyId + amount + } + } + refereesDiscountApplied { + partyId + amount + } + } +} diff --git a/apps/trading/client-pages/referrals/hooks/ReferralSetStats.graphql b/apps/trading/client-pages/referrals/hooks/ReferralSetStats.graphql index cf746ab6e..35795c913 100644 --- a/apps/trading/client-pages/referrals/hooks/ReferralSetStats.graphql +++ b/apps/trading/client-pages/referrals/hooks/ReferralSetStats.graphql @@ -8,6 +8,8 @@ query ReferralSetStats($code: ID!, $epoch: Int) { rewardFactor epochNotionalTakerVolume referralSetRunningNotionalTakerVolume + rewardsMultiplier + rewardsFactorMultiplier } } } diff --git a/apps/trading/client-pages/referrals/hooks/ReferralSets.graphql b/apps/trading/client-pages/referrals/hooks/ReferralSets.graphql new file mode 100644 index 000000000..368dca9d5 --- /dev/null +++ b/apps/trading/client-pages/referrals/hooks/ReferralSets.graphql @@ -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 + } + } + } +} diff --git a/apps/trading/client-pages/referrals/hooks/Referrer.graphql b/apps/trading/client-pages/referrals/hooks/Referrer.graphql deleted file mode 100644 index 00a02bd29..000000000 --- a/apps/trading/client-pages/referrals/hooks/Referrer.graphql +++ /dev/null @@ -1,12 +0,0 @@ -query Referrer($partyId: ID!) { - referralSets(referrer: $partyId) { - edges { - node { - id - referrer - createdAt - updatedAt - } - } - } -} diff --git a/apps/trading/client-pages/referrals/hooks/__generated__/Referee.ts b/apps/trading/client-pages/referrals/hooks/__generated__/Referee.ts deleted file mode 100644 index 0f158b091..000000000 --- a/apps/trading/client-pages/referrals/hooks/__generated__/Referee.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as Types from '@vegaprotocol/types'; - -import { gql } from '@apollo/client'; -import * as Apollo from '@apollo/client'; -const defaultOptions = {} as const; -export type RefereeQueryVariables = Types.Exact<{ - partyId: Types.Scalars['ID']; -}>; - - -export type RefereeQuery = { __typename?: 'Query', referralSets: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', id: string, referrer: string, createdAt: any, updatedAt: any } } | null> } }; - - -export const RefereeDocument = gql` - query Referee($partyId: ID!) { - referralSets(referee: $partyId) { - edges { - node { - id - referrer - createdAt - updatedAt - } - } - } -} - `; - -/** - * __useRefereeQuery__ - * - * To run a query within a React component, call `useRefereeQuery` and pass it any options that fit your needs. - * When your component renders, `useRefereeQuery` 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 } = useRefereeQuery({ - * variables: { - * partyId: // value for 'partyId' - * }, - * }); - */ -export function useRefereeQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(RefereeDocument, options); - } -export function useRefereeLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(RefereeDocument, options); - } -export type RefereeQueryHookResult = ReturnType; -export type RefereeLazyQueryHookResult = ReturnType; -export type RefereeQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/trading/client-pages/referrals/hooks/__generated__/Referees.ts b/apps/trading/client-pages/referrals/hooks/__generated__/Referees.ts index bb5632217..5eafc568c 100644 --- a/apps/trading/client-pages/referrals/hooks/__generated__/Referees.ts +++ b/apps/trading/client-pages/referrals/hooks/__generated__/Referees.ts @@ -5,21 +5,24 @@ import * as Apollo from '@apollo/client'; const defaultOptions = {} as const; export type RefereesQueryVariables = Types.Exact<{ code: Types.Scalars['ID']; + aggregationDays?: Types.InputMaybe; }>; -export type RefereesQuery = { __typename?: 'Query', referralSetReferees: { __typename?: 'ReferralSetRefereeConnection', edges: Array<{ __typename?: 'ReferralSetRefereeEdge', node: { __typename?: 'ReferralSetReferee', referralSetId: string, refereeId: string, joinedAt: any, atEpoch: number } } | null> } }; +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!) { - referralSetReferees(id: $code) { + query Referees($code: ID!, $aggregationDays: Int) { + referralSetReferees(id: $code, aggregationDays: $aggregationDays) { edges { node { referralSetId refereeId joinedAt atEpoch + totalRefereeNotionalTakerVolume + totalRefereeGeneratedRewards } } } @@ -39,6 +42,7 @@ export const RefereesDocument = gql` * const { data, loading, error } = useRefereesQuery({ * variables: { * code: // value for 'code' + * aggregationDays: // value for 'aggregationDays' * }, * }); */ diff --git a/apps/trading/client-pages/referrals/hooks/__generated__/ReferralFeesStats.ts b/apps/trading/client-pages/referrals/hooks/__generated__/ReferralFeesStats.ts new file mode 100644 index 000000000..69822e654 --- /dev/null +++ b/apps/trading/client-pages/referrals/hooks/__generated__/ReferralFeesStats.ts @@ -0,0 +1,76 @@ +import * as Types from '@vegaprotocol/types'; + +import { gql } from '@apollo/client'; +import * as Apollo from '@apollo/client'; +const defaultOptions = {} as const; +export type ReferralFeesStatsQueryVariables = Types.Exact<{ + marketId?: Types.InputMaybe; + assetId?: Types.InputMaybe; + partyId?: Types.InputMaybe; + epoch?: Types.InputMaybe; +}>; + + +export type ReferralFeesStatsQuery = { __typename?: 'Query', feesStats?: { __typename?: 'FeesStats', marketId: string, assetId: string, epoch: number, totalRewardsPaid: Array<{ __typename?: 'PartyAmount', partyId: string, amount: string }>, referrerRewardsGenerated: Array<{ __typename?: 'ReferrerRewardsGenerated', referrerId: string, generatedReward: Array<{ __typename?: 'PartyAmount', partyId: string, amount: string }> }>, refereesDiscountApplied: Array<{ __typename?: 'PartyAmount', partyId: string, amount: string }> } | null }; + + +export const ReferralFeesStatsDocument = gql` + query ReferralFeesStats($marketId: ID, $assetId: ID, $partyId: ID, $epoch: Int) { + feesStats( + marketId: $marketId + assetId: $assetId + partyId: $partyId + epoch: $epoch + ) { + marketId + assetId + epoch + totalRewardsPaid { + partyId + amount + } + referrerRewardsGenerated { + referrerId + generatedReward { + partyId + amount + } + } + refereesDiscountApplied { + partyId + amount + } + } +} + `; + +/** + * __useReferralFeesStatsQuery__ + * + * To run a query within a React component, call `useReferralFeesStatsQuery` and pass it any options that fit your needs. + * When your component renders, `useReferralFeesStatsQuery` 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 } = useReferralFeesStatsQuery({ + * variables: { + * marketId: // value for 'marketId' + * assetId: // value for 'assetId' + * partyId: // value for 'partyId' + * epoch: // value for 'epoch' + * }, + * }); + */ +export function useReferralFeesStatsQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ReferralFeesStatsDocument, options); + } +export function useReferralFeesStatsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ReferralFeesStatsDocument, options); + } +export type ReferralFeesStatsQueryHookResult = ReturnType; +export type ReferralFeesStatsLazyQueryHookResult = ReturnType; +export type ReferralFeesStatsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/trading/client-pages/referrals/hooks/__generated__/ReferralSetStats.ts b/apps/trading/client-pages/referrals/hooks/__generated__/ReferralSetStats.ts index b7323ab94..e8d957bbc 100644 --- a/apps/trading/client-pages/referrals/hooks/__generated__/ReferralSetStats.ts +++ b/apps/trading/client-pages/referrals/hooks/__generated__/ReferralSetStats.ts @@ -9,7 +9,7 @@ export type ReferralSetStatsQueryVariables = Types.Exact<{ }>; -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 } } | null> } }; +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` @@ -23,6 +23,8 @@ export const ReferralSetStatsDocument = gql` rewardFactor epochNotionalTakerVolume referralSetRunningNotionalTakerVolume + rewardsMultiplier + rewardsFactorMultiplier } } } diff --git a/apps/trading/client-pages/referrals/hooks/__generated__/ReferralSets.ts b/apps/trading/client-pages/referrals/hooks/__generated__/ReferralSets.ts new file mode 100644 index 000000000..99eca7725 --- /dev/null +++ b/apps/trading/client-pages/referrals/hooks/__generated__/ReferralSets.ts @@ -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; + referrer?: Types.InputMaybe; + referee?: Types.InputMaybe; +}>; + + +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) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ReferralSetsDocument, options); + } +export function useReferralSetsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ReferralSetsDocument, options); + } +export type ReferralSetsQueryHookResult = ReturnType; +export type ReferralSetsLazyQueryHookResult = ReturnType; +export type ReferralSetsQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/trading/client-pages/referrals/hooks/__generated__/Referrer.ts b/apps/trading/client-pages/referrals/hooks/__generated__/Referrer.ts deleted file mode 100644 index ebb8b37a0..000000000 --- a/apps/trading/client-pages/referrals/hooks/__generated__/Referrer.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as Types from '@vegaprotocol/types'; - -import { gql } from '@apollo/client'; -import * as Apollo from '@apollo/client'; -const defaultOptions = {} as const; -export type ReferrerQueryVariables = Types.Exact<{ - partyId: Types.Scalars['ID']; -}>; - - -export type ReferrerQuery = { __typename?: 'Query', referralSets: { __typename?: 'ReferralSetConnection', edges: Array<{ __typename?: 'ReferralSetEdge', node: { __typename?: 'ReferralSet', id: string, referrer: string, createdAt: any, updatedAt: any } } | null> } }; - - -export const ReferrerDocument = gql` - query Referrer($partyId: ID!) { - referralSets(referrer: $partyId) { - edges { - node { - id - referrer - createdAt - updatedAt - } - } - } -} - `; - -/** - * __useReferrerQuery__ - * - * To run a query within a React component, call `useReferrerQuery` and pass it any options that fit your needs. - * When your component renders, `useReferrerQuery` 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 } = useReferrerQuery({ - * variables: { - * partyId: // value for 'partyId' - * }, - * }); - */ -export function useReferrerQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(ReferrerDocument, options); - } -export function useReferrerLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(ReferrerDocument, options); - } -export type ReferrerQueryHookResult = ReturnType; -export type ReferrerLazyQueryHookResult = ReturnType; -export type ReferrerQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/apps/trading/client-pages/referrals/hooks/use-referral-program.ts b/apps/trading/client-pages/referrals/hooks/use-referral-program.ts index 419dfdb73..7a1a6cc76 100644 --- a/apps/trading/client-pages/referrals/hooks/use-referral-program.ts +++ b/apps/trading/client-pages/referrals/hooks/use-referral-program.ts @@ -1,12 +1,8 @@ -import { useQuery } from '@apollo/client'; import { getNumberFormat } from '@vegaprotocol/utils'; import { addDays } from 'date-fns'; import sortBy from 'lodash/sortBy'; import omit from 'lodash/omit'; -import { - ReferralProgramDocument, - useReferralProgramQuery, -} from './__generated__/CurrentReferralProgram'; +import { useReferralProgramQuery } from './__generated__/CurrentReferralProgram'; const STAKING_TIERS_MAPPING: Record = { 1: 'Tradestarter', diff --git a/apps/trading/client-pages/referrals/hooks/use-referral.ts b/apps/trading/client-pages/referrals/hooks/use-referral.ts index c1445e2ee..e08bb2e34 100644 --- a/apps/trading/client-pages/referrals/hooks/use-referral.ts +++ b/apps/trading/client-pages/referrals/hooks/use-referral.ts @@ -1,47 +1,66 @@ -import { useQuery } from '@apollo/client'; import { removePaginationWrapper } from '@vegaprotocol/utils'; import { useCallback } from 'react'; -import { ReferrerDocument } from './__generated__/Referrer'; -import { RefereeDocument } from './__generated__/Referee'; import { useRefereesQuery } from './__generated__/Referees'; import compact from 'lodash/compact'; +import type { ReferralSetsQueryVariables } from './__generated__/ReferralSets'; +import { useReferralSetsQuery } from './__generated__/ReferralSets'; + +const DEFAULT_AGGREGATION_DAYS = 30; export type Role = 'referrer' | 'referee'; -export type ReferralData = { - pubKey: string; - role: Role; - code: string; - createdAt: string; - referees: Array<{ - refereeId: string; - joinedAt: string; - atEpoch: number; - }>; +type UseReferralArgs = ( + | { code: string } + | { pubKey: string | null; role: Role } +) & { + aggregationDays?: number; }; -export const useReferral = (pubKey: string | null, role: Role) => { - const query = { - referrer: ReferrerDocument, - referee: RefereeDocument, - }; +const prepareVariables = ( + args: UseReferralArgs +): [ReferralSetsQueryVariables, boolean] => { + const byCode = 'code' in args; + const byRole = 'pubKey' in args && 'role' in args; + let variables = {}; + 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 { data: referralData, loading: referralLoading, error: referralError, refetch: referralRefetch, - } = useQuery(query[role], { - variables: { - partyId: pubKey, - }, - skip: !pubKey, + } = useReferralSetsQuery({ + variables, + skip, fetchPolicy: 'cache-and-network', }); // A user can only have 1 active referral program at a time - const referral = referralData?.referralSets.edges.length - ? referralData.referralSets.edges[0].node - : undefined; + const referralSet = + referralData?.referralSets.edges && + referralData.referralSets.edges.length > 0 + ? referralData.referralSets.edges[0]?.node + : undefined; const { data: refereesData, @@ -50,9 +69,13 @@ export const useReferral = (pubKey: string | null, role: Role) => { refetch: refereesRefetch, } = useRefereesQuery({ 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', }); @@ -65,19 +88,26 @@ export const useReferral = (pubKey: string | null, role: Role) => { 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 = - referral && refereesData + referralSet && refereesData ? { - pubKey, - role, - code: referral.id, - createdAt: referral.createdAt, + code: referralSet.id, + role: 'role' in args ? args.role : null, + referee: referee, + referrerId: referralSet.referrer, + createdAt: referralSet.createdAt, referees, } : undefined; return { - data: data as ReferralData | undefined, + data, loading: referralLoading || refereesLoading, error: referralError || refereesError, refetch, diff --git a/apps/trading/client-pages/referrals/referral-statistics.tsx b/apps/trading/client-pages/referrals/referral-statistics.tsx index a6ed0baf1..b39f36ff6 100644 --- a/apps/trading/client-pages/referrals/referral-statistics.tsx +++ b/apps/trading/client-pages/referrals/referral-statistics.tsx @@ -6,7 +6,6 @@ import { } from '@vegaprotocol/ui-toolkit'; import { useVegaWallet } from '@vegaprotocol/wallet'; -import type { ReferralData } from './hooks/use-referral'; import { useReferral } from './hooks/use-referral'; import { CreateCodeContainer } from './create-code-form'; import classNames from 'classnames'; @@ -23,16 +22,22 @@ import { useReferralSetStatsQuery } from './hooks/__generated__/ReferralSetStats import compact from 'lodash/compact'; import { useReferralProgram } from './hooks/use-referral-program'; import { useStakeAvailable } from './hooks/use-stake-available'; -import minBy from 'lodash/minBy'; import sortBy from 'lodash/sortBy'; import { useLayoutEffect, useRef, useState } from 'react'; import { useCurrentEpochInfoQuery } from './hooks/__generated__/Epoch'; +import BigNumber from 'bignumber.js'; export const ReferralStatistics = () => { const { pubKey } = useVegaWallet(); - const { data: referee } = useReferral(pubKey, 'referee'); - const { data: referrer } = useReferral(pubKey, 'referrer'); + const { data: referee } = useReferral({ + pubKey, + role: 'referee', + }); + const { data: referrer } = useReferral({ + pubKey, + role: 'referrer', + }); if (referee?.code) { return ; @@ -45,16 +50,16 @@ export const ReferralStatistics = () => { return ; }; -const Statistics = ({ +export const Statistics = ({ data, as, }: { - data: ReferralData; + data: NonNullable['data']>; as: 'referrer' | 'referee'; }) => { const { data: epochData } = useCurrentEpochInfoQuery(); const { stakeAvailable } = useStakeAvailable(); - const { stakingTiers, benefitTiers } = useReferralProgram(); + const { benefitTiers } = useReferralProgram(); const { data: statsData } = useReferralSetStatsQuery({ variables: { code: data.code, @@ -68,31 +73,24 @@ const Statistics = ({ const stats = statsData?.referralSetStats.edges && compact(removePaginationWrapper(statsData.referralSetStats.edges)); - const refereeInfo = data.referees.find((r) => r.refereeId === data.pubKey); + const refereeInfo = data.referee; + const refereeStats = stats?.find( + (r) => r.partyId === data.referee?.refereeId + ); - const refereeStats = stats?.find((r) => r.partyId === data.pubKey); - - // console.table(stats); - - const baseCommissionValue = - stats && stats.length > 0 ? Number(stats[0].rewardFactor) : 0; - const runningVolumeValue = - stats && stats.length > 0 - ? Number(stats[0].referralSetRunningNotionalTakerVolume) - : 0; - const stakingTier = - stakingTiers && - stakeAvailable && - minBy( - stakingTiers.filter( - (st) => BigInt(st.minimumStakedTokens) <= stakeAvailable - ), - (st) => BigInt(st.minimumStakedTokens) - )?.tier; - const finalCommissionValue = - !stakingTier || isNaN(stakingTier) - ? baseCommissionValue - : stakingTier * baseCommissionValue; + 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) @@ -130,7 +128,7 @@ const Statistics = ({ 18 )} $VEGA staked)`} > - {stakingTier || 'None'} + {multiplier || 'None'} ); const finalCommissionTile = ( @@ -152,9 +150,12 @@ const Statistics = ({ ); + const totalCommissionValue = data.referees + .map((r) => new BigNumber(r.totalRefereeGeneratedRewards)) + .reduce((all, r) => all.plus(r), new BigNumber(0)); const totalCommissionTile = ( - - ... + + {getNumberFormat(0).format(Number(totalCommissionValue))} ); @@ -274,23 +275,29 @@ const Statistics = ({ columns={[ { name: 'party', displayName: 'Trader' }, { name: 'joined', displayName: 'Date Joined' }, - { name: 'volume', displayName: 'Volume' }, + { name: 'volume', displayName: 'Volume (last 30 days)' }, + { + name: 'commission', + displayName: 'Commission earned (last 30 days)', + }, ]} data={sortBy( data.referees.map((r) => ({ - party: {truncateMiddle(r.refereeId)}, + party: ( + + {truncateMiddle(r.refereeId)} + + ), joined: getDateTimeFormat().format(new Date(r.joinedAt)), - volume: - Number( - stats?.find((s) => s.partyId === r.refereeId) - ?.epochNotionalTakerVolume - ) || 0, + 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()} /> diff --git a/apps/trading/client-pages/referrals/referrals.tsx b/apps/trading/client-pages/referrals/referrals.tsx index 6f8c0f2bb..0a9568b2a 100644 --- a/apps/trading/client-pages/referrals/referrals.tsx +++ b/apps/trading/client-pages/referrals/referrals.tsx @@ -1,4 +1,5 @@ import { + Loader, TradingAnchorButton, VegaIcon, VegaIconNames, @@ -25,18 +26,37 @@ const Nav = () => ( export const Referrals = () => { const { pubKey } = useVegaWallet(); - const { data: referee } = useReferral(pubKey, 'referee'); - const { data: referrer } = useReferral(pubKey, 'referrer'); - const showNav = !referrer && !referee; + const { data: referee, loading: refereeLoading } = useReferral({ + pubKey, + role: 'referee', + }); + const { data: referrer, loading: referrerLoading } = useReferral({ + pubKey, + role: 'referrer', + }); + + const loading = refereeLoading || referrerLoading; + const showNav = !loading && !referrer && !referee; return ( <> {showNav &&