Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/empty-streets-wait.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@human-protocol/sdk": major
"@human-protocol/python-sdk": major
---

- Replace statistics client by utils
- Delete agreement module
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ HUMAN is a permissionless protocol to facilitate the exchange of HUMAN work, kno

### Documentation

For a more detailed description of the HUMAN Protocol architecture and vision see [here](https://tech-docs.humanprotocol.org/)
For a more detailed description of the HUMAN Protocol architecture and vision see [here](https://docs.humanprotocol.org/)

### Description

Expand Down Expand Up @@ -59,7 +59,7 @@ The contribution guidelines are as per the CONTRIBUTING.MD file.
│ │ │ ├── subgraph # Human Protocol Subgraph
```
### Smart contracts
To access comprehensive information about the smart contracts, please visit the following URL: https://tech-docs.humanprotocol.org/contracts. This resource provides detailed documentation that covers various aspects of the smart contracts used within the Human Protocol ecosystem.
To access comprehensive information about the smart contracts, please visit the following URL: https://docs.humanprotocol.org/architecture/contracts/escrow.sol. This resource provides detailed documentation that covers various aspects of the smart contracts used within the Human Protocol ecosystem.

### How To Use This Repo

Expand Down
2 changes: 1 addition & 1 deletion packages/apps/dashboard/client/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ VITE_NAVBAR_LINK_LAUNCH_JOBS=https://job-launcher.humanprotocol.org/
VITE_NAVBAR_LINK_WORK_AND_EARN=https://app.humanprotocol.org/

# Link to button on 'Role details' page
VITE_HUMANPROTOCOL_CORE_ARCHITECTURE=https://docs.humanprotocol.org/hub/human-tech-docs/architecture
VITE_HUMANPROTOCOL_CORE_ARCHITECTURE=https://docs.humanprotocol.org/architecture/overview/

# Links to footer socials
VITE_FOOTER_LINK_GITHUB=https://github.com/humanprotocol/human-protocol
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createMock } from '@golevelup/ts-jest';
import { NETWORKS, StatisticsClient } from '@human-protocol/sdk';
import { NETWORKS, StatisticsUtils } from '@human-protocol/sdk';
import { HttpService } from '@nestjs/axios';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { ConfigService } from '@nestjs/config';
Expand All @@ -10,11 +10,6 @@ import { NetworkConfigService } from '../../common/config/network-config.service
import { DevelopmentChainId } from '../../common/constants';
import { NetworksService } from './networks.service';

jest.mock('@human-protocol/sdk', () => ({
...jest.requireActual('@human-protocol/sdk'),
StatisticsClient: jest.fn(),
}));

describe('NetworksService', () => {
let networksService: NetworksService;
let cacheManager: Cache;
Expand Down Expand Up @@ -53,6 +48,10 @@ describe('NetworksService', () => {
cacheManager = module.get<Cache>(CACHE_MANAGER);
});

afterEach(() => {
jest.restoreAllMocks();
});

it('should regenerate network list when cache TTL expires', async () => {
const mockNetworkList = [
DevelopmentChainId.SEPOLIA,
Expand All @@ -64,15 +63,18 @@ describe('NetworksService', () => {
jest.spyOn(cacheManager, 'get').mockResolvedValue(null);
jest.spyOn(cacheManager, 'set').mockResolvedValue(undefined);

const mockStatisticsClient = {
getHMTDailyData: jest
.fn()
.mockResolvedValue([{ totalTransactionCount: 7 }]),
getEscrowStatistics: jest.fn().mockResolvedValue({ totalEscrows: 1 }),
};
(StatisticsClient as jest.Mock).mockImplementation(
() => mockStatisticsClient,
);
jest.spyOn(StatisticsUtils, 'getHMTDailyData').mockResolvedValue([
{
timestamp: 0,
totalTransactionCount: 7,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
]);
jest
.spyOn(StatisticsUtils, 'getEscrowStatistics')
.mockResolvedValue({ totalEscrows: 1, dailyEscrowsData: [] });

// First call should populate cache
const firstCallResult = await networksService.getOperatingNetworks();
Expand Down Expand Up @@ -113,18 +115,25 @@ describe('NetworksService', () => {

it('should fetch and filter available networks correctly', async () => {
jest.spyOn(cacheManager, 'get').mockResolvedValue(null);
const mockStatisticsClient = {
getHMTDailyData: jest
.fn()
.mockResolvedValue([
{ totalTransactionCount: 4 },
{ totalTransactionCount: 3 },
]),
getEscrowStatistics: jest.fn().mockResolvedValue({ totalEscrows: 1 }),
};
(StatisticsClient as jest.Mock).mockImplementation(
() => mockStatisticsClient,
);
jest.spyOn(StatisticsUtils, 'getHMTDailyData').mockResolvedValue([
{
timestamp: 0,
totalTransactionCount: 4,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
{
timestamp: 0,
totalTransactionCount: 3,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
]);
jest
.spyOn(StatisticsUtils, 'getEscrowStatistics')
.mockResolvedValue({ totalEscrows: 1, dailyEscrowsData: [] });

const result = await networksService.getOperatingNetworks();
expect(result).toEqual(
Expand All @@ -143,15 +152,18 @@ describe('NetworksService', () => {

it('should exclude networks without sufficient HMT transfers', async () => {
jest.spyOn(cacheManager, 'get').mockResolvedValue(null);
const mockStatisticsClient = {
getHMTDailyData: jest
.fn()
.mockResolvedValue([{ totalTransactionCount: 2 }]),
getEscrowStatistics: jest.fn().mockResolvedValue({ totalEscrows: 1 }),
};
(StatisticsClient as jest.Mock).mockImplementation(
() => mockStatisticsClient,
);
jest.spyOn(StatisticsUtils, 'getHMTDailyData').mockResolvedValue([
{
timestamp: 0,
totalTransactionCount: 2,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
]);
jest
.spyOn(StatisticsUtils, 'getEscrowStatistics')
.mockResolvedValue({ totalEscrows: 1, dailyEscrowsData: [] });

const result = await networksService.getOperatingNetworks();
expect(result).toEqual([]);
Expand All @@ -163,18 +175,25 @@ describe('NetworksService', () => {
const originalNetworkConfig = NETWORKS[DevelopmentChainId.SEPOLIA];
NETWORKS[DevelopmentChainId.SEPOLIA] = undefined;

const mockStatisticsClient = {
getHMTDailyData: jest
.fn()
.mockResolvedValue([
{ totalTransactionCount: 3 },
{ totalTransactionCount: 3 },
]),
getEscrowStatistics: jest.fn().mockResolvedValue({ totalEscrows: 1 }),
};
(StatisticsClient as jest.Mock).mockImplementation(
() => mockStatisticsClient,
);
jest.spyOn(StatisticsUtils, 'getHMTDailyData').mockResolvedValue([
{
timestamp: 0,
totalTransactionCount: 3,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
{
timestamp: 0,
totalTransactionCount: 3,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
]);
jest
.spyOn(StatisticsUtils, 'getEscrowStatistics')
.mockResolvedValue({ totalEscrows: 1, dailyEscrowsData: [] });

const result = await networksService.getOperatingNetworks();

Expand All @@ -186,36 +205,38 @@ describe('NetworksService', () => {

it('should handle errors in getHMTDailyData gracefully', async () => {
jest.spyOn(cacheManager, 'get').mockResolvedValue(null);
const mockStatisticsClient = {
getHMTDailyData: jest
.fn()
.mockRejectedValue(new Error('Failed to fetch HMT data')),
getEscrowStatistics: jest.fn().mockResolvedValue({ totalEscrows: 1 }),
};
(StatisticsClient as jest.Mock).mockImplementation(
() => mockStatisticsClient,
);
jest
.spyOn(StatisticsUtils, 'getHMTDailyData')
.mockRejectedValue(new Error('Failed to fetch HMT data'));
jest
.spyOn(StatisticsUtils, 'getEscrowStatistics')
.mockResolvedValue({ totalEscrows: 1, dailyEscrowsData: [] });

const result = await networksService.getOperatingNetworks();
expect(result).toEqual([]);
});

it('should handle errors in getEscrowStatistics gracefully', async () => {
jest.spyOn(cacheManager, 'get').mockResolvedValue(null);
const mockStatisticsClient = {
getHMTDailyData: jest
.fn()
.mockResolvedValue([
{ totalTransactionCount: 3 },
{ totalTransactionCount: 2 },
]),
getEscrowStatistics: jest
.fn()
.mockRejectedValue(new Error('Failed to fetch escrow stats')),
};
(StatisticsClient as jest.Mock).mockImplementation(
() => mockStatisticsClient,
);
jest.spyOn(StatisticsUtils, 'getHMTDailyData').mockResolvedValue([
{
timestamp: 0,
totalTransactionCount: 3,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
{
timestamp: 0,
totalTransactionCount: 2,
totalTransactionAmount: 0n,
dailyUniqueSenders: 0,
dailyUniqueReceivers: 0,
},
]);
jest
.spyOn(StatisticsUtils, 'getEscrowStatistics')
.mockRejectedValue(new Error('Failed to fetch escrow stats'));

const result = await networksService.getOperatingNetworks();
expect(result).toEqual([]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { NETWORKS, StatisticsClient } from '@human-protocol/sdk';
import { NETWORKS, StatisticsUtils } from '@human-protocol/sdk';
import { Cache, CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable } from '@nestjs/common';

Expand Down Expand Up @@ -46,13 +46,12 @@ export class NetworksService {
const networkConfig = NETWORKS[network.chainId];
if (!networkConfig) continue;

const statisticsClient = new StatisticsClient(networkConfig);
try {
const [hmtData, escrowStats] = await Promise.all([
statisticsClient.getHMTDailyData({
StatisticsUtils.getHMTDailyData(networkConfig, {
from: new Date(Math.floor(filterDate.getTime() / 1000) * 1000),
}),
statisticsClient.getEscrowStatistics({
StatisticsUtils.getEscrowStatistics(networkConfig, {
from: new Date(Math.floor(oneMonthAgo.getTime() / 1000) * 1000),
}),
]);
Expand Down
23 changes: 13 additions & 10 deletions packages/apps/dashboard/server/src/modules/stats/stats.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IDailyHMT, NETWORKS, StatisticsClient } from '@human-protocol/sdk';
import { IDailyHMT, NETWORKS, StatisticsUtils } from '@human-protocol/sdk';
import { HttpService } from '@nestjs/axios';
import { Cache, CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
Expand Down Expand Up @@ -244,8 +244,9 @@ export class StatsService implements OnModuleInit {
const operatingNetworks =
await this.networksService.getOperatingNetworks();
for (const network of operatingNetworks) {
const statisticsClient = new StatisticsClient(NETWORKS[network]);
const generalStats = await statisticsClient.getHMTStatistics();
const generalStats = await StatisticsUtils.getHMTStatistics(
NETWORKS[network],
);
aggregatedStats.totalHolders += generalStats.totalHolders;
aggregatedStats.totalTransactions += generalStats.totalTransferCount;
}
Expand Down Expand Up @@ -295,17 +296,19 @@ export class StatsService implements OnModuleInit {
// Fetch daily data for each network
await Promise.all(
operatingNetworks.map(async (network) => {
const statisticsClient = new StatisticsClient(NETWORKS[network]);
let skip = 0;
let fetchedRecords: IDailyHMT[] = [];

do {
fetchedRecords = await statisticsClient.getHMTDailyData({
from,
to,
first: 1000, // Max subgraph query size
skip,
});
fetchedRecords = await StatisticsUtils.getHMTDailyData(
NETWORKS[network],
{
from,
to,
first: 1000, // Max subgraph query size
skip,
},
);

for (const record of fetchedRecords) {
const dailyCacheKey = `${HMT_PREFIX}${
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,43 @@ import { Box, Button, Grid, TextField, Typography } from '@mui/material';
import { useState } from 'react';
import { useParams } from 'react-router-dom';
import { useSnackbar } from '../../providers/SnackProvider';
import { useWalletClient } from 'wagmi';
import { useAccount, useWalletClient } from 'wagmi';
import * as jobService from '../../services/job';

const SolutionForm: React.FC = () => {
const { assignmentId } = useParams<{ assignmentId: string }>();

const { data: signer } = useWalletClient();
const { address, chainId, connector, isConnected } = useAccount();
const { data: signer } = useWalletClient({
account: address,
chainId,
connector,
query: {
enabled: isConnected && !!address && !!connector,
},
});
const [solution, setSolution] = useState('');
const { showError, openSnackbar } = useSnackbar();

type SnackbarApi = {
openSnackbar: (
message: string,
severity?: 'success' | 'error' | 'info' | 'warning',
) => void;
showError: (error: unknown) => void;
};

const { showError, openSnackbar } = useSnackbar() as SnackbarApi;

const handleSubmit = async () => {
if (!signer) {
openSnackbar('Please connect your wallet first', 'error');
return;
}

if (!assignmentId) {
openSnackbar('Missing assignment id', 'error');
return;
}
const message = {
solution,
assignment_id: assignmentId,
Expand Down Expand Up @@ -69,7 +95,11 @@ const SolutionForm: React.FC = () => {
sx={{ mb: 3, width: '300px' }}
/>
<br />
<Button variant="contained" onClick={handleSubmit}>
<Button
variant="contained"
onClick={handleSubmit}
disabled={!signer || !assignmentId || !solution}
>
Submit
</Button>
</Box>
Expand Down
2 changes: 1 addition & 1 deletion packages/apps/fortune/exchange-oracle/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ $ yarn migration:show

## 📚 Documentation

For detailed information about the Exchange Oracle, please refer to the [Human Protocol Tech Docs](https://human-protocol.gitbook.io/hub/human-tech-docs/architecture/components/exchange-oracle).
For detailed information about the Exchange Oracle, please refer to the [Human Protocol Tech Docs](https://docs.humanprotocol.org/architecture/exchange_oracle/overview/).

## 📝 License

Expand Down
Loading
Loading