Commit e0b89d05 authored by Igor Stuev's avatar Igor Stuev Committed by GitHub

Humanity score integration (#2354)

* Humanity score integration

* isLoading fix
parent c91bd810
......@@ -37,3 +37,4 @@ export { default as addressProfileAPI } from './addressProfileAPI';
export { default as validators } from './validators';
export { default as verifiedTokens } from './verifiedTokens';
export { default as web3Wallet } from './web3Wallet';
export { default as xStarScore } from './xStarScore';
import type { Feature } from './types';
import { getEnvValue } from '../utils';
const title = 'Xname score';
const url = getEnvValue('NEXT_PUBLIC_XNAME_SCORE_URL');
const config: Feature<{ url: string }> = (() => {
if (url) {
return Object.freeze({
title,
url,
isEnabled: true,
});
}
return Object.freeze({
title,
isEnabled: false,
});
})();
export default config;
......@@ -62,3 +62,4 @@ NEXT_PUBLIC_TRANSACTION_INTERPRETATION_PROVIDER=noves
NEXT_PUBLIC_VIEWS_CONTRACT_SOLIDITYSCAN_ENABLED=true
NEXT_PUBLIC_VISUALIZE_API_HOST=https://visualizer.services.blockscout.com
NEXT_PUBLIC_REWARDS_SERVICE_API_HOST=https://points.k8s-dev.blockscout.com
NEXT_PUBLIC_XSTAR_SCORE_URL='https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm?utm_source=blockscout&utm_medium=address'
......@@ -837,6 +837,7 @@ const schema = yup
return isUndefined || valueSchema.isValidSync(data);
}),
NEXT_PUBLIC_REWARDS_SERVICE_API_HOST: yup.string().test(urlTest),
NEXT_PUBLIC_XSTAR_SCORE_URL: yup.string().test(urlTest),
// 6. External services envs
NEXT_PUBLIC_WALLET_CONNECT_PROJECT_ID: yup.string(),
......
......@@ -55,6 +55,7 @@ Please be aware that all environment variables prefixed with `NEXT_PUBLIC_` will
- [Bridged tokens](ENVS.md#bridged-tokens)
- [Safe{Core} address tags](ENVS.md#safecore-address-tags)
- [Address profile API](ENVS.md#address-profile-api)
- [Address XStar XHS score](ENVS.md#address-xstar-xhs-score)
- [SUAVE chain](ENVS.md#suave-chain)
- [MetaSuites extension](ENVS.md#metasuites-extension)
- [Validators list](ENVS.md#validators-list)
......@@ -680,6 +681,16 @@ This feature allows the integration of an external API to fetch user info for ad
&nbsp;
### Address XStar XHS score
This feature allows the integration of an XStar API to fetch XHS score for addresses. When configured, if the API returns a score, a public tag with that score will be displayed in the address page header.
| Variable | Type| Description | Compulsoriness | Default value | Example value | Version |
| --- | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_XSTAR_SCORE_URL | `string` | XStar XHS score documentation URL for the address tag. Enables the XStar score feature. | - | - | `https://docs.xname.app/the-solution-adaptive-proof-of-humanity-on-blockchain/xhs-scoring-algorithm` | v1.36.0+ |
&nbsp;
### SUAVE chain
For blockchains that implement SUAVE architecture additional fields will be shown on the transaction page ("Allowed peekers", "Kettle"). Users also will be able to see the list of all transactions for a particular Kettle in the separate view.
......
......@@ -38,6 +38,7 @@ import type {
AddressMudRecordsSorting,
AddressMudRecord,
AddressEpochRewardsResponse,
AddressXStarResponse,
} from 'types/api/address';
import type { AddressesResponse, AddressesMetadataSearchResult, AddressesMetadataSearchFilters } from 'types/api/addresses';
import type { AddressMetadataInfo, PublicTagTypesResponse } from 'types/api/addressMetadata';
......@@ -595,6 +596,10 @@ export const RESOURCES = {
pathParams: [ 'hash' as const ],
filterFields: [],
},
address_xstar_score: {
path: '/api/v2/proxy/xname/address/:hash',
pathParams: [ 'hash' as const ],
},
// CONTRACT
contract: {
......@@ -1304,6 +1309,7 @@ Q extends 'rewards_user_daily_check' ? RewardsUserDailyCheckResponse :
Q extends 'rewards_user_daily_claim' ? RewardsUserDailyClaimResponse :
Q extends 'rewards_user_referrals' ? RewardsUserReferralsResponse :
Q extends 'token_transfers_all' ? TokenTransferResponse :
Q extends 'address_xstar_score' ? AddressXStarResponse :
never;
/* eslint-enable @typescript-eslint/indent */
......
import React from 'react';
import * as v from 'valibot';
import config from 'configs/app';
import buildUrl from 'lib/api/buildUrl';
import useApiQuery from 'lib/api/useApiQuery';
interface Params {
hash: string;
}
const RESOURCE_NAME = 'address_xstar_score';
const ERROR_NAME = 'Invalid response schema';
export default function useFetchXStarScore({ hash }: Params) {
const query = useApiQuery(RESOURCE_NAME, {
pathParams: { hash },
queryOptions: {
select: (response) => {
const parsedResponse = v.safeParse(v.object({ data: v.string() }), response);
if (!parsedResponse.success) {
throw Error(ERROR_NAME);
}
return parsedResponse.output;
},
enabled: Boolean(hash) && config.features.xStarScore.isEnabled,
placeholderData: {
data: 'Base' as const,
},
retry: 0,
},
});
const errorMessage = query.error && 'message' in query.error ? query.error.message : undefined;
React.useEffect(() => {
if (errorMessage === ERROR_NAME) {
fetch('/node-api/monitoring/invalid-api-schema', {
method: 'POST',
body: JSON.stringify({
resource: RESOURCE_NAME,
url: buildUrl(RESOURCE_NAME, { hash }, undefined, true),
}),
});
}
}, [ errorMessage, hash ]);
return query;
}
......@@ -270,3 +270,7 @@ export type AddressEpochRewardsItem = {
epoch_number: number;
associated_account: AddressParam;
}
export type AddressXStarResponse = {
data: string | null;
}
......@@ -16,6 +16,7 @@ import getNetworkValidationActionText from 'lib/networks/getNetworkValidationAct
import getQueryParamString from 'lib/router/getQueryParamString';
import useSocketChannel from 'lib/socket/useSocketChannel';
import useSocketMessage from 'lib/socket/useSocketMessage';
import useFetchXStarScore from 'lib/xStarScore/useFetchXStarScore';
import { ADDRESS_TABS_COUNTERS } from 'stubs/address';
import { USER_OPS_ACCOUNT } from 'stubs/userOps';
import AddressAccountHistory from 'ui/address/AddressAccountHistory';
......@@ -58,6 +59,7 @@ const TOKEN_TABS = [ 'tokens_erc20', 'tokens_nfts', 'tokens_nfts_collection', 't
const txInterpretation = config.features.txInterpretation;
const addressProfileAPIFeature = config.features.addressProfileAPI;
const xScoreFeature = config.features.xStarScore;
const AddressPageContent = () => {
const router = useRouter();
......@@ -139,6 +141,8 @@ const AddressPageContent = () => {
const isSafeAddress = useIsSafeAddress(!addressQuery.isPlaceholderData && addressQuery.data?.is_contract ? hash : undefined);
const safeIconColor = useColorModeValue('black', 'white');
const xStarQuery = useFetchXStarScore({ hash });
const contractTabs = useContractTabs(
addressQuery.data,
config.features.mudFramework.isEnabled ? (mudTablesCountQuery.isPlaceholderData || addressQuery.isPlaceholderData) : addressQuery.isPlaceholderData,
......@@ -295,8 +299,32 @@ const AddressPageContent = () => {
undefined,
...formatUserTags(addressQuery.data),
...(addressMetadataQuery.data?.addresses?.[hash.toLowerCase()]?.tags.filter(tag => tag.tagType !== 'note') || []),
!addressQuery.data?.is_contract && xScoreFeature.isEnabled && xStarQuery.data?.data ?
{
slug: 'xstar',
name: `XHS ${ xStarQuery.data.data } level`,
tagType: 'custom' as const,
ordinal: 12,
meta: {
tagUrl: xScoreFeature.url,
tooltipTitle: 'XStar humanity levels',
tooltipDescription:
'XStar looks for off-chain information about an address and interpret it as a XHS score. Different score means different humanity levels.',
tooltipUrl: xScoreFeature.url,
},
} :
undefined,
].filter(Boolean).sort(sortEntityTags);
}, [ addressMetadataQuery.data, addressQuery.data, hash, isSafeAddress, userOpsAccountQuery.data, mudTablesCountQuery.data, usernameApiTag ]);
}, [
addressMetadataQuery.data,
addressQuery.data,
hash,
isSafeAddress,
userOpsAccountQuery.data,
mudTablesCountQuery.data,
usernameApiTag,
xStarQuery.data?.data,
]);
const titleContentAfter = (
<EntityTags
......@@ -305,7 +333,8 @@ const AddressPageContent = () => {
isLoading ||
(config.features.userOps.isEnabled && userOpsAccountQuery.isPlaceholderData) ||
(config.features.addressMetadata.isEnabled && addressMetadataQuery.isPending) ||
(addressProfileAPIFeature.isEnabled && userPropfileApiQuery.isPending)
(addressProfileAPIFeature.isEnabled && userPropfileApiQuery.isPending) ||
(xScoreFeature.isEnabled && xStarQuery.isPlaceholderData)
}
/>
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment