dash-platform-sdk 1.4.0-dev.9 → 1.5.0-dev.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.
Files changed (42) hide show
  1. package/README.md +122 -0
  2. package/bundle.min.js +17 -17
  3. package/package.json +6 -2
  4. package/proto/generated/platform.client.d.ts +60 -0
  5. package/proto/generated/platform.client.js +42 -0
  6. package/proto/generated/platform.d.ts +783 -0
  7. package/proto/generated/platform.js +1582 -1
  8. package/src/DashPlatformSDK.d.ts +2 -0
  9. package/src/DashPlatformSDK.js +3 -0
  10. package/src/constants.d.ts +2 -1
  11. package/src/constants.js +3 -1
  12. package/src/documents/index.js +1 -1
  13. package/src/documents/query.js +4 -6
  14. package/src/keyPair/index.d.ts +25 -0
  15. package/src/keyPair/index.js +33 -0
  16. package/src/shielded/createStateTransition.d.ts +3 -0
  17. package/src/shielded/createStateTransition.js +55 -0
  18. package/src/shielded/getMostRecentShieldedAnchor.d.ts +2 -0
  19. package/src/shielded/getMostRecentShieldedAnchor.js +36 -0
  20. package/src/shielded/getShieldedAnchors.d.ts +2 -0
  21. package/src/shielded/getShieldedAnchors.js +36 -0
  22. package/src/shielded/getShieldedEncryptedNotes.d.ts +3 -0
  23. package/src/shielded/getShieldedEncryptedNotes.js +43 -0
  24. package/src/shielded/getShieldedNotesCount.d.ts +2 -0
  25. package/src/shielded/getShieldedNotesCount.js +36 -0
  26. package/src/shielded/getShieldedNullifiers.d.ts +3 -0
  27. package/src/shielded/getShieldedNullifiers.js +40 -0
  28. package/src/shielded/getShieldedPoolState.d.ts +2 -0
  29. package/src/shielded/getShieldedPoolState.js +36 -0
  30. package/src/shielded/index.d.ts +130 -0
  31. package/src/shielded/index.js +186 -0
  32. package/src/stateTransitions/broadcast.js +3 -2
  33. package/test/unit/DataContract.spec.js +1 -1
  34. package/test/unit/Document.spec.js +31 -2
  35. package/test/unit/Identity.spec.js +26 -26
  36. package/test/unit/KeyPair.spec.js +32 -0
  37. package/test/unit/PlatformAddress.spec.js +4 -4
  38. package/test/unit/Shielded.spec.d.ts +1 -0
  39. package/test/unit/Shielded.spec.js +236 -0
  40. package/test/unit/Tokens.spec.js +2 -2
  41. package/types.d.ts +86 -2
  42. package/types.js +1 -1
