@ledgerhq/coin-hypercore 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # @ledgerhq/coin-hypercore
2
2
 
3
+ ## 2.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#875](https://github.com/LedgerHQ/coin-modules/pull/875) [`f709960`](https://github.com/LedgerHQ/coin-modules/commit/f709960d0146b2c592be70d3fb0142890e7ecd2c) Thanks [@francois-guerin-ledger](https://github.com/francois-guerin-ledger)! - chore(coin-xrp,coin-stellar,coin-hypercore): remove unused peer deps
8
+
9
+ ## 2.0.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#830](https://github.com/LedgerHQ/coin-modules/pull/830) [`9adf9d9`](https://github.com/LedgerHQ/coin-modules/commit/9adf9d9ea1c7397b1fc4a09fbf9bbc4c8a6bdefb) Thanks [@cted-ledger](https://github.com/cted-ledger)! - Build the api from the framework's `notSupportedApi()` instead of listing fifteen
14
+ `notSupported('…')` stubs by hand. `createApi` spreads the framework value and overrides the four
15
+ methods this module implements — `lastBlock`, `getBalance`, `listOperations` and
16
+ `validateAddress` — taking the factory from twenty entries to four.
17
+
18
+ Hypercore could not adopt the `CoinModuleImpl` authoring type: it does not implement five of the
19
+ eight methods that type requires, because it is read-only. It reads a balance, a block and a
20
+ history, and crafts and broadcasts nothing — so its unsupported methods cannot be expressed by
21
+ omission. Spreading a fully-stubbed api satisfies the contract statically instead, and makes what
22
+ the module is readable from the four lines it keeps.
23
+
24
+ `getAccountInfo` now resolves the ADR-045 `{ type: 'none' }` sentinel from the module itself
25
+ rather than being backfilled by the resolver's `withDefaults` — the same value a consumer already
26
+ received.
27
+
28
+ `getBalance` gains a behaviour change. This module reads a plain balance and applies no filtering, so it now routes through the framework's `rejectBalanceOptions`, raising `InvalidParameterError` when options are supplied — the convention `coin-stellar`, `coin-tezos` and `coin-casper` already follow. Previously the annotated type promised to accept `BalanceOptions` while the implementation silently dropped them, so a caller asking for a filtered balance received an unfiltered one.
29
+
30
+ Its api test asserted all twenty method names, which only restated that the object was shaped
31
+ like the contract; the type guarantees that now, so it asserts the split instead: what the module
32
+ reads with, and the crafting, broadcasting, staking and enrollment it does not do.
33
+
3
34
  ## 2.0.0
4
35
 
5
36
  ### Major Changes
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpD,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,2CAA2C,CAAA;AAQlD,wBAAgB,SAAS,IAAI,aAAa,CACxC,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,CACnB,CAsBA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpD,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,2CAA2C,CAAA;AAclD,wBAAgB,SAAS,IAAI,aAAa,CACxC,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,CACnB,CASA"}
package/lib/api/index.js CHANGED
@@ -3,33 +3,25 @@
3
3
  // SPDX-License-Identifier: Apache-2.0
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.createApi = createApi;
6
+ const rejectBalanceOptions_1 = require("@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions");
6
7
  const index_1 = require("@ledgerhq/coin-module-framework/api/index");
7
8
  const getBalance_1 = require("./getBalance");
8
9
  const lastBlock_1 = require("./lastBlock");
9
10
  const listOperations_1 = require("./listOperations");
10
11
  const validateAddress_1 = require("./validateAddress");
11
12
  // The caller builds the {@link Context} (config + logger) and passes it to each method (ADR-019).
