Skip to content

Commit 9c62cc3

Browse files
Merge pull request #377 from HathorNetwork/release-candidate
2 parents c2d61fe + d6a18dc commit 9c62cc3

File tree

7 files changed

+156
-199
lines changed

7 files changed

+156
-199
lines changed

db/seeders/20250416132150-add-htr-token.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
module.exports = {
44
up: async (queryInterface) => {
5+
// Check if HTR token already exists
6+
const [existing] = await queryInterface.sequelize.query(
7+
"SELECT id FROM token WHERE id = '00'"
8+
);
9+
10+
if (existing.length > 0) {
11+
console.log('HTR token already exists, skipping.');
12+
return;
13+
}
14+
515
// Count unique transactions for HTR
616
const [results] = await queryInterface.sequelize.query(
717
"SELECT COUNT(DISTINCT tx_id) AS count FROM tx_output WHERE token_id = '00'"
@@ -14,6 +24,7 @@ module.exports = {
1424
name: 'Hathor',
1525
symbol: 'HTR',
1626
transactions: htrTxCount,
27+
version: 0, // TokenVersion.NATIVE
1728
}]);
1829
},
1930

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hathor-wallet-service",
3-
"version": "1.11.2",
3+
"version": "1.12.0",
44
"workspaces": [
55
"packages/common",
66
"packages/daemon",

packages/daemon/__tests__/services/services.test.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1675,12 +1675,42 @@ describe('checkForMissedEvents', () => {
16751675
);
16761676
});
16771677

