dash-platform-sdk 1.3.0-dev.5 → 1.3.0-dev.6

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 (91) hide show
  1. package/bundle.min.js +17 -17
  2. package/index.js +2 -0
  3. package/package.json +4 -4
  4. package/proto/generated/google/protobuf/wrappers.js +615 -0
  5. package/proto/generated/platform.client.js +175 -0
  6. package/proto/generated/platform.js +8277 -0
  7. package/src/DashPlatformSDK.js +101 -0
  8. package/src/constants.js +10 -0
  9. package/src/contestedResources/createStateTransition.js +6 -0
  10. package/src/contestedResources/getContestedResourceVoteState.js +72 -0
  11. package/src/contestedResources/index.js +30 -0
  12. package/src/dataContracts/create.js +11 -0
  13. package/src/dataContracts/createStateTransition.js +19 -0
  14. package/src/dataContracts/getDataContractByIdentifier.js +44 -0
  15. package/src/dataContracts/index.js +57 -0
  16. package/src/documents/create.js +4 -0
  17. package/src/documents/createStateTransition.js +52 -0
  18. package/src/documents/index.js +83 -0
  19. package/src/documents/query.js +62 -0
  20. package/src/grpcConnectionPool.js +79 -0
  21. package/src/identities/createStateTransition.js +34 -0
  22. package/src/identities/getIdentityBalance.js +40 -0
  23. package/src/identities/getIdentityByIdentifier.js +40 -0
  24. package/src/identities/getIdentityByNonUniquePublicKeyHash.js +44 -0
  25. package/src/identities/getIdentityByPublicKeyHash.js +40 -0
  26. package/src/identities/getIdentityContractNonce.js +43 -0
  27. package/src/identities/getIdentityNonce.js +41 -0
  28. package/src/identities/getIdentityPublicKeys.js +47 -0
  29. package/src/identities/index.js +141 -0
  30. package/src/keyPair/deriveChild.js +3 -0
  31. package/src/keyPair/derivePath.js +3 -0
  32. package/src/keyPair/index.js +89 -0
  33. package/src/keyPair/mnemonicToSeed.js +4 -0
  34. package/src/names/index.js +102 -0
  35. package/src/names/registerName.js +64 -0
  36. package/src/names/searchByIdentity.js +5 -0
  37. package/src/names/searchByName.js +16 -0
  38. package/src/names/testNameContested.js +3 -0
  39. package/src/names/validateName.js +11 -0
  40. package/src/node/epochs.js +46 -0
  41. package/src/node/index.js +43 -0
  42. package/src/node/status.js +41 -0
  43. package/src/node/totalCredits.js +35 -0
  44. package/src/signer/AbstractSigner.js +1 -0
  45. package/src/signer/PrivateKeySigner.d.ts +0 -0
  46. package/src/signer/PrivateKeySigner.js +64 -0
  47. package/src/signer/setSigner.js +5 -0
  48. package/src/stateTransitions/broadcast.js +10 -0
  49. package/src/stateTransitions/index.js +34 -0
  50. package/src/stateTransitions/waitForStateTransitionResult.js +8 -0
  51. package/src/tokens/createStateTransition.js +67 -0
  52. package/src/tokens/getIdentitiesTokenBalances.js +43 -0
  53. package/src/tokens/getIdentityTokensBalances.js +43 -0
  54. package/src/tokens/getTokenContractInfo.js +43 -0
  55. package/src/tokens/getTokenDirectPurchasePrices.js +40 -0
  56. package/src/tokens/getTokenTotalSupply.js +41 -0
  57. package/src/tokens/index.js +108 -0
  58. package/src/types.js +15 -0
  59. package/src/utils/base58ToBytes.js +4 -0
  60. package/src/utils/bytesToHex.js +3 -0
  61. package/src/utils/bytesToTypedArray.js +3 -0
  62. package/src/utils/calculateMsgHash.js +31 -0
  63. package/src/utils/calculateSignHash.js +8 -0
  64. package/src/utils/calculateStateIdHash.js +10 -0
  65. package/src/utils/convertToHomographSafeChars.js +11 -0
  66. package/src/utils/createVoterIdentityId.js +13 -0
  67. package/src/utils/getEvonodeList.js +12 -0
  68. package/src/utils/getQuorumPublicKey.js +18 -0
  69. package/src/utils/getRandomArrayItem.js +3 -0
  70. package/src/utils/getRandomBytes.js +4 -0
  71. package/src/utils/hexToBytes.js +3 -0
  72. package/src/utils/index.js +61 -0
  73. package/src/utils/indexBytesToString.js +4 -0
  74. package/src/utils/sha256.js +15 -0
  75. package/src/utils/signHash.js +22 -0
  76. package/src/utils/signRequestId.js +19 -0
  77. package/src/utils/sleep.js +3 -0
  78. package/src/utils/stringToIndexValueBytes.js +10 -0
  79. package/src/utils/verifyTenderdashProof.js +26 -0
  80. package/src/voting/createStateTransition.js +6 -0
  81. package/src/voting/createVote.js +5 -0
  82. package/src/voting/index.js +55 -0
  83. package/test/unit/ContestedResources.spec.js +259 -0
  84. package/test/unit/DataContract.spec.js +75 -0
  85. package/test/unit/Document.spec.js +109 -0
  86. package/test/unit/Identity.spec.js +232 -0
  87. package/test/unit/KeyPair.spec.js +34 -0
  88. package/test/unit/Names.spec.js +33 -0
  89. package/test/unit/Node.spec.js +58 -0
  90. package/test/unit/SDK.spec.js +10 -0
  91. package/test/unit/Tokens.spec.js +121 -0