13
+ //
14
+ // This module is read-only: it reads a balance, a block and a history, and crafts and broadcasts
15
+ // nothing. It cannot declare the `CoinModuleImpl` authoring type, which requires methods it does
16
+ // not implement, so it spreads a fully-stubbed api and overrides the four it does — the contract
17
+ // is satisfied statically, and what the module is stays readable from the four lines below.
12
18
  function createApi() {
13
19
  return {
20
+ ...(0, index_1.notSupportedApi)(),
14
21
  lastBlock: () => (0, lastBlock_1.lastBlock)(),
15
- getBlockInfo: (0, index_1.notSupported)('getBlockInfo'),
16
- getBlock: (0, index_1.notSupported)('getBlock'),
17
- call: (0, index_1.notSupported)('call'),
18
- getValidators: (0, index_1.notSupported)('getValidators'),
19
- getBalance: (ctx, address) => (0, getBalance_1.getBalance)(ctx, address),
22
+ getBalance: (ctx, address, options) => (0, rejectBalanceOptions_1.rejectBalanceOptions)(() => (0, getBalance_1.getBalance)(ctx, address), options),
20
23
  listOperations: (ctx, address, options) => (0, listOperations_1.listOperations)(ctx, address, options),
21
- getStakes: (0, index_1.notSupported)('getStakes'),
22
- getRewards: (0, index_1.notSupported)('getRewards'),
23
- register: (0, index_1.notSupported)('register'),
24
- craftTransaction: (0, index_1.notSupported)('craftTransaction'),
25
- craftRawTransaction: (0, index_1.notSupported)('craftRawTransaction'),
26
- estimateFees: (0, index_1.notSupported)('estimateFees'),
27
- combine: (0, index_1.notSupported)('combine'),
28
- broadcast: (0, index_1.notSupported)('broadcast'),
29
- validateIntent: (0, index_1.notSupported)('validateIntent'),
30
- getNextSequence: (0, index_1.notSupported)('getNextSequence'),
31
24
  validateAddress: (_ctx, address, parameters) => (0, validateAddress_1.validateAddress)(address, parameters),
32
- craftTransactionData: (0, index_1.notSupported)('craftTransactionData'),
33
25
  };
34
26
  }
35
27
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":";AAAA,4CAA4C;AAC5C,sCAAsC;;AAetC,8BA0BC;AAjCD,qEAAwE;AACxE,6CAAyC;AACzC,2CAAuC;AACvC,qDAAiD;AACjD,uDAAmD;AAEnD,kGAAkG;AAClG,SAAgB,SAAS;IAKvB,OAAO;QACL,SAAS,EAAE,GAAG,EAAE,CAAC,IAAA,qBAAS,GAAE;QAC5B,YAAY,EAAE,IAAA,oBAAY,EAAC,cAAc,CAAC;QAC1C,QAAQ,EAAE,IAAA,oBAAY,EAAC,UAAU,CAAC;QAClC,IAAI,EAAE,IAAA,oBAAY,EAAC,MAAM,CAAC;QAC1B,aAAa,EAAE,IAAA,oBAAY,EAAC,eAAe,CAAC;QAC5C,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,IAAA,uBAAU,EAAC,GAAG,EAAE,OAAO,CAAC;QACtD,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,IAAA,+BAAc,EAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC;QAChF,SAAS,EAAE,IAAA,oBAAY,EAAC,WAAW,CAAC;QACpC,UAAU,EAAE,IAAA,oBAAY,EAAC,YAAY,CAAC;QACtC,QAAQ,EAAE,IAAA,oBAAY,EAAC,UAAU,CAAC;QAClC,gBAAgB,EAAE,IAAA,oBAAY,EAAC,kBAAkB,CAAC;QAClD,mBAAmB,EAAE,IAAA,oBAAY,EAAC,qBAAqB,CAAC;QACxD,YAAY,EAAE,IAAA,oBAAY,EAAC,cAAc,CAAC;QAC1C,OAAO,EAAE,IAAA,oBAAY,EAAC,SAAS,CAAC;QAChC,SAAS,EAAE,IAAA,oBAAY,EAAC,WAAW,CAAC;QACpC,cAAc,EAAE,IAAA,oBAAY,EAAC,gBAAgB,CAAC;QAC9C,eAAe,EAAE,IAAA,oBAAY,EAAC,iBAAiB,CAAC;QAChD,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,IAAA,iCAAe,EAAC,OAAO,EAAE,UAAU,CAAC;QACpF,oBAAoB,EAAE,IAAA,oBAAY,EAAC,sBAAsB,CAAC;KAC3D,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":";AAAA,4CAA4C;AAC5C,sCAAsC;;AAqBtC,8BAaC;AA1BD,8GAA0G;AAC1G,qEAA2E;AAC3E,6CAAyC;AACzC,2CAAuC;AACvC,qDAAiD;AACjD,uDAAmD;AAEnD,kGAAkG;AAClG,EAAE;AACF,iGAAiG;AACjG,iGAAiG;AACjG,iGAAiG;AACjG,4FAA4F;AAC5F,SAAgB,SAAS;IAKvB,OAAO;QACL,GAAG,IAAA,uBAAe,GAA6D;QAC/E,SAAS,EAAE,GAAG,EAAE,CAAC,IAAA,qBAAS,GAAE;QAC5B,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAQ,EAAE,EAAE,CACrC,IAAA,2CAAoB,EAAC,GAAG,EAAE,CAAC,IAAA,uBAAU,EAAC,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAC/D,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,IAAA,+BAAc,EAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC;QAChF,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,IAAA,iCAAe,EAAC,OAAO,EAAE,UAAU,CAAC;KACrF,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpD,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,2CAA2C,CAAA;AAQlD,wBAAgB,SAAS,IAAI,aAAa,CACxC,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,CACnB,CAsBA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpD,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,2CAA2C,CAAA;AAclD,wBAAgB,SAAS,IAAI,aAAa,CACxC,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,CACnB,CASA"}
@@ -1,32 +1,24 @@
1
1
  // SPDX-FileCopyrightText: © 2024 LEDGER SAS
