dash-platform-sdk 1.4.0 → 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 (33) hide show
  1. package/README.md +15 -15
  2. package/bundle.min.js +17 -17
  3. package/package.json +2 -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 +1 -0
  11. package/src/constants.js +1 -0
  12. package/src/keyPair/index.d.ts +25 -0
  13. package/src/keyPair/index.js +33 -0
  14. package/src/shielded/createStateTransition.d.ts +3 -0
  15. package/src/shielded/createStateTransition.js +55 -0
  16. package/src/shielded/getMostRecentShieldedAnchor.d.ts +2 -0
  17. package/src/shielded/getMostRecentShieldedAnchor.js +36 -0
  18. package/src/shielded/getShieldedAnchors.d.ts +2 -0
  19. package/src/shielded/getShieldedAnchors.js +36 -0
  20. package/src/shielded/getShieldedEncryptedNotes.d.ts +3 -0
  21. package/src/shielded/getShieldedEncryptedNotes.js +43 -0
  22. package/src/shielded/getShieldedNotesCount.d.ts +2 -0
  23. package/src/shielded/getShieldedNotesCount.js +36 -0
  24. package/src/shielded/getShieldedNullifiers.d.ts +3 -0
  25. package/src/shielded/getShieldedNullifiers.js +40 -0
  26. package/src/shielded/getShieldedPoolState.d.ts +2 -0
  27. package/src/shielded/getShieldedPoolState.js +36 -0
  28. package/src/shielded/index.d.ts +130 -0
  29. package/src/shielded/index.js +186 -0
  30. package/test/unit/KeyPair.spec.js +32 -0
  31. package/test/unit/Shielded.spec.d.ts +1 -0
  32. package/test/unit/Shielded.spec.js +236 -0
  33. package/types.d.ts +85 -1
@@ -12,6 +12,7 @@ import { TokensController } from './tokens/index.js';
12
12
  import { VotingController } from './voting/index.js';
13
13
  import { Network } from '../types.js';
14
14
  import { PlatformAddressesController } from './platformAddresses/index.js';