@@ -0,0 +1,101 @@
1
+ import GRPCConnectionPool from './grpcConnectionPool';
2
+ import { IdentitiesController } from './identities';
3
+ import { StateTransitionsController } from './stateTransitions';
4
+ import { DocumentsController } from './documents';
5
+ import { UtilsController } from './utils';
6
+ import { KeyPairController } from './keyPair';
7
+ import { NodeController } from './node';
8
+ import { NamesController } from './names';
9
+ import { DataContractsController } from './dataContracts';
10
+ import { ContestedResourcesController } from './contestedResources';
11
+ import { TokensController } from './tokens';
12
+ import { VotingController } from './voting';
13
+ /**
14
+ * Javascript SDK for that let you interact with a Dash Platform blockchain
15
+ */
16
+ export class DashPlatformSDK {
17
+ network;
18
+ /** @ignore **/
19
+ grpcPool;
20
+ /** @ignore **/
21
+ options;
22
+ contestedResources;
23
+ stateTransitions;
24
+ dataContracts;
25
+ identities;
26
+ documents;
27
+ keyPair;
28
+ voting;
29
+ tokens;
30
+ utils;
31
+ names;
32
+ signer;
33
+ node;
34
+ /**
35
+ * Constructs a new DashPlatformSDK instance, optionally pass options
36
+ * if you want to configure the SDK instance (network, dapiUrl, signer)
37
+ *
38
+ * @param options {SDKOptions=}
39
+ */
40
+ constructor(options) {
41
+ if (options != null && (options.network == null || !['testnet', 'mainnet'].includes(options.network))) {
42
+ throw new Error('If options is passed, network must be set (either mainnet or testnet)');
43
+ }
44
+ this.network = options?.network ?? 'mainnet';
45
+ this.signer = options?.signer;
46
+ this.options = options;
47
+ this.utils = new UtilsController();
48
+ // Compatibility
49
+ if (options?.dapiUrl != null && ((options?.grpc) == null)) {
50
+ // @ts-expect-error
51
+ this.options.grpc = { dapiUrl: options.dapiUrl };
52
+ }
53
+ this.grpcPool = new GRPCConnectionPool(this.network, this.options?.grpc);
54
+ this._initialize(this.grpcPool, this.network);
55
+ }
56
+ /**
57
+ * @private
58
+ *
59
+ * Internal function to initialize SDK GRPC connection pool. Is not meant to be used outside the SDK
60
+ *
61
+ * @param grpcPool
62
+ * @param network
63
+ */
64
+ _initialize(grpcPool, network) {
65
+ this.grpcPool = grpcPool;
66
+ this.stateTransitions = new StateTransitionsController(grpcPool);
67
+ this.contestedResources = new ContestedResourcesController(grpcPool);
68
+ this.dataContracts = new DataContractsController(grpcPool);
69
+ this.identities = new IdentitiesController(grpcPool);
70
+ this.documents = new DocumentsController(grpcPool);
71
+ this.voting = new VotingController();
72
+ this.node = new NodeController(grpcPool, network);
73
+ this.tokens = new TokensController(grpcPool);
74
+ this.names = new NamesController(grpcPool);
75
+ this.keyPair = new KeyPairController();
76
+ }
77
+ setSigner(signer) {
78
+ this.signer = signer;
79
+ }
80
+ /**
81
+ * Get currently used network
82
+ *
83
+ * @return {string}
84
+ */
85
+ getNetwork() {
86
+ return this.network;
87
+ }
88
+ /**
89
+ * Switches a network that SDK is currently connected to
90
+ *
91
+ * @param network {string}
92
+ */
93
+ setNetwork(network) {
94
+ if (network !== 'testnet' && network !== 'mainnet') {
95
+ throw new Error('Unknown network, should be mainnet or testnet');
96
+ }
97
+ this.network = network;
98
+ const grpcPool = new GRPCConnectionPool(this.network, this.options?.grpc);
99
+ this._initialize(grpcPool, this.network);
100
+ }
101
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Default amount of documents to retrieve from DAPI
3
+ */
4
+ export const DAPI_DEFAULT_LIMIT = 100;
5
+ export const HALVING_INTERVAL = 210240;
6
+ export const TESTNET_ACTIVATION_HEIGHT = 1066900;
7
+ export const MAINNET_ACTIVATION_HEIGHT = 2128896;
8
+ export const GRPC_DEFAULT_POOL_LIMIT = 5;
9
+ export const DPNS_DATA_CONTRACT_ID = 'GWRSAVFMjXx8HpQFaNJMqBV7MBgMK4br5UESsB4S31Ec';
10
+ export const DPNS_DATA_CONTRACT_BYTES = 'AeZoxlmvZq7h5ywYbd57W34KHXEqCcQNVyH2Ir9TxTFVAAAAAAABAQAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIGZG9tYWluFgsSEGRvY3VtZW50c011dGFibGUTABIMY2FuQmVEZWxldGVkEwESDHRyYW5zZmVyYWJsZQIBEgl0cmFkZU1vZGUCARIEdHlwZRIGb2JqZWN0EgdpbmRpY2VzFQIWBBIEbmFtZRIScGFyZW50TmFtZUFuZExhYmVsEgpwcm9wZXJ0aWVzFQIWARIabm9ybWFsaXplZFBhcmVudERvbWFpbk5hbWUSA2FzYxYBEg9ub3JtYWxpemVkTGFiZWwSA2FzYxIGdW5pcXVlEwESCWNvbnRlc3RlZBYDEgxmaWVsZE1hdGNoZXMVARYCEgVmaWVsZBIPbm9ybWFsaXplZExhYmVsEgxyZWdleFBhdHRlcm4SE15bYS16QS1aMDEtXXszLDE5fSQSCnJlc29sdXRpb24CABILZGVzY3JpcHRpb24SqklmIHRoZSBub3JtYWxpemVkIGxhYmVsIHBhcnQgb2YgdGhpcyBpbmRleCBpcyBsZXNzIHRoYW4gMjAgY2hhcmFjdGVycyAoYWxsIGFscGhhYmV0IGEteiwgQS1aLCAwLCAxLCBhbmQgLSkgdGhlbiBhIG1hc3Rlcm5vZGUgdm90ZSBjb250ZXN0IHRha2VzIHBsYWNlIHRvIGdpdmUgb3V0IHRoZSBuYW1lFgMSBG5hbWUSCmlkZW50aXR5SWQSDm51bGxTZWFyY2hhYmxlEwASCnByb3BlcnRpZXMVARYBEhByZWNvcmRzLmlkZW50aXR5EgNhc2MSCnByb3BlcnRpZXMWBxIFbGFiZWwWBhIEdHlwZRIGc3RyaW5nEgdwYXR0ZXJuEipeW2EtekEtWjAtOV1bYS16QS1aMC05LV17MCw2MX1bYS16QS1aMC05XSQSCW1pbkxlbmd0aAIDEgltYXhMZW5ndGgCPxIIcG9zaXRpb24CABILZGVzY3JpcHRpb24SGURvbWFpbiBsYWJlbC4gZS5nLiAnQm9iJy4SD25vcm1hbGl6ZWRMYWJlbBYGEgR0eXBlEgZzdHJpbmcSB3BhdHRlcm4SPF5bYS1oai1rbS1ucC16MC05XVthLWhqLWttLW5wLXowLTktXXswLDYxfVthLWhqLWttLW5wLXowLTldJBIJbWF4TGVuZ3RoAj8SCHBvc2l0aW9uAgESC2Rlc2NyaXB0aW9uEqNEb21haW4gbGFiZWwgY29udmVydGVkIHRvIGxvd2VyY2FzZSBmb3IgY2FzZS1pbnNlbnNpdGl2ZSB1bmlxdWVuZXNzIHZhbGlkYXRpb24uICJvIiwgImkiIGFuZCAibCIgcmVwbGFjZWQgd2l0aCAiMCIgYW5kICIxIiB0byBtaXRpZ2F0ZSBob21vZ3JhcGggYXR0YWNrLiBlLmcuICdiMGInEggkY29tbWVudBJcTXVzdCBiZSBlcXVhbCB0byB0aGUgbGFiZWwgaW4gbG93ZXJjYXNlLiAibyIsICJpIiBhbmQgImwiIG11c3QgYmUgcmVwbGFjZWQgd2l0aCAiMCIgYW5kICIxIi4SEHBhcmVudERvbWFpbk5hbWUWBhIEdHlwZRIGc3RyaW5nEgdwYXR0ZXJuEi1eJHxeW2EtekEtWjAtOV1bYS16QS1aMC05LV17MCw2MX1bYS16QS1aMC05XSQSCW1pbkxlbmd0aAIAEgltYXhMZW5ndGgCPxIIcG9zaXRpb24CAhILZGVzY3JpcHRpb24SJ0EgZnVsbCBwYXJlbnQgZG9tYWluIG5hbWUuIGUuZy4gJ2Rhc2gnLhIabm9ybWFsaXplZFBhcmVudERvbWFpbk5hbWUWBxIEdHlwZRIGc3RyaW5nEgdwYXR0ZXJuEkFeJHxeW2EtaGota20tbnAtejAtOV1bYS1oai1rbS1ucC16MC05LVwuXXswLDYxfVthLWhqLWttLW5wLXowLTldJBIJbWluTGVuZ3RoAgASCW1heExlbmd0aAI/Eghwb3NpdGlvbgIDEgtkZXNjcmlwdGlvbhKiQSBwYXJlbnQgZG9tYWluIG5hbWUgaW4gbG93ZXJjYXNlIGZvciBjYXNlLWluc2Vuc2l0aXZlIHVuaXF1ZW5lc3MgdmFsaWRhdGlvbi4gIm8iLCAiaSIgYW5kICJsIiByZXBsYWNlZCB3aXRoICIwIiBhbmQgIjEiIHRvIG1pdGlnYXRlIGhvbW9ncmFwaCBhdHRhY2suIGUuZy4gJ2Rhc2gnEggkY29tbWVudBLATXVzdCBlaXRoZXIgYmUgZXF1YWwgdG8gYW4gZXhpc3RpbmcgZG9tYWluIG9yIGVtcHR5IHRvIGNyZWF0ZSBhIHRvcCBsZXZlbCBkb21haW4uICJvIiwgImkiIGFuZCAibCIgbXVzdCBiZSByZXBsYWNlZCB3aXRoICIwIiBhbmQgIjEiLiBPbmx5IHRoZSBkYXRhIGNvbnRyYWN0IG93bmVyIGNhbiBjcmVhdGUgdG9wIGxldmVsIGRvbWFpbnMuEgxwcmVvcmRlclNhbHQWBhIEdHlwZRIFYXJyYXkSCWJ5dGVBcnJheRMBEghtaW5JdGVtcwIgEghtYXhJdGVtcwIgEghwb3NpdGlvbgIEEgtkZXNjcmlwdGlvbhIiU2FsdCB1c2VkIGluIHRoZSBwcmVvcmRlciBkb2N1bWVudBIHcmVjb3JkcxYFEgR0eXBlEgZvYmplY3QSCnByb3BlcnRpZXMWARIIaWRlbnRpdHkWBxIEdHlwZRIFYXJyYXkSCWJ5dGVBcnJheRMBEghtaW5JdGVtcwIgEghtYXhJdGVtcwIgEghwb3NpdGlvbgIBEhBjb250ZW50TWVkaWFUeXBlEiFhcHBsaWNhdGlvbi94LmRhc2guZHBwLmlkZW50aWZpZXISC2Rlc2NyaXB0aW9uEjFJZGVudGlmaWVyIG5hbWUgcmVjb3JkIHRoYXQgcmVmZXJzIHRvIGFuIElkZW50aXR5Eg1taW5Qcm9wZXJ0aWVzAgESCHBvc2l0aW9uAgUSFGFkZGl0aW9uYWxQcm9wZXJ0aWVzEwASDnN1YmRvbWFpblJ1bGVzFgYSBHR5cGUSBm9iamVjdBIKcHJvcGVydGllcxYBEg9hbGxvd1N1YmRvbWFpbnMWBBIEdHlwZRIHYm9vbGVhbhILZGVzY3JpcHRpb24SW1RoaXMgb3B0aW9uIGRlZmluZXMgd2hvIGNhbiBjcmVhdGUgc3ViZG9tYWluczogdHJ1ZSAtIGFueW9uZTsgZmFsc2UgLSBvbmx5IHRoZSBkb21haW4gb3duZXISCCRjb21tZW50Ek9Pbmx5IHRoZSBkb21haW4gb3duZXIgaXMgYWxsb3dlZCB0byBjcmVhdGUgc3ViZG9tYWlucyBmb3Igbm9uIHRvcC1sZXZlbCBkb21haW5zEghwb3NpdGlvbgIAEghwb3NpdGlvbgIGEgtkZXNjcmlwdGlvbhJCU3ViZG9tYWluIHJ1bGVzIGFsbG93IGRvbWFpbiBvd25lcnMgdG8gZGVmaW5lIHJ1bGVzIGZvciBzdWJkb21haW5zEhRhZGRpdGlvbmFsUHJvcGVydGllcxMAEghyZXF1aXJlZBUBEg9hbGxvd1N1YmRvbWFpbnMSCHJlcXVpcmVkFQkSCiRjcmVhdGVkQXQSCiR1cGRhdGVkQXQSDiR0cmFuc2ZlcnJlZEF0EgVsYWJlbBIPbm9ybWFsaXplZExhYmVsEhpub3JtYWxpemVkUGFyZW50RG9tYWluTmFtZRIMcHJlb3JkZXJTYWx0EgdyZWNvcmRzEg5zdWJkb21haW5SdWxlcxIJdHJhbnNpZW50FQESDHByZW9yZGVyU2FsdBIUYWRkaXRpb25hbFByb3BlcnRpZXMTABIIJGNvbW1lbnQS+wE3SW4gb3JkZXIgdG8gcmVnaXN0ZXIgYSBkb21haW4geW91IG5lZWQgdG8gY3JlYXRlIGEgcHJlb3JkZXIuIFRoZSBwcmVvcmRlciBzdGVwIGlzIG5lZWRlZCB0byBwcmV2ZW50IG1hbi1pbi10aGUtbWlkZGxlIGF0dGFja3MuIG5vcm1hbGl6ZWRMYWJlbCArICcuJyArIG5vcm1hbGl6ZWRQYXJlbnREb21haW4gbXVzdCBub3QgYmUgbG9uZ2VyIHRoYW4gMjUzIGNoYXJzIGxlbmd0aCBhcyBkZWZpbmVkIGJ5IFJGQyAxMDM1LiBEb21haW4gZG9jdW1lbnRzIGFyZSBpbW11dGFibGU6IG1vZGlmaWNhdGlvbiBhbmQgZGVsZXRpb24gYXJlIHJlc3RyaWN0ZWQIcHJlb3JkZXIWCBIQZG9jdW1lbnRzTXV0YWJsZRMAEgxjYW5CZURlbGV0ZWQTARIEdHlwZRIGb2JqZWN0EgdpbmRpY2VzFQEWAxIEbmFtZRIKc2FsdGVkSGFzaBIKcHJvcGVydGllcxUBFgESEHNhbHRlZERvbWFpbkhhc2gSA2FzYxIGdW5pcXVlEwESCnByb3BlcnRpZXMWARIQc2FsdGVkRG9tYWluSGFzaBYGEgR0eXBlEgVhcnJheRIJYnl0ZUFycmF5EwESCG1pbkl0ZW1zAiASCG1heEl0ZW1zAiASCHBvc2l0aW9uAgASC2Rlc2NyaXB0aW9uEllEb3VibGUgc2hhLTI1NiBvZiB0aGUgY29uY2F0ZW5hdGlvbiBvZiBhIDMyIGJ5dGUgcmFuZG9tIHNhbHQgYW5kIGEgbm9ybWFsaXplZCBkb21haW4gbmFtZRIIcmVxdWlyZWQVARIQc2FsdGVkRG9tYWluSGFzaBIUYWRkaXRpb25hbFByb3BlcnRpZXMTABIIJGNvbW1lbnQSSlByZW9yZGVyIGRvY3VtZW50cyBhcmUgaW1tdXRhYmxlOiBtb2RpZmljYXRpb24gYW5kIGRlbGV0aW9uIGFyZSByZXN0cmljdGVkAAAAAAAAAAAAAA==';
@@ -0,0 +1,6 @@
1
+ import { IdentifierWASM, MasternodeVoteTransitionWASM } from 'pshenmic-dpp';
2
+ export default function createStateTransition(voteWASM, proTxHash, identityNonce) {
3
+ const voterIdentity = IdentifierWASM.fromHex(proTxHash);
4
+ const masternodeVoteTransition = new MasternodeVoteTransitionWASM(proTxHash, voterIdentity, voteWASM, identityNonce);
5
+ return masternodeVoteTransition.toStateTransition();
6
+ }
@@ -0,0 +1,72 @@
1
+ import { GetContestedResourceVoteStateRequest } from '../../proto/generated/platform';
2
+ import { DocumentWASM, IdentifierWASM, PlatformVersionWASM, verifyVotePollVoteStateProof } from 'pshenmic-dpp';
3
+ import verifyTenderdashProof from '../utils/verifyTenderdashProof';
4
+ import { getQuorumPublicKey } from '../utils/getQuorumPublicKey';
5
+ import bytesToHex from '../utils/bytesToHex';
6
+ export default async function getContestedResourceVoteState(grpcPool, contract, documentTypeName, indexName, indexValues, resultType, allowIncludeLockedAndAbstainingVoteTally, startAtIdentifierInfo, count) {
7
+ if (startAtIdentifierInfo != null) {
8
+ startAtIdentifierInfo = {
9
+ startIdentifier: (new IdentifierWASM(startAtIdentifierInfo.startIdentifier)).bytes(),
10
+ startIdentifierIncluded: startAtIdentifierInfo.startIdentifierIncluded
11
+ };
12
+ }
13
+ const getContestedResourceVoteStateRequest = GetContestedResourceVoteStateRequest.create({
14
+ version: {
15
+ oneofKind: 'v0',
16
+ v0: {
17
+ contractId: contract.id.bytes(),
18
+ documentTypeName,
19
+ indexName,
20
+ indexValues,
21
+ resultType: resultType,
22
+ allowIncludeLockedAndAbstainingVoteTally,
23
+ startAtIdentifierInfo,
24
+ count,
25
+ prove: true
26
+ }
27
+ }
28
+ });
29
+ const { response } = await grpcPool.getClient().getContestedResourceVoteState(getContestedResourceVoteStateRequest);
30
+ const { version } = response;
31
+ if (version.oneofKind !== 'v0') {
32
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
33
+ }
34
+ const { v0 } = version;
35
+ if (v0.result.oneofKind !== 'proof') {
36
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
37
+ }
38
+ const { result: { proof }, metadata } = v0;
39
+ if (metadata == null) {
40
+ throw new Error('Metadata not found');
41
+ }
42
+ const { rootHash, result } = verifyVotePollVoteStateProof(proof.grovedbProof, contract, documentTypeName, indexName, indexValues, resultType, allowIncludeLockedAndAbstainingVoteTally, count, startAtIdentifierInfo, PlatformVersionWASM.PLATFORM_V9);
43
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
44
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
45
+ if (!verify) {
46
+ throw new Error('Failed to verify query');
47
+ }
48
+ const { contenders } = result ?? { contenders: [] };
49
+ const { winner } = result ?? { winner: undefined };
50
+ if (contenders.length === 0) {
51
+ throw new Error('Vote state not found');
52
+ }
53
+ return {
54
+ contenders: contenders.map(contender => ({
55
+ ...contender,
56
+ identifier: contender.identityId,
57
+ document: contender.serializedDocument != null ? DocumentWASM.fromBytes(contender.serializedDocument, contract, documentTypeName, PlatformVersionWASM.PLATFORM_V9) : undefined
58
+ })),
59
+ abstainVoteTally: result?.abstainingVoteTally ?? 0,
60
+ lockVoteTally: result?.lockedVoteTally ?? 0,
61
+ finishedVoteInfo: (winner != null)
62
+ ? {
63
+ type: winner.type,
64
+ wonByIdentityId: winner.identityId != null ? new IdentifierWASM(winner.identityId) : undefined,
65
+ finishedAtBlockHeight: winner.blockInfo.height,
66
+ finishedAtCoreBlockHeight: winner.blockInfo.coreHeight,
67
+ finishedAtBlockTimeMs: winner.blockInfo.timeMs,
68
+ finishedAtEpoch: winner.blockInfo.epoch
69
+ }
70
+ : undefined
71
+ };
72
+ }
@@ -0,0 +1,30 @@
1
+ import getContestedResourceVoteState from './getContestedResourceVoteState';
2
+ /**
3
+ * Contested Resources controller for requesting information about contested resources
4
+ *
5
+ * @hideconstructor
6
+ */
7
+ export class ContestedResourcesController {
8
+ /** @ignore **/
9
+ grpcPool;
10
+ constructor(grpcPool) {
11
+ this.grpcPool = grpcPool;
12
+ }
13
+ /**
14
+ * Retrieves an info about vote state for contested resource
15
+ *
16
+ * @param contract {DataContractWASM} - instance of contract with contested resource
17
+ * @param documentTypeName {string} - document type name of contested resource
18
+ * @param indexName {string} - index name of contested resource
19
+ * @param indexValuesBytes {Uint8Array[]} - Array of contested values in bytes
20
+ * @param resultType {ContestedResourceVoteState} - enum for result info
21
+ * @param allowIncludeLockedAndAbstainingVoteTally {boolean}
22
+ * @param startAtIdentifierInfo {StartAtIdentifierInfo=}
23
+ * @param count {number=}
24
+ *
25
+ * @return {Promise<ContestedResourceVoteState>}
26
+ */
27
+ async getContestedResourceVoteState(contract, documentTypeName, indexName, indexValuesBytes, resultType, allowIncludeLockedAndAbstainingVoteTally, startAtIdentifierInfo, count) {
28
+ return await getContestedResourceVoteState(this.grpcPool, contract, documentTypeName, indexName, indexValuesBytes, resultType, allowIncludeLockedAndAbstainingVoteTally, startAtIdentifierInfo, count);
29
+ }
30
+ }
@@ -0,0 +1,11 @@
1
+ import { DataContractWASM, IdentifierWASM, PlatformVersionWASM } from 'pshenmic-dpp';
2
+ export default function createDataContract(ownerId, identityNonce, schema, tokenConfiguration, config, fullValidation, platformVersion) {
3
+ const id = new IdentifierWASM(ownerId);
4
+ const dataContract = new DataContractWASM(id, identityNonce, schema,
5
+ // we don't know what that param means yet
6
+ null, tokenConfiguration, fullValidation ?? true, platformVersion ?? PlatformVersionWASM.PLATFORM_V9);
7
+ if (config != null) {
8
+ dataContract.setConfig(config, platformVersion);
9
+ }
10
+ return dataContract;
11
+ }
@@ -0,0 +1,19 @@
1
+ import { DataContractCreateTransitionWASM, DataContractUpdateTransitionWASM } from 'pshenmic-dpp';
2
+ export var DataContractTransitionType;
3
+ (function (DataContractTransitionType) {
4
+ DataContractTransitionType[DataContractTransitionType["Create"] = 0] = "Create";
5
+ DataContractTransitionType[DataContractTransitionType["Update"] = 1] = "Update";
6
+ })(DataContractTransitionType || (DataContractTransitionType = {}));
7
+ const dataContractTransitionsMap = {
8
+ create: DataContractCreateTransitionWASM,
9
+ update: DataContractUpdateTransitionWASM
10
+ };
11
+ export default function createStateTransition(dataContract, type, identityNonce) {
12
+ const TransitionClass = dataContractTransitionsMap[type];
13
+ if (TransitionClass == null) {
14
+ throw new Error(`Unknown DataContract transition type: ${type}. Should be 'create' or 'update'.`);
15
+ }
16
+ // @ts-expect-error
17
+ const dataContractTransition = new TransitionClass(dataContract, identityNonce);
18
+ return dataContractTransition.toStateTransition();
19
+ }
@@ -0,0 +1,44 @@
1
+ import { DataContractWASM, IdentifierWASM, PlatformVersionWASM, verifyContractProof } from 'pshenmic-dpp';
2
+ import { GetDataContractRequest } from '../../proto/generated/platform';
3
+ import { getQuorumPublicKey } from '../utils/getQuorumPublicKey';
4
+ import bytesToHex from '../utils/bytesToHex';
5
+ import verifyTenderdashProof from '../utils/verifyTenderdashProof';
6
+ import { DPNS_DATA_CONTRACT_BYTES, DPNS_DATA_CONTRACT_ID } from '../constants';
7
+ export default async function getByIdentifier(grpcPool, identifier) {
8
+ const id = new IdentifierWASM(identifier);
9
+ if (id.base58() === DPNS_DATA_CONTRACT_ID) {
10
+ return DataContractWASM.fromBase64(DPNS_DATA_CONTRACT_BYTES, true, 9);
11
+ }
12
+ const getDataContractRequest = GetDataContractRequest.create({
13
+ version: {
14
+ oneofKind: 'v0',
15
+ v0: {
16
+ id: id.bytes(),
17
+ prove: true
18
+ }
19
+ }
20
+ });
21
+ const { response } = await grpcPool.getClient().getDataContract(getDataContractRequest);
22
+ const { version } = response;
23
+ if (version.oneofKind !== 'v0') {
24
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
25
+ }
26
+ const { v0 } = version;
27
+ if (v0.result.oneofKind !== 'proof') {
28
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
29
+ }
30
+ const { result: { proof }, metadata } = v0;
31
+ if (metadata == null) {
32
+ throw new Error('Metadata not found');
33
+ }
34
+ const { rootHash, dataContract } = verifyContractProof(proof.grovedbProof, undefined, false, false, id.bytes(), PlatformVersionWASM.PLATFORM_V9);
35
+ if (dataContract == null) {
36
+ throw new Error(`Data Contract with identifier ${id.base58()} not found`);
37
+ }
38
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
39
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
40
+ if (!verify) {
41
+ throw new Error('Failed to verify query');
42
+ }
43
+ return dataContract;
44
+ }
@@ -0,0 +1,57 @@
1
+ import getDataContractByIdentifier from './getDataContractByIdentifier';
2
+ import createDataContract from './create';
3
+ import createStateTransition from './createStateTransition';
4
+ /**
5
+ * Collection of methods necessary to work with Data Contracts in the network,
6
+ * such as data contract creation or retrieval
7
+ *
8
+ * @hideconstructor
9
+ */
10
+ export class DataContractsController {
11
+ /** @ignore */
12
+ grpcPool;
13
+ constructor(grpcPool) {
14
+ this.grpcPool = grpcPool;
15
+ }
16
+ /**
17
+ * Creates an instance of {DataContractWASM} that can be used to
18
+ * register a data contract in the network.
19
+ *
20
+ * @param ownerId {IdentifierLike} Identifier of the Data Contract's owner
21
+ * @param identityNonce {bigint} Identity nonce
22
+ * @param schema {object} Data Contract schema in json
23
+ * @param tokenConfiguration {object=} Token configuration
24
+ * @param config {DataContractConfig=} Data Contract config
25
+ * @param fullValidation {true=} Full validation (omit it)
26
+ * @param platformVersion {PlatformVersionWASM=} version of the platform
27
+ *
28
+ * @return {DataContractWASM}
29
+ */
30
+ create(ownerId, identityNonce, schema, fullValidation, tokenConfiguration, config, platformVersion) {
31
+ return createDataContract(ownerId, identityNonce, schema, tokenConfiguration, config, fullValidation, platformVersion);
32
+ }
33
+ /**
34
+ * Retrieves a Data Contract by an identifier from the network
35
+ *
36
+ * @param identifier {IdentifierLike} Identifier of the Data Contract
37
+ *
38
+ * @return {Promise<DataContractWASM>}
39
+ */
40
+ async getDataContractByIdentifier(identifier) {
41
+ return await getDataContractByIdentifier(this.grpcPool, identifier);
42
+ }
43
+ /**
44
+ * Helper function to create a state transition from a {DataContractWASM} instance
45
+ * Pass {DataContractTransitionType} in type param to specify which type of operation you want
46
+ * to make: create or update.
47
+ *
48
+ * @param dataContract {DataContractWASM} An instance of DataContractWASM to create or update
49
+ * @param type {string} type of identity state transition to do, must be 'create' or 'update'
50
+ * @param identityNonce {bigint} identity contract nonce
51
+ *
52
+ * @return {StateTransitionWASM}
53
+ */
54
+ createStateTransition(dataContract, type, identityNonce) {
55
+ return createStateTransition(dataContract, type, identityNonce);
56
+ }
57
+ }
@@ -0,0 +1,4 @@
1
+ import { DocumentWASM } from 'pshenmic-dpp';
2
+ export default function createDocument(dataContractId, documentType, data, owner, revision, documentId) {
3
+ return new DocumentWASM(data, documentType, revision ?? BigInt(1), dataContractId, owner, documentId);
4
+ }
@@ -0,0 +1,52 @@
1
+ import { BatchedTransitionWASM, BatchTransitionWASM, DocumentCreateTransitionWASM, DocumentDeleteTransitionWASM, DocumentPurchaseTransitionWASM, DocumentReplaceTransitionWASM, DocumentTransferTransitionWASM, DocumentUpdatePriceTransitionWASM } from 'pshenmic-dpp';
2
+ const documentTransitionsMap = {
3
+ create: {
4
+ class: DocumentCreateTransitionWASM,
5
+ arguments: ['identityContractNonce'],
6
+ optionalArguments: ['prefundedVotingBalance', 'tokenPaymentInfo']
7
+ },
8
+ replace: {
9
+ class: DocumentReplaceTransitionWASM,
10
+ arguments: ['identityContractNonce'],
11
+ optionalArguments: ['tokenPaymentInfo']
12
+ },
13
+ delete: {
14
+ class: DocumentDeleteTransitionWASM,
15
+ arguments: ['identityContractNonce'],
16
+ optionalArguments: ['tokenPaymentInfo']
17
+ },
18
+ updatePrice: {
19
+ class: DocumentUpdatePriceTransitionWASM,
20
+ arguments: ['identityContractNonce', 'price'],
21
+ optionalArguments: ['tokenPaymentInfo']
22
+ },
23
+ transfer: {
24
+ class: DocumentTransferTransitionWASM,
25
+ arguments: ['identityContractNonce', 'recipientId'],
26
+ optionalArguments: ['tokenPaymentInfo']
27
+ },
28
+ purchase: {
29
+ class: DocumentPurchaseTransitionWASM,
30
+ arguments: ['identityContractNonce', 'amount'],
31
+ optionalArguments: ['tokenPaymentInfo']
32
+ }
33
+ };
34
+ export default function createStateTransition(document, type, params) {
35
+ const { class: TransitionClass, arguments: classArguments, optionalArguments } = documentTransitionsMap[type];
36
+ if (TransitionClass == null) {
37
+ throw new Error(`Unimplemented transition type: ${type}`);
38
+ }
39
+ // check if all required params for document transition exists
40
+ const [missingArgument] = classArguments
41
+ .filter((classArgument) => params[classArgument] == null &&
42
+ !(optionalArguments).includes(classArgument));
43
+ if (missingArgument != null) {
44
+ throw new Error(`Document transition param "${missingArgument}" is missing`);
45
+ }
46
+ const transitionParams = classArguments.concat(optionalArguments).map((classArgument) => params[classArgument]);
47
+ // @ts-expect-error
48
+ const documentTransition = new TransitionClass(document, ...transitionParams).toDocumentTransition();
49
+ const batchedTransition = new BatchedTransitionWASM(documentTransition);
50
+ const batch = BatchTransitionWASM.fromV1BatchedTransitions([batchedTransition], document.ownerId, 1);
51
+ return batch.toStateTransition();
52
+ }
@@ -0,0 +1,83 @@
1
+ import createDocument from './create';
2
+ import { IdentifierWASM, PrefundedVotingBalanceWASM, TokenPaymentInfoWASM } from 'pshenmic-dpp';
3
+ import createStateTransition from './createStateTransition';
4
+ import query from './query';
5
+ /**
6
+ * Collection of methods to work with documents like creation, querying or preparing a transition action
7
+ *
8
+ * @hideconstructor
9
+ */
10
+ export class DocumentsController {
11
+ /** @ignore **/
12
+ grpcPool;
13
+ constructor(grpcPool) {
14
+ this.grpcPool = grpcPool;
15
+ }
16
+ /**
17
+ * Creates a {DocumentWASM} instance that can be used to submit a document in the network.
18
+ *
19
+ * @param dataContractId {IdentifierLike} Identifier of the Data Contract
20
+ * @param documentType {string} Document type as string
21
+ * @param data {object} Data as JSON object
22
+ * @param owner {IdentifierLike} Identifier of the document's owner
23
+ * @param revision {bigint=} revision (optional)
24
+ *
25
+ * @return {DataContractWASM}
26
+ */
27
+ create(dataContractId, documentType, data, owner, revision) {
28
+ return createDocument(new IdentifierWASM(dataContractId), documentType, data, new IdentifierWASM(owner), revision);
29
+ }
30
+ /**
31
+ * Make a query for documents retrieval from the network.
32
+ *
33
+ * @param dataContractId {IdentifierLike} Identifier of the Data Contract where fetch documents from
34
+ * @param documentType {string} Document type of the data contract
35
+ * @param where {object=} Where query clauses according syntax https://docs.dash.org/projects/platform/en/stable/docs/reference/query-syntax.html
36
+ * @param orderBy {object=} Order by clauses according syntax https://docs.dash.org/projects/platform/en/stable/docs/reference/query-syntax.html
37
+ * @param limit {number=} Limit amount of documents per request
38
+ * @param startAt {IdentifierLike=} Optional offset, where startAt is an identifier of the document. Use identifier of last item in previous response
39
+ * @param startAfter {IdentifierLike=} Same as previous, but with exclusion. Cannot be set if startAt already provided
40
+ */
41
+ async query(dataContractId, documentType, where, orderBy, limit, startAt, startAfter) {
42
+ if (startAfter != null && startAt !== null) {
43
+ throw new Error('You may only set either startAfter or startAt at once');
44
+ }
45
+ return await query(this.grpcPool, new IdentifierWASM(dataContractId), documentType, where, orderBy, limit ?? 100, startAt, startAfter);
46
+ }
47
+ /**
48
+ * Helper function for creating {StateTransitionWASM} from documents. It may be used to create any of 6 Document Transition actions:
49
+ *
50
+ * 1) Create - creates a document
51
+ * 2) Replace - replaces a document
52
+ * 3) Delete - deletes a document
53
+ * 4) Transfer - transfer a document from one identity to another
54
+ * 5) SetPrice - set a price for a document in credits
55
+ * 6) Purchase - purchase a document from identity (if price was set)
56
+ *
57
+ * @param document {DocumentWASM} Instance of the document to make transition with
58
+ * @param type {string} Type of the document transition, must be a one of ('create' | 'replace' | 'delete' | 'updatePrice' |'transfer' | 'purchase')
59
+ * @param params {DocumentTransitionParams} params
60
+ */
61
+ createStateTransition(document, type, params) {
62
+ if (type === 'transfer' && params.recipientId == null) {
63
+ throw new Error('Recipient is required for transfer transition');
64
+ }
65
+ if (type === 'updatePrice' && params.price == null) {
66
+ throw new Error('Price is required for updatePrice transition');
67
+ }
68
+ if (type === 'purchase' && params.amount == null) {
69
+ throw new Error('Amount is required for updatePrice transition');
70
+ }
71
+ if (params.prefundedVotingBalance != null) {
72
+ const { indexName, amount } = params.prefundedVotingBalance;
73
+ // @ts-expect-error
74
+ params.prefundedVotingBalance = new PrefundedVotingBalanceWASM(indexName, amount);
75
+ }
76
+ if (params.tokenPaymentInfo != null) {
77
+ const { tokenContractId, tokenContractPosition, minimumTokenCost, maximumTokenCost, gasFeesPaidBy } = params.tokenPaymentInfo;
78
+ // @ts-expect-error
79
+ params.tokenPaymentInfo = new TokenPaymentInfoWASM(new IdentifierWASM(tokenContractId), tokenContractPosition, minimumTokenCost, maximumTokenCost, gasFeesPaidBy);
80
+ }
81
+ return createStateTransition(document, type, params);
82
+ }
83
+ }
@@ -0,0 +1,62 @@
1
+ import { GetDocumentsRequest } from '../../proto/generated/platform';
2
+ import { IdentifierWASM, PlatformVersionWASM, verifyDocumentsProof } from 'pshenmic-dpp';
3
+ import { DAPI_DEFAULT_LIMIT } from '../constants';
4
+ import { getQuorumPublicKey } from '../utils/getQuorumPublicKey';
5
+ import bytesToHex from '../utils/bytesToHex';
6
+ import verifyTenderdashProof from '../utils/verifyTenderdashProof';
7
+ import { encode } from 'cbor-x';
8
+ import getDataContractByIdentifier from '../dataContracts/getDataContractByIdentifier';
9
+ export default async function query(grpcPool, dataContractId, documentTypeName, where, orderBy, limit = 100, startAt, startAfter) {
10
+ if ([startAt, startAfter].filter(e => e != null).length === 2) {
11
+ throw new Error('Only startAt or startAfter could be specified at one time');
12
+ }
13
+ let start;
14
+ if (startAt != null) {
15
+ start = {
16
+ oneofKind: 'startAt',
17
+ startAt: startAt.base58()
18
+ };
19
+ }
20
+ if (startAfter != null) {
21
+ start = {
22
+ oneofKind: 'startAfter',
23
+ startAt: startAfter.base58()
24
+ };
25
+ }
26
+ const getDocumentsRequest = GetDocumentsRequest.create({
27
+ version: {
28
+ oneofKind: 'v0',
29
+ v0: {
30
+ dataContractId: (new IdentifierWASM(dataContractId)).bytes(),
31
+ documentType: documentTypeName,
32
+ where: encode(where),
33
+ orderBy: encode(orderBy),
34
+ limit: limit ?? DAPI_DEFAULT_LIMIT,
35
+ start,
36
+ prove: true
37
+ }
38
+ }
39
+ });
40
+ const dataContract = await getDataContractByIdentifier(grpcPool, dataContractId);
41
+ const { response } = await grpcPool.getClient().getDocuments(getDocumentsRequest);
42
+ const { version } = response;
43
+ if (version.oneofKind !== 'v0') {
44
+ throw new Error('Unexpected oneOf type returned from DAPI (must be v0)');
45
+ }
46
+ const { v0 } = version;
47
+ if (v0.result.oneofKind !== 'proof') {
48
+ throw new Error('Unexpected oneOf type returned from DAPI (must be proof)');
49
+ }
50
+ const { result: { proof }, metadata } = v0;
51
+ if (metadata == null) {
52
+ throw new Error('Metadata not found');
53
+ }
54
+ const startAtIncluded = startAt != null;
55
+ const { rootHash, documents } = verifyDocumentsProof(proof.grovedbProof, dataContract, documentTypeName, where, orderBy, limit, startAt?.bytes(), startAtIncluded, BigInt(metadata?.timeMs), PlatformVersionWASM.PLATFORM_V9);
56
+ const quorumPublicKey = await getQuorumPublicKey(grpcPool.network, proof.quorumType, bytesToHex(proof.quorumHash));
57
+ const verify = await verifyTenderdashProof(proof, metadata, rootHash, quorumPublicKey);
58
+ if (!verify) {
59
+ throw new Error('Failed to verify query');
60
+ }
61
+ return documents ?? [];
62
+ }
@@ -0,0 +1,79 @@
1
+ import { GrpcWebFetchTransport } from '@protobuf-ts/grpcweb-transport';
2
+ import { PlatformClient } from '../proto/generated/platform.client';
3
+ import getEvonodeList from './utils/getEvonodeList';
4
+ import { GetStatusRequest } from '../proto/generated/platform';
5
+ import getRandomArrayItem from './utils/getRandomArrayItem';
6
+ const GRPC_DEFAULT_POOL_LIMIT = 5;
7
+ const seedNodes = {
8
+ testnet: [
9
+ // seed-1.pshenmic.dev
10
+ 'https://158.160.14.115:1443'
11
+ ],
12
+ mainnet: [
13
+ // seed-1.pshenmic.dev
14
+ 'https://158.160.14.115:443'
15
+ // mainnet dcg seeds
16
+ // 'https://158.160.14.115',
17
+ // 'https://3.0.60.103',
18
+ // 'https://34.211.174.194'
19
+ ]
20
+ };
21
+ const createClient = (url, abortController) => {
22
+ return new PlatformClient(new GrpcWebFetchTransport({
23
+ baseUrl: url,
24
+ abort: abortController?.signal
25
+ }));
26
+ };
27
+ export default class GRPCConnectionPool {
28
+ dapiUrls;
29
+ network;
30
+ constructor(network, grpcOptions) {
31
+ const grpcPoolLimit = grpcOptions?.poolLimit ?? GRPC_DEFAULT_POOL_LIMIT;
32
+ this.network = network;
33
+ this._initialize(network, grpcPoolLimit, grpcOptions?.dapiUrl).catch(console.error);
34
+ }
35
+ async _initialize(network, poolLimit, dapiUrl) {
36
+ if (typeof dapiUrl === 'string') {
37
+ this.dapiUrls = [dapiUrl];
38
+ return;
39
+ }
40
+ if (Array.isArray(dapiUrl)) {
41
+ this.dapiUrls = dapiUrl;
42
+ return;
43
+ }
44
+ if (dapiUrl != null) {
45
+ throw new Error('Unrecognized DAPI URL');
46
+ }
47
+ // Add default seed nodes
48
+ this.dapiUrls = seedNodes[network];
49
+ // retrieve last evonodes list
50
+ const evonodeList = await getEvonodeList(network);
51
+ // map it to array of dapiUrls
52
+ const networkDAPIUrls = Object.entries(evonodeList)
53
+ .map(([, info]) => info)
54
+ .filter((info) => info.status === 'ENABLED')
55
+ .map((info) => {
56
+ const [host] = info.address.split(':');
57
+ return `https://${host}:${info.platformHTTPPort}`;
58
+ });
59
+ // healthcheck nodes
60
+ for (const url of networkDAPIUrls) {
61
+ if (this.dapiUrls.length > poolLimit) {
62
+ break;
63
+ }
64
+ try {
65
+ const client = createClient(url);
66
+ const { response } = await client.getStatus(GetStatusRequest.create({}));
67
+ if (response.version.oneofKind === 'v0' && response.version.v0.chain != null) {
68
+ this.dapiUrls.push(url);
69
+ }
70
+ }
71
+ catch (e) {
72
+ }
73
+ }
74
+ }
75
+ getClient(abortController) {
76
+ const dapiUrl = getRandomArrayItem(this.dapiUrls);
77
+ return createClient(dapiUrl, abortController);
78
+ }
79
+ }