@@ -0,0 +1,130 @@
1
+ import GRPCConnectionPool from '../grpcConnectionPool.js';
2
+ import { ShieldedEncryptedNote, ShieldedNullifierStatus, ShieldedTransitionParamsMap, ShieldedTransitionType } from '../../types.js';
3
+ import { RecoveredNoteWASM, ShieldedBuilderWASM, SpendableNoteWASM, StateTransitionWASM } from 'pshenmic-dpp';
4
+ /**
5
+ * Shielded controller for requesting information about shielded pool
6
+ *
7
+ * @hideconstructor
8
+ */
9
+ export declare class ShieldedController {
10
+ /** @ignore **/
11
+ grpcPool: GRPCConnectionPool;
12
+ /** @ignore **/
13
+ shieldedBuilder?: ShieldedBuilderWASM;
14
+ constructor(grpcPool: GRPCConnectionPool);
15
+ /**
16
+ * Set bindings instance of builder
17
+ * Needed for custom builder load, because ShieldedBuilderWASM inits very slow on old hardware
18
+ */
19
+ init(builder?: ShieldedBuilderWASM): ShieldedBuilderWASM;
20
+ /**
21
+ * Lazily constructs and caches a {ShieldedBuilderWASM}. Construction builds
22
+ * the Halo 2 proving key (~seconds), so the instance is created once and reused.
23
+ *
24
+ * @ignore
25
+ */
26
+ getShieldedBuilder(): ShieldedBuilderWASM;
27
+ /**
28
+ * Retrieves a batch of shielded encrypted notes from the shielded pool,
29
+ * starting from the given note index.
30
+ *
31
+ * Returns an array of encrypted notes, each containing the nullifier,
32
+ * note commitment (cmx), encrypted note payload and value commitment (cvNet).
33
+ *
34
+ * @param startIndex {bigint} - index of the first note to fetch
35
+ * @param count {number} - amount of notes to fetch
36
+ *
37
+ * @return {Promise<ShieldedEncryptedNote[]>}
38
+ */
39
+ getShieldedEncryptedNotes(startIndex: bigint, count: number): Promise<ShieldedEncryptedNote[]>;
40
+ /**
41
+ * Retrieves the set of valid anchors (note commitment tree roots) currently
42
+ * accepted by the shielded pool.
43
+ *
44
+ * @return {Promise<Uint8Array[]>}
45
+ */
46
+ getShieldedAnchors(): Promise<Uint8Array[]>;
47
+ /**
48
+ * Retrieves the most recent anchor (note commitment tree root) of the shielded pool.
49
+ *
50
+ * @return {Promise<Uint8Array>}
51
+ */
52
+ getMostRecentShieldedAnchor(): Promise<Uint8Array | undefined>;
53
+ /**
54
+ * Retrieves the total balance currently held in the shielded pool.
55
+ *
56
+ * @return {Promise<bigint>}
57
+ */
58
+ getShieldedPoolState(): Promise<bigint | undefined>;
59
+ /**
60
+ * Retrieves the total count of notes (leaves) in the shielded notes
61
+ * commitment tree. Useful as a denominator for shielded sync progress.
62
+ *
63
+ * @return {Promise<bigint>}
64
+ */
65
+ getShieldedNotesCount(): Promise<bigint | undefined>;
66
+ /**
67
+ * Checks the spent status of the given nullifiers in the shielded pool.
68
+ *
69
+ * Returns an array of statuses, each containing the nullifier and whether
70
+ * it has already been spent.
71
+ *
72
+ * @param nullifiers {Uint8Array[]} - nullifiers to check
73
+ *
74
+ * @return {Promise<ShieldedNullifierStatus[]>}
75
+ */
76
+ getShieldedNullifiers(nullifiers: Uint8Array[]): Promise<ShieldedNullifierStatus[]>;
77
+ /**
78
+ * Recovers the notes owned by a wallet from a set of shielded encrypted notes
79
+ * (as returned by {@link getShieldedEncryptedNotes}) by trial-decrypting each
80
+ * with the viewing key derived from the seed (ZIP-32 m/32'/coinType'/account').
81
+ * Only notes addressed to the wallet are returned, each with its global leaf
82
+ * position (`index`) in the commitment tree.
83
+ *
84
+ * @param notes {ShieldedEncryptedNote[]} - shielded encrypted notes to scan
85
+ * @param seed {Uint8Array} - BIP-39 seed bytes
86
+ * @param account {number} - ZIP-32 account index
87
+ *
88
+ * @return {RecoveredNoteWASM[]}
89
+ */
90
+ recoverNotes(notes: ShieldedEncryptedNote[], seed: Uint8Array, account: number): RecoveredNoteWASM[];
91
+ /**
92
+ * Rebuilds the note commitment tree from the full on-chain note set and
93
+ * witnesses the given recovered notes against it, producing the spendable
94
+ * notes and the shared anchor required by spend transitions (`shieldedTransfer`,
95
+ * `unshield`, `shieldedWithdrawal`, `identityCreateFromShieldedPool`).
96
+ *
97
+ * Pass the complete note set from {@link getShieldedEncryptedNotes} as `notes`
98
+ * (the commitment tree leaves) and the notes you want to spend from
99
+ * {@link recoverNotes} as `recovered`. This keeps the whole spend flow inside
100
+ * the SDK — no need to construct a commitment tree yourself.
101
+ *
102
+ * @param notes {ShieldedEncryptedNote[]} - full on-chain note set (the tree leaves)
103
+ * @param recovered {RecoveredNoteWASM[]} - the recovered notes to spend
104
+ *
105
+ * @return {{ spends: SpendableNoteWASM[], anchor: Uint8Array }}
106
+ */
107
+ buildSpendableNotes(notes: ShieldedEncryptedNote[], recovered: RecoveredNoteWASM[]): {
108
+ spends: SpendableNoteWASM[];
109
+ anchor: Uint8Array;
110
+ };
111
+ /**
112
+ * Helper function for building and proving shielded (Orchard) transitions.
113
+ * It may be used to create any of 6 shielded transition actions:
114
+ *
115
+ * 1) shield - transparent platform addresses -> pool (deposit)
116
+ * 2) shieldFromAssetLock - asset lock -> pool (deposit)
117
+ * 3) shieldedWithdrawal - pool -> core L1 (spend)
118
+ * 4) unshield - pool -> platform identity balance (spend)
119
+ * 5) shieldedTransfer - pool -> pool (spend)
120
+ * 6) identityCreateFromShieldedPool - pool -> new identity (spend)
121
+ *
122
+ * Spends require a {SpendableNoteWASM} witnessed against an on-chain anchor.
123
+ *
124
+ * @param type {string} Type of the shielded transition, must be one of ('shield' | 'shieldFromAssetLock' | 'shieldedWithdrawal' | 'unshield' | 'shieldedTransfer' | 'identityCreateFromShieldedPool')
125
+ * @param params {ShieldedTransitionParams} params
126
+ *
127
+ * @return {StateTransitionWASM}
128
+ */
129
+ createStateTransition<K extends ShieldedTransitionType>(type: K, params: ShieldedTransitionParamsMap[K]): StateTransitionWASM;
130
+ }
@@ -0,0 +1,186 @@
1
+ import getShieldedEncryptedNotes from './getShieldedEncryptedNotes.js';
2
+ import getShieldedAnchors from './getShieldedAnchors.js';
3
+ import getMostRecentShieldedAnchor from './getMostRecentShieldedAnchor.js';
4
+ import getShieldedPoolState from './getShieldedPoolState.js';
5
+ import getShieldedNotesCount from './getShieldedNotesCount.js';
6
+ import getShieldedNullifiers from './getShieldedNullifiers.js';
7
+ import createStateTransition from './createStateTransition.js';
8
+ import { CommitmentTreeWASM, ContractBoundsWASM, IdentityPublicKeyInCreationWASM, recoverNotes, SerializedActionWASM, ShieldedBuilderWASM, ShieldedMemoWASM, SpendableNoteWASM } from 'pshenmic-dpp';
9
+ /**
10
+ * Shielded controller for requesting information about shielded pool
11
+ *
12
+ * @hideconstructor
13
+ */
14
+ export class ShieldedController {
15
+ /** @ignore **/
16
+ grpcPool;
17
+ /** @ignore **/
18
+ shieldedBuilder;
19
+ constructor(grpcPool) {
20
+ this.grpcPool = grpcPool;
21
+ }
22
+ /**
23
+ * Set bindings instance of builder
24
+ * Needed for custom builder load, because ShieldedBuilderWASM inits very slow on old hardware
25
+ */
26
+ init(builder) {
27
+ this.shieldedBuilder = builder ?? new ShieldedBuilderWASM();
28
+ return this.shieldedBuilder;
29
+ }
30
+ /**
31
+ * Lazily constructs and caches a {ShieldedBuilderWASM}. Construction builds
32
+ * the Halo 2 proving key (~seconds), so the instance is created once and reused.
33
+ *
34
+ * @ignore
35
+ */
36
+ getShieldedBuilder() {
37
+ if (this.shieldedBuilder == null) {
38
+ return this.init();
39
+ }
40
+ return this.shieldedBuilder;
41
+ }
42
+ /**
43
+ * Retrieves a batch of shielded encrypted notes from the shielded pool,
44
+ * starting from the given note index.
45
+ *
46
+ * Returns an array of encrypted notes, each containing the nullifier,
47
+ * note commitment (cmx), encrypted note payload and value commitment (cvNet).
48
+ *
49
+ * @param startIndex {bigint} - index of the first note to fetch
50
+ * @param count {number} - amount of notes to fetch
51
+ *
52
+ * @return {Promise<ShieldedEncryptedNote[]>}
53
+ */
54
+ async getShieldedEncryptedNotes(startIndex, count) {
55
+ return await getShieldedEncryptedNotes(this.grpcPool, startIndex, count);
56
+ }
57
+ /**
58
+ * Retrieves the set of valid anchors (note commitment tree roots) currently
59
+ * accepted by the shielded pool.
60
+ *
61
+ * @return {Promise<Uint8Array[]>}
62
+ */
63
+ async getShieldedAnchors() {
64
+ return await getShieldedAnchors(this.grpcPool);
65
+ }
66
+ /**
67
+ * Retrieves the most recent anchor (note commitment tree root) of the shielded pool.
68
+ *
69
+ * @return {Promise<Uint8Array>}
70
+ */
71
+ async getMostRecentShieldedAnchor() {
72
+ return await getMostRecentShieldedAnchor(this.grpcPool);
73
+ }
74
+ /**
75
+ * Retrieves the total balance currently held in the shielded pool.
76
+ *
77
+ * @return {Promise<bigint>}
78
+ */
79
+ async getShieldedPoolState() {
80
+ return await getShieldedPoolState(this.grpcPool);
81
+ }
82
+ /**
83
+ * Retrieves the total count of notes (leaves) in the shielded notes
84
+ * commitment tree. Useful as a denominator for shielded sync progress.
85
+ *
86
+ * @return {Promise<bigint>}
87
+ */
88
+ async getShieldedNotesCount() {
89
+ return await getShieldedNotesCount(this.grpcPool);
90
+ }
91
+ /**
92
+ * Checks the spent status of the given nullifiers in the shielded pool.
93
+ *
94
+ * Returns an array of statuses, each containing the nullifier and whether
95
+ * it has already been spent.
96
+ *
97
+ * @param nullifiers {Uint8Array[]} - nullifiers to check
98
+ *
99
+ * @return {Promise<ShieldedNullifierStatus[]>}
100
+ */
101
+ async getShieldedNullifiers(nullifiers) {
102
+ return await getShieldedNullifiers(this.grpcPool, nullifiers);
103
+ }
104
+ /**
105
+ * Recovers the notes owned by a wallet from a set of shielded encrypted notes
106
+ * (as returned by {@link getShieldedEncryptedNotes}) by trial-decrypting each
107
+ * with the viewing key derived from the seed (ZIP-32 m/32'/coinType'/account').
108
+ * Only notes addressed to the wallet are returned, each with its global leaf
109
+ * position (`index`) in the commitment tree.
110
+ *
111
+ * @param notes {ShieldedEncryptedNote[]} - shielded encrypted notes to scan
112
+ * @param seed {Uint8Array} - BIP-39 seed bytes
113
+ * @param account {number} - ZIP-32 account index
114
+ *
115
+ * @return {RecoveredNoteWASM[]}
116
+ */
117
+ recoverNotes(notes, seed, account) {
118
+ // SLIP-44 coin type: 5 = Dash mainnet, 1 = testnets. Orchard derives via ZIP-32
119
+ const coinType = this.grpcPool.network === 'mainnet' ? 5 : 1;
120
+ // ShieldedEncryptedNote carries everything needed for trial-decryption; the
121
+ // spend-authorization fields (rk, spendAuthSig) are unused here, so zero them.
122
+ const actions = notes.map(note => new SerializedActionWASM(note.nullifier, new Uint8Array(32), note.cmx, note.encryptedNote, note.cvNet, new Uint8Array(64)));
123
+ return recoverNotes(actions, seed, coinType, account);
124
+ }
125
+ /**
126
+ * Rebuilds the note commitment tree from the full on-chain note set and
127
+ * witnesses the given recovered notes against it, producing the spendable
128
+ * notes and the shared anchor required by spend transitions (`shieldedTransfer`,
129
+ * `unshield`, `shieldedWithdrawal`, `identityCreateFromShieldedPool`).
130
+ *
131
+ * Pass the complete note set from {@link getShieldedEncryptedNotes} as `notes`
132
+ * (the commitment tree leaves) and the notes you want to spend from
133
+ * {@link recoverNotes} as `recovered`. This keeps the whole spend flow inside
134
+ * the SDK — no need to construct a commitment tree yourself.
135
+ *
136
+ * @param notes {ShieldedEncryptedNote[]} - full on-chain note set (the tree leaves)
137
+ * @param recovered {RecoveredNoteWASM[]} - the recovered notes to spend
138
+ *
139
+ * @return {{ spends: SpendableNoteWASM[], anchor: Uint8Array }}
140
+ */
141
+ buildSpendableNotes(notes, recovered) {
142
+ // only the leaves we intend to witness need to be marked spendable
143
+ const spendableIndices = new Set(recovered.map(note => note.index));
144
+ const tree = new CommitmentTreeWASM();
145
+ notes.forEach((note, index) => tree.append(note.cmx, spendableIndices.has(index)));
146
+ tree.checkpoint(0);
147
+ const anchor = tree.anchor();
148
+ const spends = recovered.map(recoveredNote => {
149
+ const merklePath = tree.witness(recoveredNote.index, 0) ?? tree.witness(recoveredNote.index, 1);
150
+ if (merklePath == null) {
151
+ throw new Error(`Failed to witness recovered note at index ${recoveredNote.index}`);
152
+ }
153
+ return new SpendableNoteWASM(recoveredNote.note, merklePath);
154
+ });
155
+ return { spends, anchor };
156
+ }
157
+ /**
158
+ * Helper function for building and proving shielded (Orchard) transitions.
159
+ * It may be used to create any of 6 shielded transition actions:
160
+ *
161
+ * 1) shield - transparent platform addresses -> pool (deposit)
162
+ * 2) shieldFromAssetLock - asset lock -> pool (deposit)
163
+ * 3) shieldedWithdrawal - pool -> core L1 (spend)
164
+ * 4) unshield - pool -> platform identity balance (spend)
165
+ * 5) shieldedTransfer - pool -> pool (spend)
166
+ * 6) identityCreateFromShieldedPool - pool -> new identity (spend)
167
+ *
168
+ * Spends require a {SpendableNoteWASM} witnessed against an on-chain anchor.
169
+ *
170
+ * @param type {string} Type of the shielded transition, must be one of ('shield' | 'shieldFromAssetLock' | 'shieldedWithdrawal' | 'unshield' | 'shieldedTransfer' | 'identityCreateFromShieldedPool')
171
+ * @param params {ShieldedTransitionParams} params
172
+ *
173
+ * @return {StateTransitionWASM}
174
+ */
175
+ createStateTransition(type, params) {
176
+ // @ts-expect-error a plain string memo is normalized to ShieldedMemoWASM (empty when omitted)
177
+ params.memo = typeof params.memo === 'string' ? ShieldedMemoWASM.fromString(params.memo) : ShieldedMemoWASM.empty();
178
+ if (type === 'identityCreateFromShieldedPool') {
179
+ const identityParams = params;
180
+ // @ts-expect-error builder expects IdentityPublicKeyInCreationWASM instances
181
+ identityParams.publicKeys = identityParams.publicKeys
182
+ .map(({ id, purpose, securityLevel, keyType, readOnly, data, signature, contractBounds }) => new IdentityPublicKeyInCreationWASM(id, purpose, securityLevel, keyType, readOnly, data, signature, (contractBounds != null) ? new ContractBoundsWASM(contractBounds.dataContractId, contractBounds.documentType) : undefined));
183
+ }
184
+ return createStateTransition(this.getShieldedBuilder(), type, params);
185
+ }
186
+ }
@@ -11,8 +11,9 @@ export default async function broadcast(grpcPool, stateTransition) {
11
11
  await grpcPool.getClient().broadcastStateTransition(broadcastStateTransitionRequest);
12
12
  }