1678-
it('should throw error when context has no event', async () => {
1678+
it('should throw error when context has no event and no initialEventId', async () => {
16791679
const context = {};
16801680

16811681
await expect(checkForMissedEvents(context as any))
16821682
.rejects
1683-
.toThrow('No event in context when checking for missed events');
1683+
.toThrow('No event in context and no initialEventId when checking for missed events');
1684+
});
1685+
1686+
it('should use initialEventId when context.event is null', async () => {
1687+
const mockResponse = {
1688+
status: 200,
1689+
data: {
1690+
events: [],
1691+
latest_event_id: 25717039,
1692+
},
1693+
};
1694+
1695+
(axios.get as jest.Mock).mockResolvedValue(mockResponse);
1696+
1697+
const context = {
1698+
event: null,
1699+
initialEventId: 25717039,
1700+
};
1701+
1702+
const result = await checkForMissedEvents(context as any);
1703+
1704+
expect(result.hasNewEvents).toBe(false);
1705+
expect(axios.get).toHaveBeenCalledWith(
1706+
expect.stringContaining('/event'),
1707+
expect.objectContaining({
1708+
params: {
1709+
last_ack_event_id: 25717039,
1710+
size: 1,
1711+
},
1712+
}),
1713+
);
16841714
});
16851715

16861716
it('should handle API response with non-array events field', async () => {

packages/daemon/src/services/index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,11 +1078,11 @@ export const handleTokenCreated = async (context: Context) => {
10781078
* This is used to detect if we lost an event due to network packet loss
10791079
*/
10801080
export const checkForMissedEvents = async (context: Context): Promise<{ hasNewEvents: boolean; events: any[] }> => {
1081-
if (!context.event) {
1082-
throw new Error('No event in context when checking for missed events');
1083-
}
1081+
const lastAckEventId = context.event?.event.id ?? context.initialEventId;
10841082

1085-
const lastAckEventId = context.event.event.id;
1083+
if (lastAckEventId === null || lastAckEventId === undefined) {
1084+
throw new Error('No event in context and no initialEventId when checking for missed events');
1085+
}
10861086
const fullnodeUrl = getFullnodeHttpUrl();
10871087

10881088
logger.debug(`Checking for missed events after event ID ${lastAckEventId}`);

packages/wallet-service/src/api/tokens.ts

Lines changed: 42 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,15 @@ import 'source-map-support/register';
33
import { walletIdProxyHandler } from '@src/commons';
44
import {
55
getWalletTokens,
6-
getTotalSupply,
7-
getTotalTransactions,
8-
getTokenInformation,
9-
getAuthorityUtxo,
106
} from '@src/db';
117
import {
12-
TokenInfo,
13-
} from '@src/types';
14-
import { getDbConnection } from '@src/utils';
8+
closeDbConnection,
9+
getDbConnection,
10+
} from '@src/utils';
1511
import { ApiError } from '@src/api/errors';
1612
import { closeDbAndGetError, warmupMiddleware, txIdJoiValidator } from '@src/api/utils';
13+
import fullnode from '@src/fullnode';
1714
import Joi from 'joi';
18-
import { bigIntUtils, constants } from '@hathor/wallet-lib';
1915
import middy from '@middy/core';
2016
import cors from '@middy/http-cors';
2117
import errorHandler from '@src/api/middlewares/errorHandler';
@@ -49,8 +45,9 @@ const getTokenDetailsParamsSchema = Joi.object({
4945
* Get token details
5046
*
5147
* This lambda is called by API Gateway on GET /wallet/tokens/:token_id/details
48+
* It proxies the request to the fullnode's thin_wallet/token API
5249
*/
53-
export const getTokenDetails = middy(walletIdProxyHandler(async (walletId, event) => {
50+
export const getTokenDetails = middy(walletIdProxyHandler(async (_walletId, event) => {
5451
const params = event.pathParameters || {};
5552

5653
const { value, error } = getTokenDetailsParamsSchema.validate(params, {
@@ -68,51 +65,44 @@ export const getTokenDetails = middy(walletIdProxyHandler(async (walletId, event
6865
}
6966

7067
const tokenId = value.token_id;
71-
const tokenInfo: TokenInfo = await getTokenInformation(mysql, tokenId);
7268

73-
if (tokenId === constants.NATIVE_TOKEN_UID) {
74-
const details = [{
75-
message: 'Invalid tokenId',
76-
}];
77-
78-
return closeDbAndGetError(mysql, ApiError.INVALID_PAYLOAD, { details });
79-
}
80-
81-
if (!tokenInfo) {
82-
const details = [{
83-
message: 'Token not found',
84-
}];
85-
86-
return closeDbAndGetError(mysql, ApiError.TOKEN_NOT_FOUND, { details });
87-
}
88-
89-
const [
90-
totalSupply,
91-
totalTransactions,
92-
meltAuthority,
93-
mintAuthority,
94-
] = await Promise.all([
95-
getTotalSupply(mysql, tokenId),
96-
getTotalTransactions(mysql, tokenId),
97-
getAuthorityUtxo(mysql, tokenId, Number(constants.TOKEN_MELT_MASK)),
98-
getAuthorityUtxo(mysql, tokenId, Number(constants.TOKEN_MINT_MASK)),
99-
]);
100-
101-
return {
102-
statusCode: 200,
103-
body: bigIntUtils.JSONBigInt.stringify({
104-
success: true,
105-
details: {
106-
tokenInfo,
107-
totalSupply,
108-
totalTransactions,
109-
authorities: {
110-
mint: mintAuthority !== null,
111-
melt: meltAuthority !== null,
69+
try {
70+
const data = await fullnode.getTokenDetails(tokenId);
71+
72+
if (!data?.success) {
73+
return {
74+
statusCode: 404,
75+
body: JSON.stringify({
76+
success: false,
77+
error: ApiError.TOKEN_NOT_FOUND,
78+
details: [{ message: 'Token not found' }],
79+
}),
80+
};
81+
}
82+
83+
return {
84+
statusCode: 200,
85+
body: JSON.stringify({
86+
success: true,
87+
details: {
88+
tokenInfo: {
89+
id: tokenId,
90+
name: data.name,
91+
symbol: data.symbol,
92+
version: data.version,
93+
},
94+
totalSupply: data.total,
95+
totalTransactions: data.transactions_count,
96+
authorities: {
97+
mint: data.can_mint,
98+
melt: data.can_melt,
99+
},
112100
},
113-
},
114-
}),
115-
};
101+
}),
102+
};
103+
} finally {
104+
await closeDbConnection(mysql);
105+
}
116106
})).use(cors())
117107
.use(warmupMiddleware())
118108
.use(errorHandler());

packages/wallet-service/src/fullnode.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ export const create = (baseURL = BASE_URL) => {
118118
return response.data;
119119
}
120120

121+
const getTokenDetails = async (tokenId: string) => {
122+
const response = await api.get('thin_wallet/token', {
123+
data: null,
124+
params: { id: tokenId },
125+
headers: { 'content-type': 'application/json' },
126+
});
127+
128+
return response.data;
129+
}
130+
121131
return {
122132
api, // exported so we can mock it on the tests
123133
version,
@@ -129,6 +139,7 @@ export const create = (baseURL = BASE_URL) => {
129139
getNCState,
130140
getNCHistory,
131141
getNCBlueprintInfo,
142+
getTokenDetails,
132143
};
133144
};
134145

0 commit comments

Comments
 (0)