diff --git a/explorer/.env.sample b/explorer/.env.sample index 9ebf1d998..d23f2edb4 100644 --- a/explorer/.env.sample +++ b/explorer/.env.sample @@ -19,6 +19,9 @@ DISCORD_BOT_TOKEN="" # Subspace Discord Server Role ID's DISCORD_GUILD_ROLE_ID_FARMER="" +DISCORD_GUILD_ROLE_ID_OPERATOR="" +DISCORD_GUILD_ROLE_ID_NOMINATOR="" + # RPC URL NEXT_PUBLIC_RPC_URL="wss://" @@ -26,7 +29,5 @@ NEXT_PUBLIC_NOVA_RPC_URL="wss://" # Mock Wallet Configuration (to be used for development only) # NEXT_PUBLIC_MOCK_WALLET="true" -# NEXT_PUBLIC_MOCK_WALLET_ADDRESS="" # jeremy -# NEXT_PUBLIC_MOCK_WALLET_ADDRESS="" # top 10 farmer -# NEXT_PUBLIC_MOCK_WALLET_ADDRESS="" # top 10 nominators +# NEXT_PUBLIC_MOCK_WALLET_ADDRESS="" # NEXT_PUBLIC_MOCK_WALLET_SOURCE="polkadot-js" \ No newline at end of file diff --git a/explorer/gql/gql.ts b/explorer/gql/gql.ts index 28db9f2b1..5937f5602 100644 --- a/explorer/gql/gql.ts +++ b/explorer/gql/gql.ts @@ -48,7 +48,7 @@ const documents = { "\n query AccountsTopLeaderboard($first: Int!) {\n farmers: accountRewardsConnection(\n orderBy: amount_DESC\n first: $first\n where: { vote_gt: 0, vote_isNull: false, OR: { block_gt: 0, block_isNull: false } }\n ) {\n edges {\n cursor\n node {\n id\n }\n }\n }\n operators: operatorRewardsConnection(orderBy: amount_DESC, first: $first, where: {}) {\n edges {\n cursor\n node {\n amount\n id\n }\n }\n }\n nominators: accountRewardsConnection(\n orderBy: operator_DESC\n first: $first\n where: { operator_gt: 0, operator_isNull: false }\n ) {\n edges {\n cursor\n node {\n id\n }\n }\n }\n }\n": types.AccountsTopLeaderboardDocument, "\n query ExtrinsicsSummary($first: Int!, $subspaceAccount: String) {\n extrinsics: extrinsicsConnection(\n orderBy: id_DESC\n first: $first\n where: { signer: { id_eq: $subspaceAccount } }\n ) {\n edges {\n node {\n id\n success\n block {\n id\n timestamp\n height\n }\n name\n }\n }\n totalCount\n }\n }\n": types.ExtrinsicsSummaryDocument, "\n query StakingSummary($first: Int!, $subspaceAccount: String) {\n operators: operatorsConnection(\n orderBy: id_ASC\n first: $first\n where: { operatorOwner_eq: $subspaceAccount }\n ) {\n edges {\n node {\n id\n operatorOwner\n currentDomainId\n currentTotalStake\n totalShares\n }\n }\n totalCount\n }\n nominators: nominatorsConnection(\n orderBy: id_ASC\n first: $first\n where: { account: { id_eq: $subspaceAccount } }\n ) {\n edges {\n node {\n id\n shares\n account {\n id\n }\n operator {\n id\n operatorOwner\n currentDomainId\n currentTotalStake\n totalShares\n }\n }\n }\n totalCount\n }\n }\n": types.StakingSummaryDocument, - "\n query CheckRole($subspaceAccount: String!) {\n isFarmer: rewardEvents(\n where: { name_eq: \"Rewards.VoteReward\", account: { id_eq: $subspaceAccount } }\n limit: 1\n ) {\n account {\n id\n }\n }\n }\n": types.CheckRoleDocument, + "\n query CheckRole($subspaceAccount: String!) {\n farmer: rewardEvents(\n where: { name_eq: \"Rewards.VoteReward\", account: { id_eq: $subspaceAccount } }\n limit: 1\n ) {\n account {\n id\n }\n }\n operator: operatorsConnection(\n first: 1\n where: { operatorOwner_eq: $subspaceAccount }\n orderBy: id_ASC\n ) {\n totalCount\n }\n nominator: nominatorsConnection(\n first: 1\n where: { account: { id_eq: $subspaceAccount } }\n orderBy: id_ASC\n ) {\n totalCount\n }\n }\n": types.CheckRoleDocument, "\n query BlocksAndExtrinsicByHash($hash: String!) {\n blocks(limit: 10, where: { hash_eq: $hash }) {\n id\n height\n }\n extrinsics(limit: 10, where: { hash_eq: $hash }) {\n id\n }\n }\n": types.BlocksAndExtrinsicByHashDocument, "\n query GetResults(\n $term: String!\n $blockId: BigInt!\n $isAccount: Boolean!\n $isBlock: Boolean!\n $isExtrinsic: Boolean!\n $isExtrinsicHash: Boolean!\n $isEvent: Boolean!\n ) {\n accountById(id: $term) @include(if: $isAccount) {\n id\n }\n blocks(limit: 1, where: { height_eq: $blockId }) @include(if: $isBlock) {\n height\n }\n extrinsicById(id: $term) @include(if: $isExtrinsic) {\n id\n name\n block {\n height\n }\n indexInBlock\n timestamp\n }\n extrinsics(limit: 1, where: { hash_eq: $term }) @include(if: $isExtrinsicHash) {\n id\n }\n eventById(id: $term) @include(if: $isEvent) {\n id\n name\n block {\n height\n }\n indexInBlock\n timestamp\n }\n }\n": types.GetResultsDocument, }; @@ -210,7 +210,7 @@ export function graphql(source: "\n query StakingSummary($first: Int!, $subspac /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query CheckRole($subspaceAccount: String!) {\n isFarmer: rewardEvents(\n where: { name_eq: \"Rewards.VoteReward\", account: { id_eq: $subspaceAccount } }\n limit: 1\n ) {\n account {\n id\n }\n }\n }\n"): (typeof documents)["\n query CheckRole($subspaceAccount: String!) {\n isFarmer: rewardEvents(\n where: { name_eq: \"Rewards.VoteReward\", account: { id_eq: $subspaceAccount } }\n limit: 1\n ) {\n account {\n id\n }\n }\n }\n"]; +export function graphql(source: "\n query CheckRole($subspaceAccount: String!) {\n farmer: rewardEvents(\n where: { name_eq: \"Rewards.VoteReward\", account: { id_eq: $subspaceAccount } }\n limit: 1\n ) {\n account {\n id\n }\n }\n operator: operatorsConnection(\n first: 1\n where: { operatorOwner_eq: $subspaceAccount }\n orderBy: id_ASC\n ) {\n totalCount\n }\n nominator: nominatorsConnection(\n first: 1\n where: { account: { id_eq: $subspaceAccount } }\n orderBy: id_ASC\n ) {\n totalCount\n }\n }\n"): (typeof documents)["\n query CheckRole($subspaceAccount: String!) {\n farmer: rewardEvents(\n where: { name_eq: \"Rewards.VoteReward\", account: { id_eq: $subspaceAccount } }\n limit: 1\n ) {\n account {\n id\n }\n }\n operator: operatorsConnection(\n first: 1\n where: { operatorOwner_eq: $subspaceAccount }\n orderBy: id_ASC\n ) {\n totalCount\n }\n nominator: nominatorsConnection(\n first: 1\n where: { account: { id_eq: $subspaceAccount } }\n orderBy: id_ASC\n ) {\n totalCount\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/explorer/gql/graphql.ts b/explorer/gql/graphql.ts index 415c3663a..a56737df5 100644 --- a/explorer/gql/graphql.ts +++ b/explorer/gql/graphql.ts @@ -2825,7 +2825,7 @@ export type CheckRoleQueryVariables = Exact<{ }>; -export type CheckRoleQuery = { __typename?: 'Query', isFarmer: Array<{ __typename?: 'RewardEvent', account?: { __typename?: 'Account', id: string } | null }> }; +export type CheckRoleQuery = { __typename?: 'Query', farmer: Array<{ __typename?: 'RewardEvent', account?: { __typename?: 'Account', id: string } | null }>, operator: { __typename?: 'OperatorsConnection', totalCount: number }, nominator: { __typename?: 'NominatorsConnection', totalCount: number } }; export type BlocksAndExtrinsicByHashQueryVariables = Exact<{ hash: Scalars['String']['input']; @@ -2883,6 +2883,6 @@ export const NominatorsConnectionDocument = {"kind":"Document","definitions":[{" export const AccountsTopLeaderboardDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AccountsTopLeaderboard"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"farmers"},"name":{"kind":"Name","value":"accountRewardsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"amount_DESC"}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"vote_gt"},"value":{"kind":"IntValue","value":"0"}},{"kind":"ObjectField","name":{"kind":"Name","value":"vote_isNull"},"value":{"kind":"BooleanValue","value":false}},{"kind":"ObjectField","name":{"kind":"Name","value":"OR"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"block_gt"},"value":{"kind":"IntValue","value":"0"}},{"kind":"ObjectField","name":{"kind":"Name","value":"block_isNull"},"value":{"kind":"BooleanValue","value":false}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"operators"},"name":{"kind":"Name","value":"operatorRewardsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"amount_DESC"}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"amount"}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"nominators"},"name":{"kind":"Name","value":"accountRewardsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"operator_DESC"}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"operator_gt"},"value":{"kind":"IntValue","value":"0"}},{"kind":"ObjectField","name":{"kind":"Name","value":"operator_isNull"},"value":{"kind":"BooleanValue","value":false}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cursor"}},{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ExtrinsicsSummaryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ExtrinsicsSummary"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"extrinsics"},"name":{"kind":"Name","value":"extrinsicsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"id_DESC"}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"signer"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"success"}},{"kind":"Field","name":{"kind":"Name","value":"block"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const StakingSummaryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"StakingSummary"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"first"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"operators"},"name":{"kind":"Name","value":"operatorsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"id_ASC"}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"operatorOwner_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"operatorOwner"}},{"kind":"Field","name":{"kind":"Name","value":"currentDomainId"}},{"kind":"Field","name":{"kind":"Name","value":"currentTotalStake"}},{"kind":"Field","name":{"kind":"Name","value":"totalShares"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"nominators"},"name":{"kind":"Name","value":"nominatorsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"id_ASC"}},{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"Variable","name":{"kind":"Name","value":"first"}}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"account"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"shares"}},{"kind":"Field","name":{"kind":"Name","value":"account"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"operator"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"operatorOwner"}},{"kind":"Field","name":{"kind":"Name","value":"currentDomainId"}},{"kind":"Field","name":{"kind":"Name","value":"currentTotalStake"}},{"kind":"Field","name":{"kind":"Name","value":"totalShares"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; -export const CheckRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CheckRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"isFarmer"},"name":{"kind":"Name","value":"rewardEvents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name_eq"},"value":{"kind":"StringValue","value":"Rewards.VoteReward","block":false}},{"kind":"ObjectField","name":{"kind":"Name","value":"account"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"account"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; +export const CheckRoleDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"CheckRole"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"farmer"},"name":{"kind":"Name","value":"rewardEvents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"name_eq"},"value":{"kind":"StringValue","value":"Rewards.VoteReward","block":false}},{"kind":"ObjectField","name":{"kind":"Name","value":"account"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"account"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","alias":{"kind":"Name","value":"operator"},"name":{"kind":"Name","value":"operatorsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"operatorOwner_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"id_ASC"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}},{"kind":"Field","alias":{"kind":"Name","value":"nominator"},"name":{"kind":"Name","value":"nominatorsConnection"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"first"},"value":{"kind":"IntValue","value":"1"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"account"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subspaceAccount"}}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"EnumValue","value":"id_ASC"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const BlocksAndExtrinsicByHashDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"BlocksAndExtrinsicByHash"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"hash"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"blocks"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"10"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"hash_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hash"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"Field","name":{"kind":"Name","value":"extrinsics"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"10"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"hash_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"hash"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const GetResultsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetResults"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"term"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"blockId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"BigInt"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isAccount"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isBlock"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isExtrinsic"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isExtrinsicHash"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isEvent"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accountById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isAccount"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"blocks"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"height_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"blockId"}}}]}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isBlock"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"Field","name":{"kind":"Name","value":"extrinsicById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isExtrinsic"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"block"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"Field","name":{"kind":"Name","value":"indexInBlock"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"extrinsics"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}},{"kind":"Argument","name":{"kind":"Name","value":"where"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"hash_eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}}]}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isExtrinsicHash"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"eventById"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"term"}}}],"directives":[{"kind":"Directive","name":{"kind":"Name","value":"include"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"if"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isEvent"}}}]}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"block"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"height"}}]}},{"kind":"Field","name":{"kind":"Name","value":"indexInBlock"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file diff --git a/explorer/src/components/WalletSideKick/GetDiscordRoles.tsx b/explorer/src/components/WalletSideKick/GetDiscordRoles.tsx index 2ccc60c4f..d34b53d92 100644 --- a/explorer/src/components/WalletSideKick/GetDiscordRoles.tsx +++ b/explorer/src/components/WalletSideKick/GetDiscordRoles.tsx @@ -1,14 +1,11 @@ import { CheckMarkIcon } from '@/components/icons/CheckMarkIcon' -import { useQuery } from '@apollo/client' import { Accordion } from 'components/common/Accordion' import { List, StyledListItem } from 'components/common/List' -import { CheckRoleQuery } from 'gql/graphql' import useWallet from 'hooks/useWallet' import { signIn, useSession } from 'next-auth/react' import Link from 'next/link' import { FC, useCallback, useMemo } from 'react' import toast from 'react-hot-toast' -import { QUERY_CHECK_ROLE } from './query' interface StakingSummaryProps { subspaceAccount: string @@ -29,22 +26,10 @@ const StyledButton: FC = ({ children, className, onClick }) = ) -export const GetDiscordRoles: FC = ({ subspaceAccount }) => { +export const SubspaceWalletFlow: FC = ({ subspaceAccount }) => { const { data: session } = useSession() const { actingAccount, injector } = useWallet() - const summaryVariables = useMemo( - () => ({ - first: 10, - subspaceAccount, - }), - [subspaceAccount], - ) - const { data } = useQuery(QUERY_CHECK_ROLE, { - variables: summaryVariables, - pollInterval: 6000, - }) - const handleWalletOwnership = useCallback(async () => { try { if (!actingAccount || !injector) throw new Error('No wallet connected') @@ -74,67 +59,95 @@ export const GetDiscordRoles: FC = ({ subspaceAccount }) => } }, [actingAccount, injector, subspaceAccount]) + return ( + + {session?.user?.subspace?.signature ? ( + <> + + + Refresh + + + ) : ( + Sign + )} + + ) +} + +export const DiscordFlow: FC = () => { + const { data: session } = useSession() + const handleConnectDiscord = useCallback( async () => await signIn('discord', { redirect: false }), [], ) - const isFarmer = useMemo(() => data && data.isFarmer && data.isFarmer.length > 0, [data]) - - if (session?.user?.discord?.vcs.roles.farmer) - return ( -
- - - 🌾 - - -
+ return ( + session?.user?.subspace && ( + + {session?.user?.discord?.vcs.member ? ( + <> + + + Refresh + + + ) : ( + Connect + )} + ) + ) +} - if (isFarmer && !session?.user?.discord?.vcs.roles.farmer) - return ( -
- - - - {session?.user?.subspace?.signature ? ( - <> - - - Refresh - - - ) : ( - Sign - )} - - {!session?.user?.discord?.vcs.member && ( - - - Join - - - )} +export const GetDiscordRoles: FC = ({ subspaceAccount }) => { + const { data: session } = useSession() - {session?.user?.subspace && ( - - {session?.user?.discord?.vcs.member ? ( - <> - - - Refresh - - - ) : ( - Connect - )} - - )} - - -
- ) + const hasAnyRoles = useMemo( + () => + session?.user?.discord?.vcs && + Object.values(session.user.discord.vcs).some((role) => role === true), + [session], + ) - return <> + return ( +
+ {hasAnyRoles ? ( + <> + + + {session?.user?.discord?.vcs.roles.farmer && ( + 🌾 + )} + {session?.user?.discord?.vcs.roles.operator && ( + 🌐 + )} + {session?.user?.discord?.vcs.roles.nominator && ( + 🤝 + )} + + + + + + ) : ( + <> + + + + {!session?.user?.discord?.vcs.member && ( + + + Join + + + )} + + + + + )} +
+ ) } diff --git a/explorer/src/components/WalletSideKick/query.ts b/explorer/src/components/WalletSideKick/query.ts index e54ca559c..764785edf 100644 --- a/explorer/src/components/WalletSideKick/query.ts +++ b/explorer/src/components/WalletSideKick/query.ts @@ -106,9 +106,9 @@ export const QUERY_STAKING_SUMMARY = gql` } ` -export const QUERY_CHECK_ROLE = gql` +export const QUERY_CHECK_ROLES = gql` query CheckRole($subspaceAccount: String!) { - isFarmer: rewardEvents( + farmer: rewardEvents( where: { name_eq: "Rewards.VoteReward", account: { id_eq: $subspaceAccount } } limit: 1 ) { @@ -116,5 +116,19 @@ export const QUERY_CHECK_ROLE = gql` id } } + operator: operatorsConnection( + first: 1 + where: { operatorOwner_eq: $subspaceAccount } + orderBy: id_ASC + ) { + totalCount + } + nominator: nominatorsConnection( + first: 1 + where: { account: { id_eq: $subspaceAccount } } + orderBy: id_ASC + ) { + totalCount + } } ` diff --git a/explorer/src/utils/auth/providers/discord.ts b/explorer/src/utils/auth/providers/discord.ts index ac0232ac0..ca1f82dab 100644 --- a/explorer/src/utils/auth/providers/discord.ts +++ b/explorer/src/utils/auth/providers/discord.ts @@ -5,9 +5,14 @@ import type { DiscordProfile } from 'next-auth/providers/discord' import DiscordProvider from 'next-auth/providers/discord' import { cookies } from 'next/headers' import { + getUserRoles, giveDiscordFarmerRole, + giveDiscordNominatorRole, + giveDiscordOperatorRole, verifyDiscordFarmerRole, verifyDiscordGuildMember, + verifyDiscordNominatorRole, + verifyDiscordOperatorRole, } from '../vcs/discord' const { DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET } = process.env @@ -40,11 +45,29 @@ export const Discord = () => { const did = 'did:openid:discord:' + profile.id const member = await verifyDiscordGuildMember(token.access_token) - let farmer = await verifyDiscordFarmerRole(token.access_token) + const roles = await getUserRoles(token.access_token) + let farmer = await verifyDiscordFarmerRole(roles) + let operator = await verifyDiscordOperatorRole(roles) + let nominator = await verifyDiscordNominatorRole(roles) + let newRolesAdded = false if (session.subspace?.vcs.farmer && !farmer) { await giveDiscordFarmerRole(profile.id) - farmer = await verifyDiscordFarmerRole(token.access_token) + newRolesAdded = true + } + if (session.subspace?.vcs.operator && !operator) { + await giveDiscordOperatorRole(profile.id) + newRolesAdded = true + } + if (session.subspace?.vcs.nominator && !nominator) { + await giveDiscordNominatorRole(profile.id) + newRolesAdded = true + } + if (newRolesAdded) { + const newRoles = await getUserRoles(token.access_token) + farmer = await verifyDiscordFarmerRole(newRoles) + operator = await verifyDiscordOperatorRole(newRoles) + nominator = await verifyDiscordNominatorRole(newRoles) } return { @@ -58,9 +81,8 @@ export const Discord = () => { member, roles: { farmer, - // To-Do: Implement more role VCs - operator: false, - nominator: false, + operator, + nominator, }, }, }, diff --git a/explorer/src/utils/auth/providers/subspace.ts b/explorer/src/utils/auth/providers/subspace.ts index e01effcd5..4322c3e81 100644 --- a/explorer/src/utils/auth/providers/subspace.ts +++ b/explorer/src/utils/auth/providers/subspace.ts @@ -2,7 +2,7 @@ import { cryptoWaitReady, signatureVerify } from '@polkadot/util-crypto' import { DEFAULT_DISCORD_TOKEN } from 'constants/session' import type { Provider } from 'next-auth/providers' import CredentialsProvider from 'next-auth/providers/credentials' -import { verifySubspaceFarmer } from '../vcs/subspace' +import { verifySubspaceAccountRoles } from '../vcs/subspace' export const Subspace = () => { return CredentialsProvider({ @@ -34,7 +34,7 @@ export const Subspace = () => { const did = `did:subspace:${account}` // Verify Subspace VCs - const farmer = await verifySubspaceFarmer(account) + const { farmer, operator, nominator } = await verifySubspaceAccountRoles(account) // Return the user object if the credentials are valid return { @@ -46,9 +46,8 @@ export const Subspace = () => { signature, vcs: { farmer, - // To-Do: Implement more VCs - operator: false, - nominator: false, + operator, + nominator, }, }, discord: DEFAULT_DISCORD_TOKEN, diff --git a/explorer/src/utils/auth/vcs/discord/index.ts b/explorer/src/utils/auth/vcs/discord/index.ts index c0144a97f..20db1f7a4 100644 --- a/explorer/src/utils/auth/vcs/discord/index.ts +++ b/explorer/src/utils/auth/vcs/discord/index.ts @@ -1,4 +1,16 @@ import { verifyDiscordGuildMember } from './member' import { giveDiscordFarmerRole, verifyDiscordFarmerRole } from './role-farmer' +import { giveDiscordNominatorRole, verifyDiscordNominatorRole } from './role-nominator' +import { giveDiscordOperatorRole, verifyDiscordOperatorRole } from './role-operator' +import { getUserRoles } from './utils' -export { giveDiscordFarmerRole, verifyDiscordFarmerRole, verifyDiscordGuildMember } +export { + getUserRoles, + giveDiscordFarmerRole, + giveDiscordNominatorRole, + giveDiscordOperatorRole, + verifyDiscordFarmerRole, + verifyDiscordGuildMember, + verifyDiscordNominatorRole, + verifyDiscordOperatorRole, +} diff --git a/explorer/src/utils/auth/vcs/discord/role-farmer.ts b/explorer/src/utils/auth/vcs/discord/role-farmer.ts index 97d469737..cc87103a7 100644 --- a/explorer/src/utils/auth/vcs/discord/role-farmer.ts +++ b/explorer/src/utils/auth/vcs/discord/role-farmer.ts @@ -1,13 +1,10 @@ -import { getUserRoles, giveDiscordRole } from './utils' +import { giveDiscordRole } from './utils' -export const verifyDiscordFarmerRole = async (accessToken: string) => { +export const verifyDiscordFarmerRole = async (roles: string[]) => { if (!process.env.DISCORD_GUILD_ROLE_ID_FARMER) throw new Error('No Discord guild role ID for farmer') const { DISCORD_GUILD_ROLE_ID_FARMER } = process.env - // Get the user roles - const roles = await getUserRoles(accessToken) - // Check if the user has the farmer role return roles.includes(DISCORD_GUILD_ROLE_ID_FARMER) } diff --git a/explorer/src/utils/auth/vcs/discord/role-nominator.ts b/explorer/src/utils/auth/vcs/discord/role-nominator.ts new file mode 100644 index 000000000..85e18ca62 --- /dev/null +++ b/explorer/src/utils/auth/vcs/discord/role-nominator.ts @@ -0,0 +1,19 @@ +import { giveDiscordRole } from './utils' + +export const verifyDiscordNominatorRole = async (roles: string[]) => { + if (!process.env.DISCORD_GUILD_ROLE_ID_NOMINATOR) + throw new Error('No Discord guild role ID for nominator') + const { DISCORD_GUILD_ROLE_ID_NOMINATOR } = process.env + + // Check if the user has the nominator role + return roles.includes(DISCORD_GUILD_ROLE_ID_NOMINATOR) +} + +export const giveDiscordNominatorRole = async (userId: string) => { + if (!process.env.DISCORD_GUILD_ROLE_ID_NOMINATOR) + throw new Error('No Discord guild role ID for nominator') + const { DISCORD_GUILD_ROLE_ID_NOMINATOR } = process.env + + // Add the nominator role to the user + await giveDiscordRole(userId, DISCORD_GUILD_ROLE_ID_NOMINATOR, 'Give the user the nominator role') +} diff --git a/explorer/src/utils/auth/vcs/discord/role-operator.ts b/explorer/src/utils/auth/vcs/discord/role-operator.ts new file mode 100644 index 000000000..09122e697 --- /dev/null +++ b/explorer/src/utils/auth/vcs/discord/role-operator.ts @@ -0,0 +1,19 @@ +import { giveDiscordRole } from './utils' + +export const verifyDiscordOperatorRole = async (roles: string[]) => { + if (!process.env.DISCORD_GUILD_ROLE_ID_OPERATOR) + throw new Error('No Discord guild role ID for operator') + const { DISCORD_GUILD_ROLE_ID_OPERATOR } = process.env + + // Check if the user has the operator role + return roles.includes(DISCORD_GUILD_ROLE_ID_OPERATOR) +} + +export const giveDiscordOperatorRole = async (userId: string) => { + if (!process.env.DISCORD_GUILD_ROLE_ID_OPERATOR) + throw new Error('No Discord guild role ID for operator') + const { DISCORD_GUILD_ROLE_ID_OPERATOR } = process.env + + // Add the operator role to the user + await giveDiscordRole(userId, DISCORD_GUILD_ROLE_ID_OPERATOR, 'Give the user the operator role') +} diff --git a/explorer/src/utils/auth/vcs/subspace/events-farmer.ts b/explorer/src/utils/auth/vcs/subspace/events-farmer.ts deleted file mode 100644 index b9ee1283a..000000000 --- a/explorer/src/utils/auth/vcs/subspace/events-farmer.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { QUERY_CHECK_ROLE } from 'components/WalletSideKick/query' -import { queryGraphqlServer } from 'utils/queryGraphqlServer' - -export const verifySubspaceFarmer = async (subspaceAccount: string) => { - try { - if (!QUERY_CHECK_ROLE.loc) throw new Error('No query') - if (!subspaceAccount) throw new Error('No subspaceAccount') - - const data = await queryGraphqlServer(QUERY_CHECK_ROLE.loc.source.body, { subspaceAccount }) - - return data && data.isFarmer && data.isFarmer.length > 0 - } catch (error) { - console.error('Failed to fetch if user has any farmers related events:', error) - throw new Error('Failed to fetch if user has any farmers related events') - } -} diff --git a/explorer/src/utils/auth/vcs/subspace/index.ts b/explorer/src/utils/auth/vcs/subspace/index.ts index 579332dae..7f4004884 100644 --- a/explorer/src/utils/auth/vcs/subspace/index.ts +++ b/explorer/src/utils/auth/vcs/subspace/index.ts @@ -1,3 +1,21 @@ -import { verifySubspaceFarmer } from './events-farmer' +import { QUERY_CHECK_ROLES } from 'components/WalletSideKick/query' +import { queryGraphqlServer } from 'utils/queryGraphqlServer' -export { verifySubspaceFarmer } +export const verifySubspaceAccountRoles = async (subspaceAccount: string) => { + try { + if (!QUERY_CHECK_ROLES.loc) throw new Error('No query') + + const data = await queryGraphqlServer(QUERY_CHECK_ROLES.loc.source.body, { + subspaceAccount, + }) + + return { + farmer: data.farmer.length > 0, + operator: data.operator.totalCount > 0, + nominator: data.nominator.totalCount > 0, + } + } catch (error) { + console.error('Failed to fetch if user has any related events:', error) + throw new Error('Failed to fetch if user has any related events') + } +}