2
2
  // SPDX-License-Identifier: Apache-2.0
3
- import { notSupported } from '@ledgerhq/coin-module-framework/api/index';
3
+ import { rejectBalanceOptions } from '@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions';
4
+ import { notSupportedApi } from '@ledgerhq/coin-module-framework/api/index';
4
5
  import { getBalance } from './getBalance';
5
6
  import { lastBlock } from './lastBlock';
6
7
  import { listOperations } from './listOperations';
7
8
  import { validateAddress } from './validateAddress';
8
9
  // The caller builds the {@link Context} (config + logger) and passes it to each method (ADR-019).
10
+ //
11
+ // This module is read-only: it reads a balance, a block and a history, and crafts and broadcasts
12
+ // nothing. It cannot declare the `CoinModuleImpl` authoring type, which requires methods it does
13
+ // not implement, so it spreads a fully-stubbed api and overrides the four it does — the contract
14
+ // is satisfied statically, and what the module is stays readable from the four lines below.
9
15
  export function createApi() {
10
16
  return {
17
+ ...notSupportedApi(),
11
18
  lastBlock: () => lastBlock(),
12
- getBlockInfo: notSupported('getBlockInfo'),
13
- getBlock: notSupported('getBlock'),
14
- call: notSupported('call'),
15
- getValidators: notSupported('getValidators'),
16
- getBalance: (ctx, address) => getBalance(ctx, address),
19
+ getBalance: (ctx, address, options) => rejectBalanceOptions(() => getBalance(ctx, address), options),
17
20
  listOperations: (ctx, address, options) => listOperations(ctx, address, options),
18
- getStakes: notSupported('getStakes'),
19
- getRewards: notSupported('getRewards'),
20
- register: notSupported('register'),
21
- craftTransaction: notSupported('craftTransaction'),
22
- craftRawTransaction: notSupported('craftRawTransaction'),
23
- estimateFees: notSupported('estimateFees'),
24
- combine: notSupported('combine'),
25
- broadcast: notSupported('broadcast'),
26
- validateIntent: notSupported('validateIntent'),
27
- getNextSequence: notSupported('getNextSequence'),
28
21
  validateAddress: (_ctx, address, parameters) => validateAddress(address, parameters),
29
- craftTransactionData: notSupported('craftTransactionData'),
30
22
  };
31
23
  }