13
13
  catch (err) {
14
- if (err.meta?.['dash-serialized-consensus-error-bin']?.length !== 0) {
15
- throw new Error(deserializeConsensusError(err.meta['dash-serialized-consensus-error-bin']));
14
+ const errorBin = err.meta?.['dash-serialized-consensus-error-bin'];
15
+ if (errorBin?.length !== 0 && errorBin != null) {
16
+ throw new Error(deserializeConsensusError(errorBin));
16
17
  }
17
18
  else {
18
19
  throw err;
@@ -11,7 +11,7 @@ describe('DataContract', () => {
11
11
  ownerIdentifier = 'GARSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec';
12
12
  identityNonce = BigInt(11);
13
13
  config = {
14
- $format_version: '1',
14
+ $formatVersion: '1',
15
15
  canBeDeleted: true,
16
16
  readonly: true,
17
17
  keepsHistory: false,
@@ -1,4 +1,4 @@
1
- import { DocumentWASM, StateTransitionWASM } from 'pshenmic-dpp';
1
+ import { DocumentWASM, GasFeesPaidByWASM, StateTransitionWASM } from 'pshenmic-dpp';
2
2
  import { DashPlatformSDK } from '../../src/DashPlatformSDK.js';
3
3
  let sdk;
4
4
  let dataContract;
@@ -42,6 +42,35 @@ describe('Document', () => {
42
42
  expect(document.dataContractId.base58()).toEqual(dataContract);
43
43
  expect(document).toEqual(expect.any(DocumentWASM));
44
44
  });
45
+ test('should be able to get document with startAt', async () => {
46
+ const dataContract = '6hVQW16jyvZyGSQk2YVty4ND6bgFXozizYWnPt753uW5';
47
+ const documentType = 'torrent';
48
+ const limit = 5;
49
+ // @ts-expect-error
50
+ const [firstQueriedDoc] = (await sdk.documents.query(dataContract, documentType, null, null, limit)).toReversed();
51
+ // @ts-expect-error
52
+ const [secondQueriedDoc] = await sdk.documents.query(dataContract, documentType, null, null, limit, firstQueriedDoc.id);
53
+ expect(secondQueriedDoc.id.base58()).toEqual(firstQueriedDoc.id.base58());
54
+ expect(secondQueriedDoc.createdAtBlockHeight).toEqual(undefined);
55
+ expect(secondQueriedDoc.dataContractId.base58()).toEqual(dataContract);
56
+ expect(secondQueriedDoc).toEqual(expect.any(DocumentWASM));
57
+ });
58
+ test('should be able to get document with startAfter', async () => {
59
+ const dataContract = '6hVQW16jyvZyGSQk2YVty4ND6bgFXozizYWnPt753uW5';
60
+ const documentType = 'torrent';
61
+ const limit = 5;
62
+ const masterQueryLimit = limit * 2;
63
+ // @ts-expect-error
64
+ const masterQuery = await sdk.documents.query(dataContract, documentType, null, null, masterQueryLimit);
65
+ // @ts-expect-error
66
+ const [firstQueriedDoc] = (await sdk.documents.query(dataContract, documentType, null, null, limit)).toReversed();
67
+ // @ts-expect-error
68
+ const [secondQueriedDoc] = await sdk.documents.query(dataContract, documentType, null, null, limit, undefined, firstQueriedDoc.id);
69
+ expect(masterQuery[5].id.base58()).toEqual(secondQueriedDoc.id.base58());
70
+ expect(secondQueriedDoc.createdAtBlockHeight).toEqual(undefined);
71
+ expect(secondQueriedDoc.dataContractId.base58()).toEqual(dataContract);
72
+ expect(secondQueriedDoc).toEqual(expect.any(DocumentWASM));
73
+ });
45
74
  describe('should be able to create state transition', () => {
46
75
  test('should be able to create a create transition', async () => {
47
76
  const document = sdk.documents.create(dataContract, documentType, data, identity);
@@ -67,7 +96,7 @@ describe('Document', () => {
67
96
  tokenContractPosition: 0,
68
97
  minimumTokenCost: BigInt(1000),
69
98
  maximumTokenCost: BigInt(100000),
70
- gasFeesPaidBy: 1 /* GasFeesPaidByWASM.ContractOwner */
99
+ gasFeesPaidBy: GasFeesPaidByWASM.ContractOwner
71
100
  };
72
101
  const stateTransition = sdk.documents.createStateTransition(document, 'create', { identityContractNonce, tokenPaymentInfo });
73
102
  expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
@@ -1,4 +1,4 @@
1
- import { CoreScriptWASM, IdentityPublicKeyWASM, IdentityWASM, PrivateKeyWASM, StateTransitionWASM } from 'pshenmic-dpp';
1
+ import { CoreScriptWASM, IdentityPublicKeyWASM, IdentityWASM, KeyType, PrivateKeyWASM, Purpose, SecurityLevel, StateTransitionWASM } from 'pshenmic-dpp';
2
2
  import { DashPlatformSDK } from '../../types.js';
3
3
  import { base58 } from '@scure/base';
4
4
  let sdk;
@@ -50,18 +50,18 @@ describe('Identity', () => {
50
50
  const privateKey1 = PrivateKeyWASM.fromHex('a1286dd195e2b8e1f6bdc946c56a53e0c544750d6452ddc0f4c593ef311f21af', 'testnet');
51
51
  const identityPublicKeyInCreation1 = {
52
52
  id: 0,
53
- purpose: 0 /* Purpose.AUTHENTICATION */,
54
- securityLevel: 0 /* SecurityLevel.MASTER */,
55
- keyType: 0 /* KeyType.ECDSA_SECP256K1 */,
53
+ purpose: Purpose.AUTHENTICATION,
54
+ securityLevel: SecurityLevel.MASTER,
55
+ keyType: KeyType.ECDSA_SECP256K1,
56
56
  readOnly: false,
57
57
  data: privateKey1.getPublicKey().bytes()
58
58
  };
59
59
  const privateKey2 = PrivateKeyWASM.fromHex('44a8195e242364b935e9d7ff2106ed109e9baf3800907f5e58a259fdfd1ca5e5', 'testnet');
60
60
  const identityPublicKeyInCreation2 = {
61
61
  id: 1,
62
- purpose: 0 /* Purpose.AUTHENTICATION */,
63
- securityLevel: 2 /* SecurityLevel.HIGH */,
64
- keyType: 0 /* KeyType.ECDSA_SECP256K1 */,
62
+ purpose: Purpose.AUTHENTICATION,
63
+ securityLevel: SecurityLevel.HIGH,
64
+ keyType: KeyType.ECDSA_SECP256K1,
65
65
  readOnly: false,
66
66
  data: privateKey2.getPublicKey().bytes()
67
67
  };
@@ -76,7 +76,7 @@ describe('Identity', () => {
76
76
  type: 'chainLock'
77
77
  }
78
78
  });
79
- identityCreateStateTransition.signByPrivateKey(privateKey1, 0 /* KeyType.ECDSA_SECP256K1 */);
79
+ identityCreateStateTransition.signByPrivateKey(privateKey1, KeyType.ECDSA_SECP256K1);
80
80
  identityPublicKeyInCreation1.signature = identityCreateStateTransition.signature;
81
81
  // Set identity public key signature for public key 1
82
82
  identityCreateStateTransition = sdk.identities.createStateTransition('create', {
@@ -88,7 +88,7 @@ describe('Identity', () => {
88
88
  type: 'chainLock'
89
89
  }
90
90
  });
91
- identityCreateStateTransition.signByPrivateKey(privateKey2, 0 /* KeyType.ECDSA_SECP256K1 */);
91
+ identityCreateStateTransition.signByPrivateKey(privateKey2, KeyType.ECDSA_SECP256K1);
92
92
  identityPublicKeyInCreation2.signature = identityCreateStateTransition.signature;
93
93
  // Finalize
94
94
  identityCreateStateTransition = sdk.identities.createStateTransition('create', {
@@ -100,7 +100,7 @@ describe('Identity', () => {
100
100
  type: 'chainLock'
101
101
  }
102
102
  });
103
- identityCreateStateTransition.signByPrivateKey(assetLockPrivateKey, 0 /* KeyType.ECDSA_SECP256K1 */);
103
+ identityCreateStateTransition.signByPrivateKey(assetLockPrivateKey, KeyType.ECDSA_SECP256K1);
104
104
  });
105
105
  test('should be able to create IdentityCreateTransition via InstantSend', async () => {
106
106
  const assetLockPrivateKey = PrivateKeyWASM.fromHex('edd04a71bddb31e530f6c2314fd42ada333f6656bb853ece13f0577a8fd30612', 'testnet');
@@ -110,18 +110,18 @@ describe('Identity', () => {
110
110
  const privateKey1 = PrivateKeyWASM.fromHex('a1286dd195e2b8e1f6bdc946c56a53e0c544750d6452ddc0f4c593ef311f21af', 'testnet');
111
111
  const identityPublicKeyInCreation1 = {
112
112
  id: 0,
113
- purpose: 0 /* Purpose.AUTHENTICATION */,
114
- securityLevel: 0 /* SecurityLevel.MASTER */,
115
- keyType: 0 /* KeyType.ECDSA_SECP256K1 */,
113
+ purpose: Purpose.AUTHENTICATION,
114
+ securityLevel: SecurityLevel.MASTER,
115
+ keyType: KeyType.ECDSA_SECP256K1,
116
116
  readOnly: false,
117
117
  data: privateKey1.getPublicKey().bytes()
118
118
  };
119
119
  const privateKey2 = PrivateKeyWASM.fromHex('44a8195e242364b935e9d7ff2106ed109e9baf3800907f5e58a259fdfd1ca5e5', 'testnet');
120
120
  const identityPublicKeyInCreation2 = {
121
121
  id: 1,
122
- purpose: 0 /* Purpose.AUTHENTICATION */,
123
- securityLevel: 2 /* SecurityLevel.HIGH */,
124
- keyType: 0 /* KeyType.ECDSA_SECP256K1 */,
122
+ purpose: Purpose.AUTHENTICATION,
123
+ securityLevel: SecurityLevel.HIGH,
124
+ keyType: KeyType.ECDSA_SECP256K1,
125
125
  readOnly: false,
126
126
  data: privateKey2.getPublicKey().bytes()
127
127
  };
@@ -136,7 +136,7 @@ describe('Identity', () => {
136
136
  type: 'instantLock'
137
137
  }
138
138
  });
139
- identityCreateStateTransition.signByPrivateKey(privateKey1, 0 /* KeyType.ECDSA_SECP256K1 */);
139
+ identityCreateStateTransition.signByPrivateKey(privateKey1, KeyType.ECDSA_SECP256K1);
140
140
  identityPublicKeyInCreation1.signature = identityCreateStateTransition.signature;
141
141
  // Set identity public key signature for public key 1
142
142
  identityCreateStateTransition = sdk.identities.createStateTransition('create', {
@@ -148,7 +148,7 @@ describe('Identity', () => {
148
148
  type: 'instantLock'
149
149
  }
150
150
  });
151
- identityCreateStateTransition.signByPrivateKey(privateKey2, 0 /* KeyType.ECDSA_SECP256K1 */);
151
+ identityCreateStateTransition.signByPrivateKey(privateKey2, KeyType.ECDSA_SECP256K1);
152
152
  identityPublicKeyInCreation2.signature = identityCreateStateTransition.signature;
153
153
  // Finalize
154
154
  identityCreateStateTransition = sdk.identities.createStateTransition('create', {
@@ -160,7 +160,7 @@ describe('Identity', () => {
160
160
  type: 'instantLock'
161
161
  }
162
162
  });
163
- identityCreateStateTransition.signByPrivateKey(assetLockPrivateKey, 0 /* KeyType.ECDSA_SECP256K1 */);
163
+ identityCreateStateTransition.signByPrivateKey(assetLockPrivateKey, KeyType.ECDSA_SECP256K1);
164
164
  });
165
165
  test('should be able to create IdentityTopUpTransition via InstantSend', async () => {
166
166
  const transaction = '03000800011a468e6a7cf1c5111b09b7bca6743f2571a9bf13d2ff6d21d3d230fd1dea1e97000000006b483045022100fceb25c45e77e1a273660e4f4c9a09042fb858a57704806e14bf80a734af232a02201929893dd720cf5855e31dda577cda16df29520a9774b4f3e813a4cc468fe086012103e16ede6dc5c99f28e3a5733f47a7494992bc6ce4f98551c092645910b9888b8fffffffff0200e1f50500000000026a004054fa02000000001976a91416bbe230f46eea86fc4bf4dd550be45dc9adfcb488ac0000000024010100e1f505000000001976a9147f78813975a3282e09e284d97d93c083b202e34188ac';
@@ -177,7 +177,7 @@ describe('Identity', () => {
177
177
  type: 'instantLock'
178
178
  }
179
179
  });
180
- identityTopUpTransaction.signByPrivateKey(assetLockPrivateKey, undefined, 0 /* KeyType.ECDSA_SECP256K1 */);
180
+ identityTopUpTransaction.signByPrivateKey(assetLockPrivateKey, undefined, KeyType.ECDSA_SECP256K1);
181
181
  });
182
182
  test('should be able to create IdentityTopUpTransition via ChainLock', async () => {
183
183
  const txid = '61aede830477254876d435a317241ad46753c4b1350dc991a45ebcf19ab80a11';
@@ -194,7 +194,7 @@ describe('Identity', () => {
194
194
  type: 'chainLock'
195
195
  }
196
196
  });
197
- identityTopUpTransaction.signByPrivateKey(assetLockPrivateKey, undefined, 0 /* KeyType.ECDSA_SECP256K1 */);
197
+ identityTopUpTransaction.signByPrivateKey(assetLockPrivateKey, undefined, KeyType.ECDSA_SECP256K1);
198
198
  });
199
199
  test('should be able to create IdentityUpdateTransition', async () => {
200
200
  const identityId = 'HT3pUBM1Uv2mKgdPEN1gxa7A4PdsvNY89aJbdSKQb5wR';
@@ -207,9 +207,9 @@ describe('Identity', () => {
207
207
  const identityPrivateKey = PrivateKeyWASM.fromHex('16f614c6242580628d849e3616491dda1eccce99642a85667eb9a364dc85324a', 'testnet');
208
208
  const identityPublicKeyInCreation = {
209
209
  id: keyId,
210
- purpose: 0 /* Purpose.AUTHENTICATION */,
211
- securityLevel: 2 /* SecurityLevel.HIGH */,
212
- keyType: 0 /* KeyType.ECDSA_SECP256K1 */,
210
+ purpose: Purpose.AUTHENTICATION,
211
+ securityLevel: SecurityLevel.HIGH,
212
+ keyType: KeyType.ECDSA_SECP256K1,
213
213
  readOnly: false,
214
214
  data: identityPrivateKey.getPublicKey().bytes()
215
215
  };
@@ -219,7 +219,7 @@ describe('Identity', () => {
219
219
  identityNonce,
220
220
  addPublicKeys: [identityPublicKeyInCreation]
221
221
  });
222
- identityUpdateTransition.signByPrivateKey(masterPrivateKey, masterKeyId, 0 /* KeyType.ECDSA_SECP256K1 */);
222
+ identityUpdateTransition.signByPrivateKey(masterPrivateKey, masterKeyId, KeyType.ECDSA_SECP256K1);
223
223
  identityPublicKeyInCreation.signature = identityUpdateTransition.signature;
224
224
  identityUpdateTransition = sdk.identities.createStateTransition('update', {
225
225
  identityId,
@@ -227,7 +227,7 @@ describe('Identity', () => {
227
227
  identityNonce,
228
228
  addPublicKeys: [identityPublicKeyInCreation]
229
229
  });
230
- identityUpdateTransition.signByPrivateKey(masterPrivateKey, masterKeyId, 0 /* KeyType.ECDSA_SECP256K1 */);
230
+ identityUpdateTransition.signByPrivateKey(masterPrivateKey, masterKeyId, KeyType.ECDSA_SECP256K1);
231
231
  });
232
232
  test('should able be create credit transfer transition', async () => {
233
233
  const identityId = 'QMfCRPcjXoTnZa9sA9JR2KWgGxZXMRJ4akgS3Uia1Qv';
@@ -1,3 +1,4 @@
1
+ import { OrchardAddressWASM } from 'pshenmic-dpp';
1
2
  import { DashPlatformSDK } from '../../src/DashPlatformSDK.js';
2
3
  let sdk;
3
4
  let mnemonic;
@@ -31,4 +32,35 @@ describe('KeyPair', () => {
31
32
  expect(key.privateKey).toEqual(Uint8Array.from([89, 255, 64, 41, 202, 170, 83, 68, 135, 58, 161, 107, 130, 20, 3, 50, 69, 16, 108, 104, 32, 68, 13, 100, 225, 24, 79, 20, 193, 184, 238, 55]));
32
33
  });
33
34
  });
35
+ describe('shielded', () => {
36
+ const account = 0;
37
+ test('should be able to derive a shielded address from seed', () => {
38
+ const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
39
+ const address = sdk.keyPair.deriveShieldedAddress(seed, 'testnet', account);
40
+ expect(address).toEqual(expect.any(OrchardAddressWASM));
41
+ expect(address.bytes()).toHaveLength(43);
42
+ // deterministic for the same seed/network/account
43
+ expect(address.bytes()).toEqual(sdk.keyPair.deriveShieldedAddress(seed, 'testnet', account).bytes());
44
+ });
45
+ test('should derive distinct shielded addresses per diversifier index', () => {
46
+ const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
47
+ const first = sdk.keyPair.deriveShieldedAddress(seed, 'testnet', account, 0);
48
+ const second = sdk.keyPair.deriveShieldedAddress(seed, 'testnet', account, 1);
49
+ expect(first.bytes()).not.toEqual(second.bytes());
50
+ });
51
+ test('should derive distinct shielded addresses per network', () => {
52
+ const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
53
+ const mainnet = sdk.keyPair.deriveShieldedAddress(seed, 'mainnet', account);
54
+ const testnet = sdk.keyPair.deriveShieldedAddress(seed, 'testnet', account);
55
+ expect(mainnet.bytes()).not.toEqual(testnet.bytes());
56
+ });
57
+ test('should be able to derive the outgoing viewing key from seed', () => {
58
+ const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
59
+ const ovk = sdk.keyPair.deriveShieldedOutgoingViewingKey(seed, 'testnet', account);
60
+ expect(ovk).toBeInstanceOf(Uint8Array);
61
+ expect(ovk).toHaveLength(32);
62
+ // deterministic for the same seed/network/account
63
+ expect(ovk).toEqual(sdk.keyPair.deriveShieldedOutgoingViewingKey(seed, 'testnet', account));
64
+ });
65
+ });
34
66
  });
@@ -5,16 +5,16 @@ describe('PlatformAddress', () => {
5
5
  sdk = new DashPlatformSDK({ network: 'testnet' });
6
6
  });
7
7
  test('getAddressInfo', async () => {
8
- const info = await sdk.platformAddresses.getAddressInfo('tdashevo1qpgz9hk6tkn5zj3653s8qkjmk9439qkf0gl4yxxw');
8
+ const info = await sdk.platformAddresses.getAddressInfo('tdash1kzg5azscav69z7m6dfzr9ner0a5vt7pn9ca4sz8d');
9
9
  expect(info.balance).toBeDefined();
10
10
  expect(info.nonce).toBeDefined();
11
11
  expect(info.address).toBeDefined();
12
12
  });
13
13
  test('getAddressesInfos', async () => {
14
14
  const addresses = [
15
- 'tdashevo1qpgz9hk6tkn5zj3653s8qkjmk9439qkf0gl4yxxw',
16
- 'tdashevo1qq79z66rh34l4u2axlz3jv34zwshggnenut9k093',
17
- 'tdashevo1qpwyg4khd0rh8px5cjphv9wx38psl6hma5krg9gk'
15
+ 'tdash1kzg5azscav69z7m6dfzr9ner0a5vt7pn9ca4sz8d',
16
+ 'tdash1kqr3cxhgel75ru0yrhj5eq8j8jt92m5enqrfajxw',
17
+ 'tdash1kq9plfyacx9q26dtaxgwuw9lt78nyu2mzc3xwcxv'
18
18
  ];
19
19
  const info = await sdk.platformAddresses.getAddressesInfos(addresses);
20
20
  expect(info).toHaveLength(addresses.length);
@@ -0,0 +1 @@
1
+ export {};