15
+ import { ShieldedController } from './shielded/index.js';
15
16
  export interface GRPCOptions {
16
17
  poolLimit: 5;
17
18
  dapiUrl?: string | string[];
@@ -33,6 +34,7 @@ export declare class DashPlatformSDK {
33
34
  options?: SDKOptions;
34
35
  contestedResources: ContestedResourcesController;
35
36
  platformAddresses: PlatformAddressesController;
37
+ shielded: ShieldedController;
36
38
  stateTransitions: StateTransitionsController;
37
39
  dataContracts: DataContractsController;
38
40
  identities: IdentitiesController;
@@ -11,6 +11,7 @@ import { ContestedResourcesController } from './contestedResources/index.js';
11
11
  import { TokensController } from './tokens/index.js';
12
12
  import { VotingController } from './voting/index.js';
13
13
  import { PlatformAddressesController } from './platformAddresses/index.js';
14
+ import { ShieldedController } from './shielded/index.js';
14
15
  /**
15
16
  * Javascript SDK for that let you interact with a Dash Platform blockchain
16
17
  */
@@ -22,6 +23,7 @@ export class DashPlatformSDK {
22
23
  options;
23
24
  contestedResources;
24
25
  platformAddresses;
26
+ shielded;
25
27
  stateTransitions;
26
28
  dataContracts;
27
29
  identities;
@@ -65,6 +67,7 @@ export class DashPlatformSDK {
65
67
  this.grpcPool = grpcPool;
66
68
  this.contestedResources = new ContestedResourcesController(grpcPool);
67
69
  this.platformAddresses = new PlatformAddressesController(grpcPool);
70
+ this.shielded = new ShieldedController(grpcPool);
68
71
  this.stateTransitions = new StateTransitionsController(grpcPool);
69
72
  this.dataContracts = new DataContractsController(grpcPool);
70
73
  this.identities = new IdentitiesController(grpcPool);
@@ -3,6 +3,7 @@ import { PlatformVersionWASM } from 'pshenmic-dpp';
3
3
  * Default amount of documents to retrieve from DAPI
4
4
  */
5
5
  export declare const DAPI_DEFAULT_LIMIT = 100;
6
+ export declare const SHIELDED_MAX_NOTES_PER_QUERY = 8192;
6
7
  export declare const HALVING_INTERVAL = 210240;
7
8
  export declare const TESTNET_ACTIVATION_HEIGHT = 1066900;
8
9
  export declare const MAINNET_ACTIVATION_HEIGHT = 2128896;
package/src/constants.js CHANGED
@@ -3,6 +3,7 @@ import { PlatformVersionWASM } from 'pshenmic-dpp';
3
3
  * Default amount of documents to retrieve from DAPI
4
4
  */
5
5
  export const DAPI_DEFAULT_LIMIT = 100;
6
+ export const SHIELDED_MAX_NOTES_PER_QUERY = 8192;
6
7
  export const HALVING_INTERVAL = 210240;
7
8
  export const TESTNET_ACTIVATION_HEIGHT = 1066900;
8
9
  export const MAINNET_ACTIVATION_HEIGHT = 2128896;
@@ -1,5 +1,6 @@
1
1
  import { HDKey } from '@scure/bip32';
2
2
  import { Network } from '../../types.js';
3
+ import { OrchardAddressWASM } from 'pshenmic-dpp';
3
4
  /**
4
5
  * Collection of functions to work with private keys and seed phrases
5
6
  *
@@ -64,4 +65,28 @@ export declare class KeyPairController {
64
65
  * @returns {string}
65
66
  */
66
67
  p2pkhAddress(publicKey: Uint8Array, network: Network): string;
68
+ /**
69
+ * Derives a shielded (Orchard) address from a BIP-39 seed via ZIP-32
70
+ * (m/32'/coinType'/account').
71
+ *
72
+ * @param seed {Uint8Array} - BIP-39 seed bytes
73
+ * @param network {Network} - network (selects the SLIP-44 coin type)
74
+ * @param account {number} - ZIP-32 account index
75
+ * @param diversifierIndex {number=} - optional diversifier index
76
+ *
77
+ * @returns {OrchardAddressWASM}
78
+ */
79
+ deriveShieldedAddress(seed: Uint8Array, network: Network, account: number, diversifierIndex?: number): OrchardAddressWASM;
80
+ /**
81
+ * Derives the sender's Orchard outgoing viewing key (OVK, 32 bytes) from a
82
+ * BIP-39 seed via ZIP-32 (m/32'/coinType'/account'). Used to recover the
83
+ * outgoing notes a wallet sent.
84
+ *
85
+ * @param seed {Uint8Array} - BIP-39 seed bytes
86
+ * @param network {Network} - network (selects the SLIP-44 coin type)
87
+ * @param account {number} - ZIP-32 account index
88
+ *
89
+ * @returns {Uint8Array} 32-byte outgoing viewing key
90
+ */
91
+ deriveShieldedOutgoingViewingKey(seed: Uint8Array, network: Network, account: number): Uint8Array;
67
92
  }
@@ -3,6 +3,7 @@ import mnemonicToSeed from './mnemonicToSeed.js';
3
3
  import deriveChild from './deriveChild.js';
4
4
  import derivePath from './derivePath.js';
5
5
  import { p2pkh } from '@scure/btc-signer';
6
+ import { OrchardAddressWASM, orchardOvkFromSeed } from 'pshenmic-dpp';
6
7
  const DASH_VERSIONS = {
7
8
  mainnet: { pubKeyHash: 0x4c, scriptHash: 0x10, bech32: 'dc', wif: 0xcc, private: 0x0488ade4, public: 0x0488b21e },
8
9
  testnet: { pubKeyHash: 0x8c, scriptHash: 0x13, bech32: 'dc', wif: 0xef, private: 0x04358394, public: 0x043587cf }
@@ -86,4 +87,36 @@ export class KeyPairController {
86
87
  const P2PKH = p2pkh(publicKey, DASH_VERSIONS[network]);
87
88
  return P2PKH.address;
88
89
  }
90
+ /**
91
+ * Derives a shielded (Orchard) address from a BIP-39 seed via ZIP-32
92
+ * (m/32'/coinType'/account').
93
+ *
94
+ * @param seed {Uint8Array} - BIP-39 seed bytes
95
+ * @param network {Network} - network (selects the SLIP-44 coin type)
96
+ * @param account {number} - ZIP-32 account index
97
+ * @param diversifierIndex {number=} - optional diversifier index
98
+ *
99
+ * @returns {OrchardAddressWASM}
100
+ */
101
+ deriveShieldedAddress(seed, network, account, diversifierIndex) {
102
+ // SLIP-44 coin type: 5 = Dash mainnet, 1 = testnets. Orchard derives via ZIP-32
103
+ const coinType = network === 'mainnet' ? 5 : 1;
104
+ return OrchardAddressWASM.fromSeed(seed, coinType, account, diversifierIndex);
105
+ }
106
+ /**
107
+ * Derives the sender's Orchard outgoing viewing key (OVK, 32 bytes) from a
108
+ * BIP-39 seed via ZIP-32 (m/32'/coinType'/account'). Used to recover the
109
+ * outgoing notes a wallet sent.
110
+ *
111
+ * @param seed {Uint8Array} - BIP-39 seed bytes
112
+ * @param network {Network} - network (selects the SLIP-44 coin type)
113
+ * @param account {number} - ZIP-32 account index
114
+ *
115
+ * @returns {Uint8Array} 32-byte outgoing viewing key
116
+ */
117
+ deriveShieldedOutgoingViewingKey(seed, network, account) {
118
+ // SLIP-44 coin type: 5 = Dash mainnet, 1 = testnets. Orchard derives via ZIP-32
119
+ const coinType = network === 'mainnet' ? 5 : 1;
120
+ return orchardOvkFromSeed(seed, coinType, account);
121
+ }
89
122
  }
@@ -0,0 +1,3 @@
1
+ import { ShieldedBuilderWASM, StateTransitionWASM } from 'pshenmic-dpp';
2
+ import { ShieldedTransitionParamsMap, ShieldedTransitionType } from '../../types.js';
3
+ export default function createStateTransition<K extends ShieldedTransitionType>(builder: ShieldedBuilderWASM, type: K, params: ShieldedTransitionParamsMap[K]): StateTransitionWASM;
@@ -0,0 +1,55 @@
1
+ import { IdentityCreateFromShieldedPoolTransitionWASM, ShieldedBuilderWASM, ShieldedWithdrawalResultWASM, StateTransitionWASM } from 'pshenmic-dpp';
2
+ import { LATEST_PLATFORM_VERSION } from '../constants.js';
3
+ const shieldedTransitionsMap = {
4
+ shield: {
5
+ method: ShieldedBuilderWASM.prototype.shield,
6
+ arguments: ['recipient', 'shieldAmount', 'inputs', 'privateKeys', 'feeStrategy', 'userFeeIncrease', 'memo'],
7
+ optionalArguments: ['senderOvk']
8
+ },
9
+ shieldFromAssetLock: {
10
+ method: ShieldedBuilderWASM.prototype.shieldFromAssetLock,
11
+ arguments: ['recipient', 'shieldAmount', 'assetLockProof', 'privateKey', 'memo', 'dummyOutputs'],
12
+ optionalArguments: ['senderOvk', 'surplusOutput']
13
+ },
14
+ shieldedWithdrawal: {
15
+ method: ShieldedBuilderWASM.prototype.shieldedWithdrawal,
16
+ arguments: ['spends', 'withdrawalAmount', 'outputScript', 'coreFeePerByte', 'pooling', 'changeAddress', 'seed', 'coinType', 'account', 'anchor', 'memo'],
17
+ optionalArguments: []
18
+ },
19
+ unshield: {
20
+ method: ShieldedBuilderWASM.prototype.unshield,
21
+ arguments: ['spends', 'outputAddress', 'unshieldAmount', 'changeAddress', 'seed', 'coinType', 'account', 'anchor', 'memo'],
22
+ optionalArguments: []
23
+ },
24
+ shieldedTransfer: {
25
+ method: ShieldedBuilderWASM.prototype.shieldedTransfer,
26
+ arguments: ['spends', 'recipient', 'transferAmount', 'changeAddress', 'seed', 'coinType', 'account', 'anchor', 'memo'],
27
+ optionalArguments: []
28
+ },
29
+ identityCreateFromShieldedPool: {
30
+ method: ShieldedBuilderWASM.prototype.identityCreateFromShieldedPool,
31
+ arguments: ['publicKeys', 'privateKeys', 'denomination', 'sendToAddressOnCreationFailure', 'spends', 'changeAddress', 'seed', 'coinType', 'account', 'anchor', 'memo'],
32
+ optionalArguments: []
33
+ }
34
+ };
35
+ export default function createStateTransition(builder, type, params) {
36
+ const { method: builderMethod, arguments: classArguments, optionalArguments } = shieldedTransitionsMap[type];
37
+ if (builderMethod == null) {
38
+ throw new Error(`Unimplemented shielded transition type: ${type}`);
39
+ }
40
+ const [missingArgument] = classArguments
41
+ .filter((classArgument) => params[classArgument] == null);
42
+ if (missingArgument != null) {
43
+ throw new Error(`Shielded transition param "${missingArgument}" is missing`);
44
+ }
45
+ const transitionParams = classArguments.concat(optionalArguments).map((classArgument) => params[classArgument]);
46
+ const result = builderMethod.apply(builder, [...transitionParams, params.platformVersion ?? LATEST_PLATFORM_VERSION]);
47
+ if (result instanceof StateTransitionWASM) {
48
+ return result;
49
+ }
50
+ if (result instanceof ShieldedWithdrawalResultWASM) {
51
+ return result.stateTransition;
52
+ }
53
+ const { denomination, sendToAddressOnCreationFailure } = params;
54
+ return new IdentityCreateFromShieldedPoolTransitionWASM(result.publicKeys, denomination, result.actions, result.anchor, result.proof, result.bindingsSignature, sendToAddressOnCreationFailure, result.identityId).toStateTransition();
55
+ }
@@ -0,0 +1,2 @@
1
+ import GRPCConnectionPool from '../grpcConnectionPool.js';
2
+ export default function getMostRecentShieldedAnchor(grpcPool: GRPCConnectionPool): Promise<Uint8Array | undefined>;
@@ -0,0 +1,36 @@
1
+ import { GetMostRecentShieldedAnchorRequest } from '../../proto/generated/platform.js';
2
+ import { verifyMostRecentShieldedAnchorProof } from "pshenmic-dpp";
3
+ import { LATEST_PLATFORM_VERSION } from "../constants.js";
4
+ import { getQuorumPublicKey } from "../utils/getQuorumPublicKey.js";
5
+ import bytesToHex from "../utils/bytesToHex.js";
6
+ import verifyTenderdashProof from "../utils/verifyTenderdashProof.js";
7
+ export default async function getMostRecentShieldedAnchor(grpcPool) {
8
+ const getMostRecentShieldedAnchorRequest = GetMostRecentShieldedAnchorRequest.create({
9
+ version: {
10
+ oneofKind: 'v0',
11
+ v0: {
12
+ prove: true
13
+ }
14
+ }
15
+ });
16
+ const { response } = await grpcPool.getClient().getMostRecentShieldedAnchor(getMostRecentShieldedAnchorRequest);
17
+ const { version } = response;
18
+ if (version.oneofKind !== 'v0') {
19
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
20
+ }
21
+ const { v0 } = version;
22
+ if (v0.result.oneofKind !== 'proof') {
23
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
24
+ }
25
+ const { result: { proof }, metadata } = v0;
26
+ if (metadata == null) {
27
+ throw new Error('Metadata not found');
28
+ }
29
+ const { rootHash, anchor } = verifyMostRecentShieldedAnchorProof(proof.grovedbProof, true, LATEST_PLATFORM_VERSION);
30
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
31
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
32
+ if (!verify) {
33
+ throw new Error('Failed to verify query');
34
+ }
35
+ return anchor;
36
+ }
@@ -0,0 +1,2 @@
1
+ import GRPCConnectionPool from '../grpcConnectionPool.js';
2
+ export default function getShieldedAnchors(grpcPool: GRPCConnectionPool): Promise<Uint8Array[]>;
@@ -0,0 +1,36 @@
1
+ import { GetShieldedAnchorsRequest } from '../../proto/generated/platform.js';
2
+ import { verifyShieldedAnchorsProof } from "pshenmic-dpp";
3
+ import { LATEST_PLATFORM_VERSION } from "../constants.js";
4
+ import { getQuorumPublicKey } from "../utils/getQuorumPublicKey.js";
5
+ import bytesToHex from "../utils/bytesToHex.js";
6
+ import verifyTenderdashProof from "../utils/verifyTenderdashProof.js";
7
+ export default async function getShieldedAnchors(grpcPool) {
8
+ const getShieldedAnchorsRequest = GetShieldedAnchorsRequest.create({
9
+ version: {
10
+ oneofKind: 'v0',
11
+ v0: {
12
+ prove: true
13
+ }
14
+ }
15
+ });
16
+ const { response } = await grpcPool.getClient().getShieldedAnchors(getShieldedAnchorsRequest);
17
+ const { version } = response;
18
+ if (version.oneofKind !== 'v0') {
19
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
20
+ }
21
+ const { v0 } = version;
22
+ if (v0.result.oneofKind !== 'proof') {
23
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
24
+ }
25
+ const { result: { proof }, metadata } = v0;
26
+ if (metadata == null) {
27
+ throw new Error('Metadata not found');
28
+ }
29
+ const { rootHash, anchors } = verifyShieldedAnchorsProof(proof.grovedbProof, true, LATEST_PLATFORM_VERSION);
30
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
31
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
32
+ if (!verify) {
33
+ throw new Error('Failed to verify query');
34
+ }
35
+ return anchors;
36
+ }
@@ -0,0 +1,3 @@
1
+ import GRPCConnectionPool from '../grpcConnectionPool.js';
2
+ import { ShieldedEncryptedNote } from '../../types.js';
3
+ export default function getShieldedEncryptedNotes(grpcPool: GRPCConnectionPool, startIndex: bigint, count: number): Promise<ShieldedEncryptedNote[]>;
@@ -0,0 +1,43 @@
1
+ import { GetShieldedEncryptedNotesRequest } from '../../proto/generated/platform.js';
2
+ import { verifyShieldedEncryptedNotesProof } from "pshenmic-dpp";
3
+ import { LATEST_PLATFORM_VERSION, SHIELDED_MAX_NOTES_PER_QUERY } from "../constants.js";
4
+ import { getQuorumPublicKey } from "../utils/getQuorumPublicKey.js";
5
+ import bytesToHex from "../utils/bytesToHex.js";
6
+ import verifyTenderdashProof from "../utils/verifyTenderdashProof.js";
7
+ export default async function getShieldedEncryptedNotes(grpcPool, startIndex, count) {
8
+ const getShieldedEncryptedNotesRequest = GetShieldedEncryptedNotesRequest.create({
9
+ version: {
10
+ oneofKind: 'v0',
11
+ v0: {
12
+ startIndex: startIndex.toString(),
13
+ count,
14
+ prove: true
15
+ }
16
+ }
17
+ });
18
+ const { response } = await grpcPool.getClient().getShieldedEncryptedNotes(getShieldedEncryptedNotesRequest);
19
+ const { version } = response;
20
+ if (version.oneofKind !== 'v0') {
21
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
22
+ }
23
+ const { v0 } = version;
24
+ if (v0.result.oneofKind !== 'proof') {
25
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
26
+ }
27
+ const { result: { proof }, metadata } = v0;
28
+ if (metadata == null) {
29
+ throw new Error('Metadata not found');
30
+ }
31
+ const { rootHash, notes } = verifyShieldedEncryptedNotesProof(proof.grovedbProof, startIndex, count, SHIELDED_MAX_NOTES_PER_QUERY, true, LATEST_PLATFORM_VERSION);
32
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
33
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
34
+ if (!verify) {
35
+ throw new Error('Failed to verify query');
36
+ }
37
+ return notes.map(note => ({
38
+ nullifier: note.nullifier,
39
+ cmx: note.cmx,
40
+ encryptedNote: note.encryptedNote,
41
+ cvNet: note.cvNet
42
+ }));
43
+ }
@@ -0,0 +1,2 @@
1
+ import GRPCConnectionPool from '../grpcConnectionPool.js';
2
+ export default function getShieldedNotesCount(grpcPool: GRPCConnectionPool): Promise<bigint | undefined>;
@@ -0,0 +1,36 @@
1
+ import { GetShieldedNotesCountRequest } from '../../proto/generated/platform.js';
2
+ import { verifyShieldedNotesCountProof } from "pshenmic-dpp";
3
+ import { LATEST_PLATFORM_VERSION } from "../constants.js";
4
+ import { getQuorumPublicKey } from "../utils/getQuorumPublicKey.js";
5
+ import bytesToHex from "../utils/bytesToHex.js";
6
+ import verifyTenderdashProof from "../utils/verifyTenderdashProof.js";
7
+ export default async function getShieldedNotesCount(grpcPool) {
8
+ const getShieldedNotesCountRequest = GetShieldedNotesCountRequest.create({
9
+ version: {
10
+ oneofKind: 'v0',
11
+ v0: {
12
+ prove: true
13
+ }
14
+ }
15
+ });
16
+ const { response } = await grpcPool.getClient().getShieldedNotesCount(getShieldedNotesCountRequest);
17
+ const { version } = response;
18
+ if (version.oneofKind !== 'v0') {
19
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
20
+ }
21
+ const { v0 } = version;
22
+ if (v0.result.oneofKind !== 'proof') {
23
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
24
+ }
25
+ const { result: { proof }, metadata } = v0;
26
+ if (metadata == null) {
27
+ throw new Error('Metadata not found');
28
+ }
29
+ const { rootHash, count } = verifyShieldedNotesCountProof(proof.grovedbProof, true, LATEST_PLATFORM_VERSION);
30
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
31
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
32
+ if (!verify) {
33
+ throw new Error('Failed to verify query');
34
+ }
35
+ return count;
36
+ }
@@ -0,0 +1,3 @@
1
+ import GRPCConnectionPool from '../grpcConnectionPool.js';
2
+ import { ShieldedNullifierStatus } from '../../types.js';
3
+ export default function getShieldedNullifiers(grpcPool: GRPCConnectionPool, nullifiers: Uint8Array[]): Promise<ShieldedNullifierStatus[]>;
@@ -0,0 +1,40 @@
1
+ import { GetShieldedNullifiersRequest } from '../../proto/generated/platform.js';
2
+ import { verifyShieldedNullifiersProof } from "pshenmic-dpp";
3
+ import { LATEST_PLATFORM_VERSION } from "../constants.js";
4
+ import { getQuorumPublicKey } from "../utils/getQuorumPublicKey.js";
5
+ import bytesToHex from "../utils/bytesToHex.js";
6
+ import verifyTenderdashProof from "../utils/verifyTenderdashProof.js";
7
+ export default async function getShieldedNullifiers(grpcPool, nullifiers) {
8
+ const getShieldedNullifiersRequest = GetShieldedNullifiersRequest.create({
9
+ version: {
10
+ oneofKind: 'v0',
11
+ v0: {
12
+ nullifiers,
13
+ prove: true
14
+ }
15
+ }
16
+ });
17
+ const { response } = await grpcPool.getClient().getShieldedNullifiers(getShieldedNullifiersRequest);
18
+ const { version } = response;
19
+ if (version.oneofKind !== 'v0') {
20
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
21
+ }
22
+ const { v0 } = version;
23
+ if (v0.result.oneofKind !== 'proof') {
24
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
25
+ }
26
+ const { result: { proof }, metadata } = v0;
27
+ if (metadata == null) {
28
+ throw new Error('Metadata not found');
29
+ }
30
+ const { rootHash, nullifiers: nullifiersStatuses } = verifyShieldedNullifiersProof(proof.grovedbProof, nullifiers, true, LATEST_PLATFORM_VERSION);
31
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
32
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
33
+ if (!verify) {
34
+ throw new Error('Failed to verify query');
35
+ }
36
+ return nullifiersStatuses.map(entry => ({
37
+ nullifier: entry.nullifier,
38
+ isSpent: entry.isSpent
39
+ }));
40
+ }
@@ -0,0 +1,2 @@
1
+ import GRPCConnectionPool from '../grpcConnectionPool.js';
2
+ export default function getShieldedPoolState(grpcPool: GRPCConnectionPool): Promise<bigint | undefined>;
@@ -0,0 +1,36 @@
1
+ import { GetShieldedPoolStateRequest } from '../../proto/generated/platform.js';
2
+ import { getQuorumPublicKey } from "../utils/getQuorumPublicKey.js";
3
+ import bytesToHex from "../utils/bytesToHex.js";
4
+ import verifyTenderdashProof from "../utils/verifyTenderdashProof.js";
5
+ import { verifyShieldedPoolStateProof } from "pshenmic-dpp";
6
+ import { LATEST_PLATFORM_VERSION } from "../constants.js";
7
+ export default async function getShieldedPoolState(grpcPool) {
8
+ const getShieldedPoolStateRequest = GetShieldedPoolStateRequest.create({
9
+ version: {
10
+ oneofKind: 'v0',
11
+ v0: {
12
+ prove: true
13
+ }
14
+ }
15
+ });
16
+ const { response } = await grpcPool.getClient().getShieldedPoolState(getShieldedPoolStateRequest);
17
+ const { version } = response;
18
+ if (version.oneofKind !== 'v0') {
19
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
20
+ }
21
+ const { v0 } = version;
22
+ if (v0.result.oneofKind !== 'proof') {
23
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
24
+ }
25
+ const { result: { proof }, metadata } = v0;
26
+ if (metadata == null) {
27
+ throw new Error('Metadata not found');
28
+ }
29
+ const { rootHash, totalBalance } = verifyShieldedPoolStateProof(proof.grovedbProof, true, LATEST_PLATFORM_VERSION);
30
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
31
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
32
+ if (!verify) {
33
+ throw new Error('Failed to verify query');
34
+ }
35
+ return totalBalance;
36
+ }
@@ -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
+ }