32
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,sCAAsC;AAQtC,OAAO,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAA;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD,kGAAkG;AAClG,MAAM,UAAU,SAAS;IAKvB,OAAO;QACL,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE;QAC5B,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC;QAC1C,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC;QAClC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC;QAC1B,aAAa,EAAE,YAAY,CAAC,eAAe,CAAC;QAC5C,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;QACtD,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC;QAChF,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC;QACpC,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC;QACtC,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC;QAClC,gBAAgB,EAAE,YAAY,CAAC,kBAAkB,CAAC;QAClD,mBAAmB,EAAE,YAAY,CAAC,qBAAqB,CAAC;QACxD,YAAY,EAAE,YAAY,CAAC,cAAc,CAAC;QAC1C,OAAO,EAAE,YAAY,CAAC,SAAS,CAAC;QAChC,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC;QACpC,cAAc,EAAE,YAAY,CAAC,gBAAgB,CAAC;QAC9C,eAAe,EAAE,YAAY,CAAC,iBAAiB,CAAC;QAChD,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC;QACpF,oBAAoB,EAAE,YAAY,CAAC,sBAAsB,CAAC;KAC3D,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,sCAAsC;AAQtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,qEAAqE,CAAA;AAC1G,OAAO,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAA;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD,kGAAkG;AAClG,EAAE;AACF,iGAAiG;AACjG,iGAAiG;AACjG,iGAAiG;AACjG,4FAA4F;AAC5F,MAAM,UAAU,SAAS;IAKvB,OAAO;QACL,GAAG,eAAe,EAA6D;QAC/E,SAAS,EAAE,GAAG,EAAE,CAAC,SAAS,EAAE;QAC5B,UAAU,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAQ,EAAE,EAAE,CACrC,oBAAoB,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAC/D,cAAc,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC;QAChF,eAAe,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC;KACrF,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/coin-hypercore",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Ledger Hypercore Coin integration",
5
5
  "keywords": [
6
6
  "Ledger",
@@ -65,7 +65,7 @@
65
65
  "author": "LEDGER SAS",
66
66
  "license": "Apache-2.0",
67
67
  "dependencies": {
68
- "@ledgerhq/coin-module-framework": "^8.0.0"
68
+ "@ledgerhq/coin-module-framework": "^8.5.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@swc/core": "1.15.11",
@@ -78,8 +78,7 @@
78
78
  "typescript": "6.0.2"
79
79
  },
80
80
  "peerDependencies": {
81
- "@ledgerhq/live-network": "^3.0.0",
82
- "@ledgerhq/logs": "^6.17.0"
81
+ "@ledgerhq/live-network": "^3.0.0"
83
82
  },
84
83
  "scripts": {
85
84
  "clean": "rimraf lib lib-es",
@@ -1,30 +1,65 @@
1
1
  // SPDX-FileCopyrightText: © 2024 LEDGER SAS
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { isNotSupportedStub } from '@ledgerhq/coin-module-framework/api/index'
5
+ import { InvalidParameterError } from '@ledgerhq/coin-module-framework/errors'
4
6
  import { createApi } from '.'
5
7
 
6
8
  describe('createApi', () => {
7
- it('returns all API methods', () => {
8
- expect(createApi()).toEqual({
9
- broadcast: expect.any(Function),
10
- call: expect.any(Function),
11
- combine: expect.any(Function),
12
- craftRawTransaction: expect.any(Function),
13
- craftTransaction: expect.any(Function),
14
- craftTransactionData: expect.any(Function),
15
- estimateFees: expect.any(Function),
16
- getBalance: expect.any(Function),
17
- getBlock: expect.any(Function),
18
- getBlockInfo: expect.any(Function),
19
- getNextSequence: expect.any(Function),
20
- getRewards: expect.any(Function),
21
- getStakes: expect.any(Function),
22
- getValidators: expect.any(Function),
23
- lastBlock: expect.any(Function),
24
- listOperations: expect.any(Function),
25
- register: expect.any(Function),
26
- validateAddress: expect.any(Function),
27
- validateIntent: expect.any(Function),
28
- })
9
+ const api = createApi()
10
+
11
+ // The contract's shape is guaranteed by the type now that `notSupportedApi()` is spread in, so
12
+ // what is worth asserting is the split: the four methods this read-only module reads with, and
13
+ // the crafting and broadcasting it does not do. Listing all twenty method names, as this test
14
+ // did, only restated that the object was shaped like the contract.
15
+ it('reads a balance, a block and a history, and validates an address', () => {
16
+ expect(isNotSupportedStub(api.lastBlock)).toBe(false)
17
+ expect(isNotSupportedStub(api.getBalance)).toBe(false)
18
+ expect(isNotSupportedStub(api.listOperations)).toBe(false)
19
+ expect(isNotSupportedStub(api.validateAddress)).toBe(false)
20
+ })
21
+
22
+ it('crafts and broadcasts nothing', () => {
23
+ expect(isNotSupportedStub(api.craftTransaction)).toBe(true)
24
+ expect(isNotSupportedStub(api.craftRawTransaction)).toBe(true)
25
+ expect(isNotSupportedStub(api.craftTransactionData)).toBe(true)
26
+ expect(isNotSupportedStub(api.estimateFees)).toBe(true)
27
+ expect(isNotSupportedStub(api.combine)).toBe(true)
28
+ expect(isNotSupportedStub(api.broadcast)).toBe(true)
29
+ expect(isNotSupportedStub(api.validateIntent)).toBe(true)
30
+ expect(isNotSupportedStub(api.getNextSequence)).toBe(true)
31
+ })
32
+
33
+ it('has no staking, block lookup, contract call or enrollment', () => {
34
+ expect(isNotSupportedStub(api.getStakes)).toBe(true)
35
+ expect(isNotSupportedStub(api.getRewards)).toBe(true)
36
+ expect(isNotSupportedStub(api.getValidators)).toBe(true)
37
+ expect(isNotSupportedStub(api.getBlock)).toBe(true)
38
+ expect(isNotSupportedStub(api.getBlockInfo)).toBe(true)
39
+ expect(isNotSupportedStub(api.call)).toBe(true)
40
+ expect(isNotSupportedStub(api.register)).toBe(true)
41
+ })
42
+
43
+ // Hypercore reads a plain balance and applies no filtering, so the framework's convention is to
44
+ // reject the options rather than accept and silently ignore them.
45
+ it('rejects the getBalance options it does not support', async () => {
46
+ await expect(
47
+ api.getBalance(
48
+ { config: () => Promise.reject(new Error('stub')), logger: () => undefined },
49
+ 'addr',
50
+ {}
51
+ )
52
+ ).rejects.toThrow(InvalidParameterError)
53
+ })
54
+
55
+ // Absent account metadata is an answer, not a missing capability (ADR-045) — the same value
56
+ // `withDefaults` supplied before, now carried by the module itself.
57
+ it('answers the sentinel for getAccountInfo rather than throwing', async () => {
58
+ await expect(
59
+ api.getAccountInfo?.(
60
+ { config: () => Promise.reject(new Error('stub')), logger: () => undefined },
61
+ 'addr'
62
+ )
63
+ ).resolves.toEqual({ type: 'none' })
29
64
  })
30
65
  })
package/src/api/index.ts CHANGED
@@ -7,37 +7,30 @@ import type {
7
7
  MemoNotSupported,
8
8
  TxDataNotSupported,
9
9
  } from '@ledgerhq/coin-module-framework/api/index'
10
- import { notSupported } from '@ledgerhq/coin-module-framework/api/index'
10
+ import { rejectBalanceOptions } from '@ledgerhq/coin-module-framework/api/getBalance/rejectBalanceOptions'
11
+ import { notSupportedApi } from '@ledgerhq/coin-module-framework/api/index'
11
12
  import { getBalance } from './getBalance'
12
13
  import { lastBlock } from './lastBlock'
13
14
  import { listOperations } from './listOperations'
14
15
  import { validateAddress } from './validateAddress'
15
16
 
16
17
  // The caller builds the {@link Context} (config + logger) and passes it to each method (ADR-019).
18
+ //
19
+ // This module is read-only: it reads a balance, a block and a history, and crafts and broadcasts
20
+ // nothing. It cannot declare the `CoinModuleImpl` authoring type, which requires methods it does
21
+ // not implement, so it spreads a fully-stubbed api and overrides the four it does — the contract
22
+ // is satisfied statically, and what the module is stays readable from the four lines below.
17
23
  export function createApi(): CoinModuleApi<
18
24
  HypercoreCoinConfig,
19
25
  MemoNotSupported,
20
26
  TxDataNotSupported
21
27
  > {
22
28
  return {
29
+ ...notSupportedApi<HypercoreCoinConfig, MemoNotSupported, TxDataNotSupported>(),
23
30
  lastBlock: () => lastBlock(),
24
- getBlockInfo: notSupported('getBlockInfo'),
25
- getBlock: notSupported('getBlock'),
26
- call: notSupported('call'),
27
- getValidators: notSupported('getValidators'),
28
- getBalance: (ctx, address) => getBalance(ctx, address),
31
+ getBalance: (ctx, address, options?) =>
32
+ rejectBalanceOptions(() => getBalance(ctx, address), options),
29
33
  listOperations: (ctx, address, options) => listOperations(ctx, address, options),
30
- getStakes: notSupported('getStakes'),
31
- getRewards: notSupported('getRewards'),
32
- register: notSupported('register'),
33
- craftTransaction: notSupported('craftTransaction'),
34
- craftRawTransaction: notSupported('craftRawTransaction'),
35
- estimateFees: notSupported('estimateFees'),
36
- combine: notSupported('combine'),
37
- broadcast: notSupported('broadcast'),
38
- validateIntent: notSupported('validateIntent'),
39
- getNextSequence: notSupported('getNextSequence'),
40
34
  validateAddress: (_ctx, address, parameters) => validateAddress(address, parameters),
41
- craftTransactionData: notSupported('craftTransactionData'),
42
35
  }
43
36
  }