@ledgerhq/coin-hypercore 2.0.0 → 2.0.1

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,30 @@
1
1
  # @ledgerhq/coin-hypercore
2
2
 
3
+ ## 2.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#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
8
+ `notSupported('…')` stubs by hand. `createApi` spreads the framework value and overrides the four
9
+ methods this module implements — `lastBlock`, `getBalance`, `listOperations` and
10
+ `validateAddress` — taking the factory from twenty entries to four.
11
+
12
+ Hypercore could not adopt the `CoinModuleImpl` authoring type: it does not implement five of the
13
+ eight methods that type requires, because it is read-only. It reads a balance, a block and a
14
+ history, and crafts and broadcasts nothing — so its unsupported methods cannot be expressed by
15
+ omission. Spreading a fully-stubbed api satisfies the contract statically instead, and makes what
16
+ the module is readable from the four lines it keeps.
17
+
18
+ `getAccountInfo` now resolves the ADR-045 `{ type: 'none' }` sentinel from the module itself
19
+ rather than being backfilled by the resolver's `withDefaults` — the same value a consumer already
20
+ received.
21
+
22
+ `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.
23
+
24
+ Its api test asserted all twenty method names, which only restated that the object was shaped
25
+ like the contract; the type guarantees that now, so it asserts the split instead: what the module
26
+ reads with, and the crafting, broadcasting, staking and enrollment it does not do.
27
+
3
28
  ## 2.0.0
4
29
 
5
30
  ### 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.1",
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.2.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@swc/core": "1.15.11",
@@ -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
  }