Skip to content

Commit 5f83d3e

Browse files
refactor: added a "common" package to share code between packages (#151)
* chore: added common package * chore: using wallet-lib from daemon resolution * chore: installed shared dependencies on root project, using peerDependencies * refactor: using addAlert method from common utils * chore: updated package.json with missing deps * refactor: using types from commons on wallet-service * chore: re-added sequelize to root * refactor: removed isNftAutoReviewEnabled from services * tests: mocked assertEnv * tests: mocked assertEnv on integration tests * chore: removed nft utils * refactor: removed old addAlerts from the wallet-service package * chore: wallet-lib is now a peerDependency in wallet-service package * refactor: logger is now a required param in addAlert, refactored all methods in wallet-service package * docs: added missing hathor header * refactor: invalid type for metadata on addAlert * tests: passing mocked logger * chore: updated gitignore to ignore env files * chore: revert eslint package updates * refactor: using types from commons on wallet-service * refactor: removed unused commented line * chore: missing package in daemon * refactor: using transaction type from common * refactor: bitcoinjs is not a shared dep * chore: added a comment explaining that logger is a param temporarily * refactor: removed default from metadata * chore: lint fixes and package ordering * feat: call onNewNftEvent when a new NFT tx is received (#150) * feat: added nft utils * tests: added tests for common utils * chore: added common module to CI * refactor: moved used types to common package * tests: removed nft utils * tests: fixed nft tests on txProcessor * tests: mocking network on getconfig * tests: fixed nft tests on txProcessor * refactor: passing logger to invoke nft handler * refactor: no need to ignore ts * chore: removed jest script, instead using only test * chore: added hathor header * refactor: using common utils on txProcessor * tests: nft utils using old syntax * tests: skipped txProcessor tests * tests: fixed txProcessor tests * refactor: using isAuthority from common utils * refactor: using isAuthority from common types * refactor: using assertEnvVariablesExistance from common project * refactor: getting CREATE_NFT_MAX_RETRIES from env * docs: updated docstrings on nft utils * chore: removed events/nftCreationTx.ts * refactor: invalid import locations * refactor: remove unused lambdas (#155) * tests: fixed nft tests on txProcessor * refactor: removed all methods related to the old wallet-service txProcessor * tests: fixed failing test * fix: serverless failing (#162) * refactor: logger is now a required param in addAlert, refactored all methods in wallet-service package * chore: changed module resolution and several package locks * chore: added common library to externals whitelist and whitelisted it in tsloader * chore: wallet-service common package moved from direct path to workspace * chore: added common as a peer dependency and restored peer dependencies * chore: removed peer dependencies as they were not working with serverless-monorepo * chore: added comment on hoisting limits * chore: added comment explaining externals in webpack
1 parent ea7f2b7 commit 5f83d3e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2906
-3933
lines changed

.codebuild/buildspec.yml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ env:
1414
CONFIRM_FIRST_ADDRESS: true
1515
VOIDED_TX_OFFSET: 20
1616
TX_HISTORY_MAX_COUNT: 50
17+
CREATE_NFT_MAX_RETRIES: 3
1718
dev_DEFAULT_SERVER: "https://wallet-service.private-nodes.testnet.hathor.network/v1a/"
1819
dev_WS_DOMAIN: "ws.dev.wallet-service.testnet.hathor.network"
1920
dev_NETWORK: "testnet"

.github/workflows/main.yml

+5-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
nix_path: nixpkgs=channel:nixos-unstable
4141
extra_nix_config: |
4242
experimental-features = nix-command flakes
43-
43+
4444
- name: Cache Nix
4545
uses: DeterminateSystems/magic-nix-cache-action@v2
4646

@@ -59,6 +59,10 @@ jobs:
5959
CI_DB_HOST: 127.0.0.1
6060
CI_DB_PORT: 3306
6161

62+
- name: Run tests on the common modules project
63+
run: |
64+
nix develop . -c yarn workspace @wallet-service/common run test
65+
6266
- name: Run tests on the daemon
6367
run: |
6468
nix develop . -c yarn workspace sync-daemon run test

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ dist
77
coverage/
88
packages/daemon/dist
99
packages/daemon/node_modules
10+
packages/common/node_modules
1011
packages/wallet-service/node_modules
1112
packages/wallet-service/.serverless
1213
packages/wallet-service/.webpack
1314
packages/wallet-service/.env*
15+
packages/wallet-service/.warmup
1416
.yarn/
17+
.env.*

.yarnrc.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ compressionLevel: mixed
22

33
enableGlobalCache: false
44

5-
nmHoistingLimits: dependencies
5+
# Without this setting, the common package is hoisted in the root node_modules, causing the serverless-monorepo plugin to fail
6+
nmHoistingLimits: workspaces
67

78
nodeLinker: node-modules

package.json

+27-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "hathor-wallet-service",
33
"version": "1.5.0",
44
"workspaces": [
5+
"packages/common",
56
"packages/daemon",
67
"packages/wallet-service"
78
],
@@ -11,14 +12,34 @@
1112
"nohoist": [
1213
"**"
1314
],
14-
"repository": "[email protected]:HathorNetwork/hathor-wallet-service-sync_daemon.git",
15+
"repository": "[email protected]:HathorNetwork/hathor-wallet-service.git",
1516
"author": "André Abadesso <[email protected]>",
1617
"private": true,
1718
"devDependencies": {
18-
"dotenv": "^16.3.1",
19-
"mysql2": "^3.6.1",
20-
"sequelize": "^6.33.0",
21-
"sequelize-cli": "^6.6.1"
19+
"@types/jest": "^29.5.12",
20+
"@typescript-eslint/eslint-plugin": "^7.4.0",
21+
"@typescript-eslint/parser": "^7.4.0",
22+
"dotenv": "^16.4.5",
23+
"eslint": "^8.57.0",
24+
"eslint-config-airbnb-base": "^15.0.0",
25+
"eslint-plugin-import": "^2.29.1",
26+
"eslint-plugin-jest": "^27.9.0",
27+
"mysql2": "^3.9.3",
28+
"sequelize": "^6.37.2",
29+
"sequelize-cli": "^6.6.2"
2230
},
23-
"packageManager": "[email protected]"
31+
"packageManager": "[email protected]",
32+
"dependencies": {
33+
"@aws-sdk/client-apigatewaymanagementapi": "3.540.0",
34+
"@aws-sdk/client-lambda": "3.540.0",
35+
"@aws-sdk/client-sqs": "3.540.0",
36+
"@hathor/wallet-lib": "0.39.0",
37+
"@wallet-service/common": "1.5.0",
38+
"bip32": "^4.0.0",
39+
"bitcoinjs-lib": "^6.1.5",
40+
"bitcoinjs-message": "^2.2.0",
41+
"jest": "^29.7.0",
42+
"tiny-secp256k1": "^2.2.3",
43+
"winston": "3.13.0"
44+
}
2445
}

packages/common/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Common utils for the wallet-service

packages/wallet-service/events/nftCreationTx.ts renamed to packages/common/__tests__/events/nftCreationTx.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
/* eslint-disable @typescript-eslint/no-empty-function */
1313

1414
import { Context } from 'aws-lambda';
15-
import { Transaction } from '@src/types';
15+
import { Transaction, TxOutput } from '../../src/types';
1616

1717
/**
1818
* A sample transaction for a NFT creation, as obtained by a wallet's history methods
@@ -149,11 +149,12 @@ export function getTransaction(): Transaction {
149149
spent_by: o.spent_by,
150150
token_data: o.token_data,
151151
locked: false,
152-
})),
152+
})) as TxOutput[],
153153
height: 8,
154154
token_name: nftCreationTx.token_name,
155155
token_symbol: nftCreationTx.token_symbol,
156156
};
157+
157158
return result;
158159
}
159160

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export const mockedAddAlert = jest.fn();
2+
export default jest.mock('@src/utils/alerting.utils', () => ({
3+
addAlert: mockedAddAlert.mockReturnValue(Promise.resolve()),
4+
}));

packages/wallet-service/tests/utils/nft.utils.test.ts renamed to packages/common/__tests__/utils/nft.utils.test.ts

+47-22
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
1+
// @ts-ignore: Using old wallet-lib version, no types exported
12
import hathorLib from '@hathor/wallet-lib';
2-
import { mockedAddAlert } from '@tests/utils/alerting.utils.mock';
3+
import { mockedAddAlert } from './alerting.utils.mock';
34
import { Severity } from '@src/types';
4-
import { MAX_METADATA_UPDATE_RETRIES, NftUtils } from '@src/utils/nft.utils';
5-
import { getHandlerContext, getTransaction } from '@events/nftCreationTx';
5+
import { NftUtils } from '@src/utils/nft.utils';
6+
import { getHandlerContext, getTransaction } from '../events/nftCreationTx';
67
import {
78
LambdaClient as LambdaClientMock,
89
InvokeCommandOutput,
910
} from '@aws-sdk/client-lambda';
11+
import { Logger } from 'winston';
12+
13+
jest.mock('winston', () => {
14+
class FakeLogger {
15+
warn() {
16+
return jest.fn();
17+
}
18+
error() {
19+
return jest.fn();
20+
}
21+
info() {
22+
return jest.fn();
23+
}
24+
};
25+
26+
return {
27+
Logger: FakeLogger,
28+
}
29+
});
1030

1131
jest.mock('@aws-sdk/client-lambda', () => {
1232
const mLambda = { send: jest.fn() };
@@ -17,19 +37,23 @@ jest.mock('@aws-sdk/client-lambda', () => {
1737
};
1838
});
1939

40+
const network = new hathorLib.Network('testnet');
41+
const logger = new Logger();
42+
2043
describe('shouldInvokeNftHandlerForTx', () => {
2144
it('should return false for a NFT transaction if the feature is disabled', () => {
2245
expect.hasAssertions();
2346

2447
// Preparation
2548
const tx = getTransaction();
26-
const isNftTransaction = NftUtils.isTransactionNFTCreation(tx);
49+
const isNftTransaction = NftUtils.isTransactionNFTCreation(tx, network, logger);
2750
expect(isNftTransaction).toStrictEqual(true);
2851

2952
expect(process.env.NFT_AUTO_REVIEW_ENABLED).not.toStrictEqual('true');
3053

3154
// Execution
32-
const result = NftUtils.shouldInvokeNftHandlerForTx(tx);
55+
// @ts-ignore
56+
const result = NftUtils.shouldInvokeNftHandlerForTx(tx, network, logger);
3357

3458
// Assertion
3559
expect(result).toBe(false);
@@ -40,14 +64,14 @@ describe('shouldInvokeNftHandlerForTx', () => {
4064

4165
// Preparation
4266
const tx = getTransaction();
43-
const isNftTransaction = NftUtils.isTransactionNFTCreation(tx);
67+
const isNftTransaction = NftUtils.isTransactionNFTCreation(tx, network, logger);
4468
expect(isNftTransaction).toStrictEqual(true);
4569

4670
const oldValue = process.env.NFT_AUTO_REVIEW_ENABLED;
4771
process.env.NFT_AUTO_REVIEW_ENABLED = 'true';
4872

4973
// Execution
50-
const result = NftUtils.shouldInvokeNftHandlerForTx(tx);
74+
const result = NftUtils.shouldInvokeNftHandlerForTx(tx, network, logger);
5175

5276
// Assertion
5377
expect(result).toBe(true);
@@ -70,21 +94,21 @@ describe('isTransactionNFTCreation', () => {
7094
// Incorrect version
7195
tx = getTransaction();
7296
tx.version = hathorLib.constants.DEFAULT_TX_VERSION;
73-
result = NftUtils.isTransactionNFTCreation(tx);
97+
result = NftUtils.isTransactionNFTCreation(tx, network, logger);
7498
expect(result).toBe(false);
7599
expect(spyCreateTx).not.toHaveBeenCalled();
76100

77101
// Missing name
78102
tx = getTransaction();
79103
tx.token_name = undefined;
80-
result = NftUtils.isTransactionNFTCreation(tx);
104+
result = NftUtils.isTransactionNFTCreation(tx, network, logger);
81105
expect(result).toBe(false);
82106
expect(spyCreateTx).not.toHaveBeenCalled();
83107

84108
// Missing symbol
85109
tx = getTransaction();
86110
tx.token_symbol = undefined;
87-
result = NftUtils.isTransactionNFTCreation(tx);
111+
result = NftUtils.isTransactionNFTCreation(tx, network, logger);
88112
expect(result).toBe(false);
89113
expect(spyCreateTx).not.toHaveBeenCalled();
90114

@@ -101,7 +125,7 @@ describe('isTransactionNFTCreation', () => {
101125

102126
// Validation
103127
const tx = getTransaction();
104-
const result = NftUtils.isTransactionNFTCreation(tx);
128+
const result = NftUtils.isTransactionNFTCreation(tx, network, logger);
105129
expect(result).toBe(true);
106130

107131
// Reverting mocks
@@ -113,7 +137,7 @@ describe('isTransactionNFTCreation', () => {
113137

114138
// Validation
115139
const tx = getTransaction();
116-
const result = NftUtils.isTransactionNFTCreation(tx);
140+
const result = NftUtils.isTransactionNFTCreation(tx, network, logger);
117141
expect(result).toBe(true);
118142
});
119143

@@ -128,7 +152,7 @@ describe('isTransactionNFTCreation', () => {
128152

129153
// Validation
130154
const tx = getTransaction();
131-
const result = NftUtils.isTransactionNFTCreation(tx);
155+
const result = NftUtils.isTransactionNFTCreation(tx, network, logger);
132156
expect(result).toBe(false);
133157

134158
// Reverting mocks
@@ -154,11 +178,11 @@ describe('createOrUpdateNftMetadata', () => {
154178
const expectedUpdateResponse = { updated: 'ok' };
155179

156180
spyUpdateMetadata.mockImplementation(async () => expectedUpdateResponse);
157-
const result = await NftUtils.createOrUpdateNftMetadata('sampleUid');
181+
const result = await NftUtils.createOrUpdateNftMetadata('sampleUid', 5, logger);
158182

159183
expect(spyUpdateMetadata).toHaveBeenCalledTimes(1);
160184

161-
expect(spyUpdateMetadata).toHaveBeenCalledWith('sampleUid', expectedUpdateRequest);
185+
expect(spyUpdateMetadata).toHaveBeenCalledWith('sampleUid', expectedUpdateRequest, 5, logger);
162186
expect(result).toBeUndefined(); // The method returns void
163187
});
164188
});
@@ -181,7 +205,7 @@ describe('_updateMetadata', () => {
181205
const oldStage = process.env.STAGE;
182206
process.env.STAGE = 'dev'; // Testing all code branches, including the developer ones, for increased coverage
183207

184-
const result = await NftUtils._updateMetadata('sampleUid', { sampleData: 'fake' });
208+
const result = await NftUtils._updateMetadata('sampleUid', { sampleData: 'fake' }, 5, logger);
185209
expect(result).toStrictEqual(expectedLambdaResponse);
186210
process.env.STAGE = oldStage;
187211
});
@@ -197,7 +221,7 @@ describe('_updateMetadata', () => {
197221
};
198222
const mLambdaClient = new LambdaClientMock({});
199223
(mLambdaClient.send as jest.Mocked<any>).mockImplementation(async () => {
200-
if (failureCount < MAX_METADATA_UPDATE_RETRIES - 1) {
224+
if (failureCount < 4) {
201225
++failureCount;
202226
return {
203227
StatusCode: 500,
@@ -207,7 +231,7 @@ describe('_updateMetadata', () => {
207231
return expectedLambdaResponse;
208232
});
209233

210-
const result = await NftUtils._updateMetadata('sampleUid', { sampleData: 'fake' });
234+
const result = await NftUtils._updateMetadata('sampleUid', { sampleData: 'fake' }, 5, logger);
211235
expect(result).toStrictEqual(expectedLambdaResponse);
212236
});
213237

@@ -218,7 +242,7 @@ describe('_updateMetadata', () => {
218242
let failureCount = 0;
219243
const mLambdaClient = new LambdaClientMock({});
220244
(mLambdaClient.send as jest.Mocked<any>).mockImplementation(() => {
221-
if (failureCount < MAX_METADATA_UPDATE_RETRIES) {
245+
if (failureCount < 5) {
222246
++failureCount;
223247
return {
224248
StatusCode: 500,
@@ -232,7 +256,7 @@ describe('_updateMetadata', () => {
232256
});
233257

234258
// eslint-disable-next-line jest/valid-expect
235-
expect(NftUtils._updateMetadata('sampleUid', { sampleData: 'fake' }))
259+
expect(NftUtils._updateMetadata('sampleUid', { sampleData: 'fake' }, network, logger))
236260
.rejects.toThrow(new Error('Metadata update failed for tx_id: sampleUid.'));
237261
});
238262
});
@@ -249,7 +273,7 @@ describe('invokeNftHandlerLambda', () => {
249273
const mLambdaClient = new LambdaClientMock({});
250274
(mLambdaClient.send as jest.Mocked<any>).mockImplementationOnce(async () => expectedLambdaResponse);
251275

252-
await expect(NftUtils.invokeNftHandlerLambda('sampleUid')).resolves.toBeUndefined();
276+
await expect(NftUtils.invokeNftHandlerLambda('sampleUid', 'local', logger)).resolves.toBeUndefined();
253277
});
254278

255279
it('should throw when payload response status is invalid', async () => {
@@ -263,14 +287,15 @@ describe('invokeNftHandlerLambda', () => {
263287
};
264288
(mLambdaClient.send as jest.Mocked<any>).mockImplementation(() => expectedLambdaResponse);
265289

266-
await expect(NftUtils.invokeNftHandlerLambda('sampleUid'))
290+
await expect(NftUtils.invokeNftHandlerLambda('sampleUid', 'local', logger))
267291
.rejects.toThrow(new Error('onNewNftEvent lambda invoke failed for tx: sampleUid'));
268292

269293
expect(mockedAddAlert).toHaveBeenCalledWith(
270294
'Error on NFTHandler lambda',
271295
'Erroed on invokeNftHandlerLambda invocation',
272296
Severity.MINOR,
273297
{ TxId: 'sampleUid' },
298+
logger,
274299
);
275300
});
276301
});

packages/common/jest.config.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module.exports = {
2+
roots: ["<rootDir>/__tests__"],
3+
testRegex: ".*\\.test\\.ts$",
4+
moduleNameMapper: {
5+
'^@src/(.*)$': '<rootDir>/src/$1',
6+
'^@tests/(.*)$': '<rootDir>/__tests__/$1',
7+
'^@events/(.*)$': '<rootDir>/__tests__/events/$1',
8+
},
9+
transform: {
10+
"^.+\\.ts$": ["ts-jest", {
11+
tsconfig: "./tsconfig.json",
12+
babelConfig: {
13+
sourceMaps: true,
14+
}
15+
}]
16+
},
17+
moduleFileExtensions: ["ts", "js", "json", "node"]
18+
};

packages/common/package.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "@wallet-service/common",
3+
"version": "1.5.0",
4+
"packageManager": "[email protected]",
5+
"scripts": {
6+
"test": "jest --runInBand --collectCoverage --detectOpenHandles --forceExit"
7+
},
8+
"peerDependencies": {
9+
"@aws-sdk/client-lambda": "3.540.0",
10+
"@hathor/wallet-lib": "0.39.0",
11+
"winston": "^3.13.0"
12+
},
13+
"devDependencies": {
14+
"@types/aws-lambda": "^8.10.136",
15+
"@types/node": "^20.11.30",
16+
"jest": "^29.6.4",
17+
"ts-jest": "^29.1.2",
18+
"typescript": "^5.4.3"
19+
}
20+
}

0 commit comments

Comments
 (0)