dash-platform-sdk 1.5.0-dev.3 → 1.5.0-dev.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -13
- package/bundle.min.js +1 -1
- package/package.json +1 -1
- package/src/keyPair/index.d.ts +63 -1
- package/src/keyPair/index.js +96 -1
- package/src/platformAddresses/createStateTransition.d.ts +12 -0
- package/src/platformAddresses/createStateTransition.js +62 -0
- package/src/platformAddresses/index.d.ts +20 -2
- package/src/platformAddresses/index.js +21 -0
- package/test/unit/KeyPair.spec.js +49 -1
- package/test/unit/PlatformAddress.spec.js +111 -0
- package/types.d.ts +59 -2
- package/types.js +1 -1
package/package.json
CHANGED
package/src/keyPair/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HDKey } from '@scure/bip32';
|
|
2
2
|
import { Network } from '../../types.js';
|
|
3
|
-
import { OrchardAddressWASM } from 'pshenmic-dpp';
|
|
3
|
+
import { OrchardAddressWASM, PlatformAddressWASM, PrivateKeyWASM } from 'pshenmic-dpp';
|
|
4
4
|
/**
|
|
5
5
|
* Collection of functions to work with private keys and seed phrases
|
|
6
6
|
*
|
|
@@ -65,6 +65,16 @@ export declare class KeyPairController {
|
|
|
65
65
|
* @returns {string}
|
|
66
66
|
*/
|
|
67
67
|
p2pkhAddress(publicKey: Uint8Array, network: Network): string;
|
|
68
|
+
/**
|
|
69
|
+
* Converts a public key to a transparent platform P2PKH address (DIP-18):
|
|
70
|
+
* the canonical `variantByte || Hash160(pubkey)` PlatformAddress.
|
|
71
|
+
*
|
|
72
|
+
* @param publicKey {Uint8Array}
|
|
73
|
+
* @param network {Network}
|
|
74
|
+
*
|
|
75
|
+
* @returns {PlatformAddressWASM}
|
|
76
|
+
*/
|
|
77
|
+
platformAddress(publicKey: Uint8Array, network: Network): PlatformAddressWASM;
|
|
68
78
|
/**
|
|
69
79
|
* Derives a shielded (Orchard) address from a BIP-39 seed via ZIP-32
|
|
70
80
|
* (m/32'/coinType'/account').
|
|
@@ -89,4 +99,56 @@ export declare class KeyPairController {
|
|
|
89
99
|
* @returns {Uint8Array} 32-byte outgoing viewing key
|
|
90
100
|
*/
|
|
91
101
|
deriveShieldedOutgoingViewingKey(seed: Uint8Array, network: Network, account: number): Uint8Array;
|
|
102
|
+
/**
|
|
103
|
+
* Derives the DIP-17 account-level extended public key (xpub) for the
|
|
104
|
+
* clear-funds key class: m/9'/coinType'/17'/account'/0'. The seed is only
|
|
105
|
+
* needed once per account — the returned xpub derives every address index
|
|
106
|
+
* publicly (see {@link derivePlatformAddressFromXpub}), with no further access
|
|
107
|
+
* to the seed.
|
|
108
|
+
*
|
|
109
|
+
* @param seed {Uint8Array} - BIP-39 seed bytes
|
|
110
|
+
* @param network {Network} - network (selects the SLIP-44 coin type)
|
|
111
|
+
* @param account {number} - DIP-17 account index
|
|
112
|
+
*
|
|
113
|
+
* @returns {Promise<string>} account-level extended public key
|
|
114
|
+
*/
|
|
115
|
+
derivePlatformAccountXpub(seed: Uint8Array, network: Network, account: number): Promise<string>;
|
|
116
|
+
/**
|
|
117
|
+
* Derives a transparent platform P2PKH address from a BIP-39 seed via DIP-17
|
|
118
|
+
* (m/9'/coinType'/17'/account'/0'/index).
|
|
119
|
+
*
|
|
120
|
+
* @param seed {Uint8Array} - BIP-39 seed bytes
|
|
121
|
+
* @param network {Network} - network (selects the SLIP-44 coin type)
|
|
122
|
+
* @param account {number} - DIP-17 account index
|
|
123
|
+
* @param index {number} - address index
|
|
124
|
+
*
|
|
125
|
+
* @returns {Promise<PlatformAddressWASM>}
|
|
126
|
+
*/
|
|
127
|
+
derivePlatformAddress(seed: Uint8Array, network: Network, account: number, index: number): Promise<PlatformAddressWASM>;
|
|
128
|
+
/**
|
|
129
|
+
* Derives a transparent platform P2PKH address from an account-level xpub (see
|
|
130
|
+
* {@link derivePlatformAccountXpub}). The address index is non-hardened, so
|
|
131
|
+
* public-only derivation reproduces the exact same address as the seed-based
|
|
132
|
+
* path — no seed required.
|
|
133
|
+
*
|
|
134
|
+
* @param xpub {string} - account-level extended public key
|
|
135
|
+
* @param network {Network} - network (selects the extended-key version bytes)
|
|
136
|
+
* @param index {number} - address index
|
|
137
|
+
*
|
|
138
|
+
* @returns {PlatformAddressWASM}
|
|
139
|
+
*/
|
|
140
|
+
derivePlatformAddressFromXpub(xpub: string, network: Network, index: number): PlatformAddressWASM;
|
|
141
|
+
/**
|
|
142
|
+
* Derives the private key for a DIP-17 platform address by its index
|
|
143
|
+
* (m/9'/coinType'/17'/account'/0'/index). Used to sign a transfer that spends
|
|
144
|
+
* from that address.
|
|
145
|
+
*
|
|
146
|
+
* @param seed {Uint8Array} - BIP-39 seed bytes
|
|
147
|
+
* @param network {Network} - network (selects the SLIP-44 coin type)
|
|
148
|
+
* @param account {number} - DIP-17 account index
|
|
149
|
+
* @param index {number} - address index
|
|
150
|
+
*
|
|
151
|
+
* @returns {Promise<PrivateKeyWASM>}
|
|
152
|
+
*/
|
|
153
|
+
derivePlatformAddressPrivateKey(seed: Uint8Array, network: Network, account: number, index: number): Promise<PrivateKeyWASM>;
|
|
92
154
|
}
|
package/src/keyPair/index.js
CHANGED
|
@@ -3,7 +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
|
+
import { OrchardAddressWASM, orchardOvkFromSeed, PlatformAddressWASM, PrivateKeyWASM } from 'pshenmic-dpp';
|
|
7
7
|
const DASH_VERSIONS = {
|
|
8
8
|
mainnet: { pubKeyHash: 0x4c, scriptHash: 0x10, bech32: 'dc', wif: 0xcc, private: 0x0488ade4, public: 0x0488b21e },
|
|
9
9
|
testnet: { pubKeyHash: 0x8c, scriptHash: 0x13, bech32: 'dc', wif: 0xef, private: 0x04358394, public: 0x043587cf }
|
|
@@ -87,6 +87,20 @@ export class KeyPairController {
|
|
|
87
87
|
const P2PKH = p2pkh(publicKey, DASH_VERSIONS[network]);
|
|
88
88
|
return P2PKH.address;
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Converts a public key to a transparent platform P2PKH address (DIP-18):
|
|
92
|
+
* the canonical `variantByte || Hash160(pubkey)` PlatformAddress.
|
|
93
|
+
*
|
|
94
|
+
* @param publicKey {Uint8Array}
|
|
95
|
+
* @param network {Network}
|
|
96
|
+
*
|
|
97
|
+
* @returns {PlatformAddressWASM}
|
|
98
|
+
*/
|
|
99
|
+
platformAddress(publicKey, network) {
|
|
100
|
+
const { hash } = p2pkh(publicKey, DASH_VERSIONS[network]);
|
|
101
|
+
// variant byte 0x00 = P2PKH
|
|
102
|
+
return PlatformAddressWASM.fromBytes(Uint8Array.from([0x00, ...hash]));
|
|
103
|
+
}
|
|
90
104
|
/**
|
|
91
105
|
* Derives a shielded (Orchard) address from a BIP-39 seed via ZIP-32
|
|
92
106
|
* (m/32'/coinType'/account').
|
|
@@ -119,4 +133,85 @@ export class KeyPairController {
|
|
|
119
133
|
const coinType = network === 'mainnet' ? 5 : 1;
|
|
120
134
|
return orchardOvkFromSeed(seed, coinType, account);
|
|
121
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Derives the DIP-17 account-level extended public key (xpub) for the
|
|
138
|
+
* clear-funds key class: m/9'/coinType'/17'/account'/0'. The seed is only
|
|
139
|
+
* needed once per account — the returned xpub derives every address index
|
|
140
|
+
* publicly (see {@link derivePlatformAddressFromXpub}), with no further access
|
|
141
|
+
* to the seed.
|
|
142
|
+
*
|
|
143
|
+
* @param seed {Uint8Array} - BIP-39 seed bytes
|
|
144
|
+
* @param network {Network} - network (selects the SLIP-44 coin type)
|
|
145
|
+
* @param account {number} - DIP-17 account index
|
|
146
|
+
*
|
|
147
|
+
* @returns {Promise<string>} account-level extended public key
|
|
148
|
+
*/
|
|
149
|
+
async derivePlatformAccountXpub(seed, network, account) {
|
|
150
|
+
const coinType = network === 'mainnet' ? 5 : 1;
|
|
151
|
+
const hdKey = this.seedToHdKey(seed, network);
|
|
152
|
+
const accountNode = await this.derivePath(hdKey, `m/9'/${coinType}'/17'/${account}'/0'`);
|
|
153
|
+
return accountNode.publicExtendedKey;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Derives a transparent platform P2PKH address from a BIP-39 seed via DIP-17
|
|
157
|
+
* (m/9'/coinType'/17'/account'/0'/index).
|
|
158
|
+
*
|
|
159
|
+
* @param seed {Uint8Array} - BIP-39 seed bytes
|
|
160
|
+
* @param network {Network} - network (selects the SLIP-44 coin type)
|
|
161
|
+
* @param account {number} - DIP-17 account index
|
|
162
|
+
* @param index {number} - address index
|
|
163
|
+
*
|
|
164
|
+
* @returns {Promise<PlatformAddressWASM>}
|
|
165
|
+
*/
|
|
166
|
+
async derivePlatformAddress(seed, network, account, index) {
|
|
167
|
+
const coinType = network === 'mainnet' ? 5 : 1;
|
|
168
|
+
const hdKey = this.seedToHdKey(seed, network);
|
|
169
|
+
const childNode = await this.derivePath(hdKey, `m/9'/${coinType}'/17'/${account}'/0'/${index}`);
|
|
170
|
+
if (childNode.publicKey == null) {
|
|
171
|
+
throw new Error(`Could not derive platform address public key at index ${index}`);
|
|
172
|
+
}
|
|
173
|
+
return this.platformAddress(childNode.publicKey, network);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Derives a transparent platform P2PKH address from an account-level xpub (see
|
|
177
|
+
* {@link derivePlatformAccountXpub}). The address index is non-hardened, so
|
|
178
|
+
* public-only derivation reproduces the exact same address as the seed-based
|
|
179
|
+
* path — no seed required.
|
|
180
|
+
*
|
|
181
|
+
* @param xpub {string} - account-level extended public key
|
|
182
|
+
* @param network {Network} - network (selects the extended-key version bytes)
|
|
183
|
+
* @param index {number} - address index
|
|
184
|
+
*
|
|
185
|
+
* @returns {PlatformAddressWASM}
|
|
186
|
+
*/
|
|
187
|
+
derivePlatformAddressFromXpub(xpub, network, index) {
|
|
188
|
+
const accountNode = HDKey.fromExtendedKey(xpub, DASH_VERSIONS[network]);
|
|
189
|
+
const childNode = accountNode.deriveChild(index);
|
|
190
|
+
if (childNode.publicKey == null) {
|
|
191
|
+
throw new Error(`Could not derive platform address public key at index ${index}`);
|
|
192
|
+
}
|
|
193
|
+
return this.platformAddress(childNode.publicKey, network);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Derives the private key for a DIP-17 platform address by its index
|
|
197
|
+
* (m/9'/coinType'/17'/account'/0'/index). Used to sign a transfer that spends
|
|
198
|
+
* from that address.
|
|
199
|
+
*
|
|
200
|
+
* @param seed {Uint8Array} - BIP-39 seed bytes
|
|
201
|
+
* @param network {Network} - network (selects the SLIP-44 coin type)
|
|
202
|
+
* @param account {number} - DIP-17 account index
|
|
203
|
+
* @param index {number} - address index
|
|
204
|
+
*
|
|
205
|
+
* @returns {Promise<PrivateKeyWASM>}
|
|
206
|
+
*/
|
|
207
|
+
async derivePlatformAddressPrivateKey(seed, network, account, index) {
|
|
208
|
+
const coinType = network === 'mainnet' ? 5 : 1;
|
|
209
|
+
const hdKey = this.seedToHdKey(seed, network);
|
|
210
|
+
const path = `m/9'/${coinType}'/17'/${account}'/0'/${index}`;
|
|
211
|
+
const { privateKey } = await this.derivePath(hdKey, path);
|
|
212
|
+
if (privateKey == null) {
|
|
213
|
+
throw new Error(`Could not derive platform address key at ${path}`);
|
|
214
|
+
}
|
|
215
|
+
return PrivateKeyWASM.fromBytes(privateKey, network);
|
|
216
|
+
}
|
|
122
217
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StateTransitionWASM } from 'pshenmic-dpp';
|
|
2
|
+
import { PlatformAddressTransitionParamsMap, PlatformAddressTransitionType } from '../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Helper function that assembles a {StateTransitionWASM} for Platform Address transitions
|
|
5
|
+
* out of already-built params. The builder is pure: it does not sign, broadcast or
|
|
6
|
+
* mutate the passed params. Producing witnesses / signatures stays the caller's
|
|
7
|
+
* responsibility (they are passed in via the `inputWitness` / `signature` params).
|
|
8
|
+
*
|
|
9
|
+
* @param type {string} type of transition
|
|
10
|
+
* @param params {PlatformAddressTransitionParamsMap[K]} params required by that transition type
|
|
11
|
+
*/
|
|
12
|
+
export default function createStateTransition<K extends PlatformAddressTransitionType>(type: K, params: PlatformAddressTransitionParamsMap[K]): StateTransitionWASM;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { IdentityCreditTransferToAddressesTransitionWASM, IdentityCreateFromAddressesTransitionWASM, IdentityTopUpFromAddressesTransitionWASM, AddressFundsTransferTransitionWASM, AddressFundingFromAssetLockTransitionWASM, AddressCreditWithdrawalTransitionWASM } from 'pshenmic-dpp';
|
|
2
|
+
const platformAddressTransitionsMap = {
|
|
3
|
+
identityCreditTransferToAddresses: {
|
|
4
|
+
class: IdentityCreditTransferToAddressesTransitionWASM,
|
|
5
|
+
arguments: ['identityId', 'recipients', 'nonce', 'userFeeIncrease'],
|
|
6
|
+
optionalArguments: ['userFeeIncrease']
|
|
7
|
+
},
|
|
8
|
+
identityCreateFromAddresses: {
|
|
9
|
+
class: IdentityCreateFromAddressesTransitionWASM,
|
|
10
|
+
arguments: ['publicKeys', 'inputs', 'feeStrategy', 'userFeeIncrease', 'inputWitness', 'output'],
|
|
11
|
+
optionalArguments: ['userFeeIncrease', 'output']
|
|
12
|
+
},
|
|
13
|
+
identityTopUpFromAddresses: {
|
|
14
|
+
class: IdentityTopUpFromAddressesTransitionWASM,
|
|
15
|
+
arguments: ['identityId', 'inputs', 'feeStrategy', 'userFeeIncrease', 'inputWitness', 'output'],
|
|
16
|
+
optionalArguments: ['userFeeIncrease', 'output']
|
|
17
|
+
},
|
|
18
|
+
addressFundsTransfer: {
|
|
19
|
+
class: AddressFundsTransferTransitionWASM,
|
|
20
|
+
arguments: ['inputs', 'feeStrategy', 'userFeeIncrease', 'inputWitness', 'outputs'],
|
|
21
|
+
optionalArguments: ['userFeeIncrease']
|
|
22
|
+
},
|
|
23
|
+
addressFundingFromAssetLock: {
|
|
24
|
+
class: AddressFundingFromAssetLockTransitionWASM,
|
|
25
|
+
arguments: ['assetLockProof', 'inputs', 'feeStrategy', 'userFeeIncrease', 'inputWitness', 'outputs'],
|
|
26
|
+
optionalArguments: ['userFeeIncrease']
|
|
27
|
+
},
|
|
28
|
+
addressCreditWithdrawal: {
|
|
29
|
+
class: AddressCreditWithdrawalTransitionWASM,
|
|
30
|
+
arguments: ['inputs', 'feeStrategy', 'coreFeePerByte', 'pooling', 'outputScript', 'userFeeIncrease', 'inputWitness', 'output'],
|
|
31
|
+
optionalArguments: ['userFeeIncrease', 'output']
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Helper function that assembles a {StateTransitionWASM} for Platform Address transitions
|
|
36
|
+
* out of already-built params. The builder is pure: it does not sign, broadcast or
|
|
37
|
+
* mutate the passed params. Producing witnesses / signatures stays the caller's
|
|
38
|
+
* responsibility (they are passed in via the `inputWitness` / `signature` params).
|
|
39
|
+
*
|
|
40
|
+
* @param type {string} type of transition
|
|
41
|
+
* @param params {PlatformAddressTransitionParamsMap[K]} params required by that transition type
|
|
42
|
+
*/
|
|
43
|
+
export default function createStateTransition(type, params) {
|
|
44
|
+
const { class: TransitionClass, arguments: classArguments, optionalArguments } = platformAddressTransitionsMap[type] ?? {};
|
|
45
|
+
if (TransitionClass == null) {
|
|
46
|
+
throw new Error(`Unimplemented transition type: ${type}`);
|
|
47
|
+
}
|
|
48
|
+
const [missingArgument] = classArguments
|
|
49
|
+
.filter((classArgument) => params[classArgument] == null &&
|
|
50
|
+
!optionalArguments.includes(classArgument));
|
|
51
|
+
if (missingArgument != null) {
|
|
52
|
+
throw new Error(`Platform address transition param "${missingArgument}" is missing`);
|
|
53
|
+
}
|
|
54
|
+
// userFeeIncrease is a required positional `number` in every WASM constructor,
|
|
55
|
+
// so coerce a missing value to 0 to keep the positional order intact.
|
|
56
|
+
const transitionParams = classArguments.map((classArgument) => classArgument === 'userFeeIncrease'
|
|
57
|
+
? (params[classArgument] ?? 0)
|
|
58
|
+
: params[classArgument]);
|
|
59
|
+
// @ts-expect-error
|
|
60
|
+
const platformAddressTransition = new TransitionClass(...transitionParams);
|
|
61
|
+
return platformAddressTransition.toStateTransition();
|
|
62
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import GRPCConnectionPool from '../grpcConnectionPool.js';
|
|
2
|
-
import { PlatformAddressLike } from 'pshenmic-dpp';
|
|
3
|
-
import { PlatformAddressInfo } from '../../types.js';
|
|
2
|
+
import { PlatformAddressLike, StateTransitionWASM } from 'pshenmic-dpp';
|
|
3
|
+
import { PlatformAddressInfo, PlatformAddressTransitionParamsMap, PlatformAddressTransitionType } from '../../types.js';
|
|
4
4
|
export declare class PlatformAddressesController {
|
|
5
5
|
/** @ignore **/
|
|
6
6
|
grpcPool: GRPCConnectionPool;
|
|
@@ -19,4 +19,22 @@ export declare class PlatformAddressesController {
|
|
|
19
19
|
* @return {Promise<PlatformAddressInfo[]>}
|
|
20
20
|
*/
|
|
21
21
|
getAddressesInfos(addresses: PlatformAddressLike[]): Promise<PlatformAddressInfo[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Helper function for creating {StateTransitionWASM} for Platform Address transitions
|
|
24
|
+
*
|
|
25
|
+
* Unlike identity transitions (which are signed after construction), address transitions carry
|
|
26
|
+
* their signature material as constructor input (the `inputWitness` param, and a `signature`
|
|
27
|
+
* setter on the asset-lock variant), so this builder is pure and only assembles the transition
|
|
28
|
+
* from already-built params - producing witnesses stays the caller's responsibility.
|
|
29
|
+
*
|
|
30
|
+
* Please refer to PlatformAddress.spec.ts or README for example commands
|
|
31
|
+
*
|
|
32
|
+
* @param type {string} type of transition, must be a one of ('identityCreditTransferToAddresses' |
|
|
33
|
+
* 'identityCreateFromAddresses' | 'identityTopUpFromAddresses' | 'addressFundsTransfer' |
|
|
34
|
+
* 'addressFundingFromAssetLock' | 'addressCreditWithdrawal')
|
|
35
|
+
* @param params {PlatformAddressTransitionParamsMap[K]} params required by that transition type
|
|
36
|
+
*
|
|
37
|
+
* @return {StateTransitionWASM}
|
|
38
|
+
*/
|
|
39
|
+
createStateTransition<K extends PlatformAddressTransitionType>(type: K, params: PlatformAddressTransitionParamsMap[K]): StateTransitionWASM;
|
|
22
40
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getAddressInfo } from './getAddressInfo.js';
|
|
2
2
|
import { getAddressesInfos } from './getAddressesInfos.js';
|
|
3
|
+
import createStateTransition from './createStateTransition.js';
|
|
3
4
|
export class PlatformAddressesController {
|
|
4
5
|
/** @ignore **/
|
|
5
6
|
grpcPool;
|
|
@@ -24,4 +25,24 @@ export class PlatformAddressesController {
|
|
|
24
25
|
async getAddressesInfos(addresses) {
|
|
25
26
|
return await getAddressesInfos(this.grpcPool, addresses);
|
|
26
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Helper function for creating {StateTransitionWASM} for Platform Address transitions
|
|
30
|
+
*
|
|
31
|
+
* Unlike identity transitions (which are signed after construction), address transitions carry
|
|
32
|
+
* their signature material as constructor input (the `inputWitness` param, and a `signature`
|
|
33
|
+
* setter on the asset-lock variant), so this builder is pure and only assembles the transition
|
|
34
|
+
* from already-built params - producing witnesses stays the caller's responsibility.
|
|
35
|
+
*
|
|
36
|
+
* Please refer to PlatformAddress.spec.ts or README for example commands
|
|
37
|
+
*
|
|
38
|
+
* @param type {string} type of transition, must be a one of ('identityCreditTransferToAddresses' |
|
|
39
|
+
* 'identityCreateFromAddresses' | 'identityTopUpFromAddresses' | 'addressFundsTransfer' |
|
|
40
|
+
* 'addressFundingFromAssetLock' | 'addressCreditWithdrawal')
|
|
41
|
+
* @param params {PlatformAddressTransitionParamsMap[K]} params required by that transition type
|
|
42
|
+
*
|
|
43
|
+
* @return {StateTransitionWASM}
|
|
44
|
+
*/
|
|
45
|
+
createStateTransition(type, params) {
|
|
46
|
+
return createStateTransition(type, params);
|
|
47
|
+
}
|
|
27
48
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { OrchardAddressWASM } from 'pshenmic-dpp';
|
|
1
|
+
import { OrchardAddressWASM, PlatformAddressWASM } from 'pshenmic-dpp';
|
|
2
2
|
import { DashPlatformSDK } from '../../src/DashPlatformSDK.js';
|
|
3
3
|
let sdk;
|
|
4
4
|
let mnemonic;
|
|
@@ -63,4 +63,52 @@ describe('KeyPair', () => {
|
|
|
63
63
|
expect(ovk).toEqual(sdk.keyPair.deriveShieldedOutgoingViewingKey(seed, 'testnet', account));
|
|
64
64
|
});
|
|
65
65
|
});
|
|
66
|
+
describe('platform addresses', () => {
|
|
67
|
+
const account = 0;
|
|
68
|
+
// Reference values produced by the dash-platform-extension derivation utils
|
|
69
|
+
// (proven byte-identical to on-chain / desktop-wallet addresses) for the
|
|
70
|
+
// fixed mnemonic above, testnet, account 0.
|
|
71
|
+
const expectedXpub = 'tpubDH6WaqMU1YHJMbPG413my6Dx5DwnsuuL6EzbetEZQac6ixmkByzCGgiibue3HQmHX5JGVUm2fBHKGttJpVkx3NrK5Em9br8GyLd1fVGm7ud';
|
|
72
|
+
const expectedAddresses = [
|
|
73
|
+
'tdash1kr0xt5wj85ht5u464rfysjrq75rewz9mysjwf59p',
|
|
74
|
+
'tdash1kqgy7ngm2wf0zsv20k4mc62s5rapw26yeg6em4jq',
|
|
75
|
+
'tdash1kzlatzl0u06uxrqz8hkc7naz9d2g3v8g7gw83ew3'
|
|
76
|
+
];
|
|
77
|
+
test('derives the DIP-17 account xpub matching the reference', async () => {
|
|
78
|
+
const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
|
|
79
|
+
const xpub = await sdk.keyPair.derivePlatformAccountXpub(seed, 'testnet', account);
|
|
80
|
+
expect(xpub).toEqual(expectedXpub);
|
|
81
|
+
});
|
|
82
|
+
test('derives seed-based addresses matching the reference', async () => {
|
|
83
|
+
const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
|
|
84
|
+
for (let index = 0; index < expectedAddresses.length; index++) {
|
|
85
|
+
const address = await sdk.keyPair.derivePlatformAddress(seed, 'testnet', account, index);
|
|
86
|
+
expect(address).toEqual(expect.any(PlatformAddressWASM));
|
|
87
|
+
expect(address.isP2PKH()).toBe(true);
|
|
88
|
+
expect(address.toBech32m('testnet')).toEqual(expectedAddresses[index]);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
test('xpub-based public derivation reproduces the seed-based addresses', async () => {
|
|
92
|
+
const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
|
|
93
|
+
const xpub = await sdk.keyPair.derivePlatformAccountXpub(seed, 'testnet', account);
|
|
94
|
+
for (let index = 0; index < expectedAddresses.length; index++) {
|
|
95
|
+
const fromXpub = sdk.keyPair.derivePlatformAddressFromXpub(xpub, 'testnet', index);
|
|
96
|
+
expect(fromXpub.toBech32m('testnet')).toEqual(expectedAddresses[index]);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
test('private key derivation yields the same pubkey hash as the address', async () => {
|
|
100
|
+
const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
|
|
101
|
+
for (let index = 0; index < expectedAddresses.length; index++) {
|
|
102
|
+
const privateKey = await sdk.keyPair.derivePlatformAddressPrivateKey(seed, 'testnet', account, index);
|
|
103
|
+
const address = await sdk.keyPair.derivePlatformAddress(seed, 'testnet', account, index);
|
|
104
|
+
expect(privateKey.getPublicKeyHash()).toEqual(Buffer.from(address.hash()).toString('hex'));
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
test('derives distinct addresses per network', async () => {
|
|
108
|
+
const seed = sdk.keyPair.mnemonicToSeed(mnemonic);
|
|
109
|
+
const mainnet = await sdk.keyPair.derivePlatformAddress(seed, 'mainnet', account, 0);
|
|
110
|
+
const testnet = await sdk.keyPair.derivePlatformAddress(seed, 'testnet', account, 0);
|
|
111
|
+
expect(mainnet.bytes()).not.toEqual(testnet.bytes());
|
|
112
|
+
});
|
|
113
|
+
});
|
|
66
114
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AddressFundsFeeStrategyStepWASM, AddressWitnessWASM, AssetLockProofWASM, CoreScriptWASM, IdentityPublicKeyInCreationWASM, InputAddressWASM, OutputAddressWASM, OutputAddressNullableCreditsWASM, KeyType, OutPointWASM, PlatformAddressWASM, PrivateKeyWASM, Purpose, SecurityLevel, StateTransitionWASM } from 'pshenmic-dpp';
|
|
2
|
+
import { base58 } from '@scure/base';
|
|
1
3
|
import { DashPlatformSDK } from '../../src/DashPlatformSDK.js';
|
|
2
4
|
let sdk;
|
|
3
5
|
describe('PlatformAddress', () => {
|
|
@@ -19,4 +21,113 @@ describe('PlatformAddress', () => {
|
|
|
19
21
|
const info = await sdk.platformAddresses.getAddressesInfos(addresses);
|
|
20
22
|
expect(info).toHaveLength(addresses.length);
|
|
21
23
|
});
|
|
24
|
+
describe('createStateTransition', () => {
|
|
25
|
+
const identityId = 'QMfCRPcjXoTnZa9sA9JR2KWgGxZXMRJ4akgS3Uia1Qv';
|
|
26
|
+
const addressA = PlatformAddressWASM.fromBech32m('tdash1kzg5azscav69z7m6dfzr9ner0a5vt7pn9ca4sz8d');
|
|
27
|
+
const addressB = PlatformAddressWASM.fromBech32m('tdash1kqr3cxhgel75ru0yrhj5eq8j8jt92m5enqrfajxw');
|
|
28
|
+
const inputs = [new InputAddressWASM(addressA, 0, 100000n)];
|
|
29
|
+
const outputs = [new OutputAddressWASM(addressB, 50000n)];
|
|
30
|
+
const recipients = [new OutputAddressWASM(addressB, 50000n)];
|
|
31
|
+
const nullableOutputs = [new OutputAddressNullableCreditsWASM(addressB)];
|
|
32
|
+
const feeStrategy = [AddressFundsFeeStrategyStepWASM.DeductFromInput(1)];
|
|
33
|
+
const inputWitness = [AddressWitnessWASM.P2PKH(new Uint8Array(65))];
|
|
34
|
+
const output = new OutputAddressWASM(addressA, 10000n);
|
|
35
|
+
const nonce = 1n;
|
|
36
|
+
const privateKey = PrivateKeyWASM.fromHex('a1286dd195e2b8e1f6bdc946c56a53e0c544750d6452ddc0f4c593ef311f21af', 'testnet');
|
|
37
|
+
const publicKeys = [
|
|
38
|
+
new IdentityPublicKeyInCreationWASM(0, Purpose.AUTHENTICATION, SecurityLevel.MASTER, KeyType.ECDSA_SECP256K1, false, privateKey.getPublicKey().bytes())
|
|
39
|
+
];
|
|
40
|
+
const assetLockProof = AssetLockProofWASM.createChainAssetLockProof(1337, new OutPointWASM('61aede830477254876d435a317241ad46753c4b1350dc991a45ebcf19ab80a11', 0));
|
|
41
|
+
const withdrawalAddress = 'yjHVQ3dj37UJwXFmvMTKR9ZVfoJSc3opTD';
|
|
42
|
+
const outputScript = CoreScriptWASM.newP2PKH(base58.decode(withdrawalAddress).slice(1, 21));
|
|
43
|
+
test('should be able to create identityCreditTransferToAddresses', () => {
|
|
44
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('identityCreditTransferToAddresses', {
|
|
45
|
+
identityId, recipients, nonce
|
|
46
|
+
});
|
|
47
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
48
|
+
});
|
|
49
|
+
test('should throw when identityCreditTransferToAddresses is missing recipients', () => {
|
|
50
|
+
// @ts-expect-error testing the runtime missing-param check
|
|
51
|
+
expect(() => sdk.platformAddresses.createStateTransition('identityCreditTransferToAddresses', {
|
|
52
|
+
identityId, nonce
|
|
53
|
+
})).toThrow('Platform address transition param "recipients" is missing');
|
|
54
|
+
});
|
|
55
|
+
test('should be able to create identityCreateFromAddresses', () => {
|
|
56
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('identityCreateFromAddresses', {
|
|
57
|
+
publicKeys, inputs, feeStrategy, inputWitness
|
|
58
|
+
});
|
|
59
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
60
|
+
});
|
|
61
|
+
test('should throw when identityCreateFromAddresses is missing publicKeys', () => {
|
|
62
|
+
// @ts-expect-error testing the runtime missing-param check
|
|
63
|
+
expect(() => sdk.platformAddresses.createStateTransition('identityCreateFromAddresses', {
|
|
64
|
+
inputs, feeStrategy, inputWitness
|
|
65
|
+
})).toThrow('Platform address transition param "publicKeys" is missing');
|
|
66
|
+
});
|
|
67
|
+
test('should be able to create identityTopUpFromAddresses', () => {
|
|
68
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('identityTopUpFromAddresses', {
|
|
69
|
+
identityId, inputs, feeStrategy, inputWitness
|
|
70
|
+
});
|
|
71
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
72
|
+
});
|
|
73
|
+
test('should throw when identityTopUpFromAddresses is missing identityId', () => {
|
|
74
|
+
// @ts-expect-error testing the runtime missing-param check
|
|
75
|
+
expect(() => sdk.platformAddresses.createStateTransition('identityTopUpFromAddresses', {
|
|
76
|
+
inputs, feeStrategy, inputWitness
|
|
77
|
+
})).toThrow('Platform address transition param "identityId" is missing');
|
|
78
|
+
});
|
|
79
|
+
test('should be able to create addressFundsTransfer', () => {
|
|
80
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('addressFundsTransfer', {
|
|
81
|
+
inputs, feeStrategy, inputWitness, outputs
|
|
82
|
+
});
|
|
83
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
84
|
+
});
|
|
85
|
+
test('should throw when addressFundsTransfer is missing outputs', () => {
|
|
86
|
+
// @ts-expect-error testing the runtime missing-param check
|
|
87
|
+
expect(() => sdk.platformAddresses.createStateTransition('addressFundsTransfer', {
|
|
88
|
+
inputs, feeStrategy, inputWitness
|
|
89
|
+
})).toThrow('Platform address transition param "outputs" is missing');
|
|
90
|
+
});
|
|
91
|
+
test('should be able to create addressFundingFromAssetLock', () => {
|
|
92
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('addressFundingFromAssetLock', {
|
|
93
|
+
assetLockProof, inputs, feeStrategy, inputWitness, outputs: nullableOutputs
|
|
94
|
+
});
|
|
95
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
96
|
+
});
|
|
97
|
+
test('should throw when addressFundingFromAssetLock is missing assetLockProof', () => {
|
|
98
|
+
// @ts-expect-error testing the runtime missing-param check
|
|
99
|
+
expect(() => sdk.platformAddresses.createStateTransition('addressFundingFromAssetLock', {
|
|
100
|
+
inputs, feeStrategy, inputWitness, outputs: nullableOutputs
|
|
101
|
+
})).toThrow('Platform address transition param "assetLockProof" is missing');
|
|
102
|
+
});
|
|
103
|
+
test('should be able to create addressCreditWithdrawal', () => {
|
|
104
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('addressCreditWithdrawal', {
|
|
105
|
+
inputs, feeStrategy, coreFeePerByte: 1, pooling: 'Standard', outputScript, inputWitness
|
|
106
|
+
});
|
|
107
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
108
|
+
});
|
|
109
|
+
test('should be able to create addressCreditWithdrawal with optional output', () => {
|
|
110
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('addressCreditWithdrawal', {
|
|
111
|
+
inputs, feeStrategy, coreFeePerByte: 1, pooling: 'Standard', outputScript, inputWitness, output
|
|
112
|
+
});
|
|
113
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
114
|
+
});
|
|
115
|
+
test('should throw when addressCreditWithdrawal is missing outputScript', () => {
|
|
116
|
+
// @ts-expect-error testing the runtime missing-param check
|
|
117
|
+
expect(() => sdk.platformAddresses.createStateTransition('addressCreditWithdrawal', {
|
|
118
|
+
inputs, feeStrategy, coreFeePerByte: 1, pooling: 'Standard', inputWitness
|
|
119
|
+
})).toThrow('Platform address transition param "outputScript" is missing');
|
|
120
|
+
});
|
|
121
|
+
test('should default userFeeIncrease to 0 when omitted', () => {
|
|
122
|
+
const stateTransition = sdk.platformAddresses.createStateTransition('addressFundsTransfer', {
|
|
123
|
+
inputs, feeStrategy, inputWitness, outputs
|
|
124
|
+
});
|
|
125
|
+
expect(stateTransition).toEqual(expect.any(StateTransitionWASM));
|
|
126
|
+
});
|
|
127
|
+
test('should throw on unimplemented transition type', () => {
|
|
128
|
+
expect(() => sdk.platformAddresses.createStateTransition(
|
|
129
|
+
// @ts-expect-error testing an unknown transition type
|
|
130
|
+
'unknownTransition', {})).toThrow('Unimplemented transition type: unknownTransition');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
22
133
|
});
|
package/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AddressFundsFeeStrategyStepWASM, AssetLockProofWASM, CoreScriptWASM, DocumentWASM, GasFeesPaidByWASM, IdentifierLike, IdentifierWASM, InputAddressWASM, KeyType, OrchardAddressWASM, PlatformAddressLike, PlatformAddressWASM, PlatformVersionWASM, PoolingLike, PrivateKeyWASM, Purpose, SecurityLevel, SpendableNoteWASM, TokenEmergencyActionWASM, TokenPricingScheduleWASM } from 'pshenmic-dpp';
|
|
2
|
-
export { CoreScriptWASM, DocumentWASM, GasFeesPaidByWASM, IdentifierWASM, KeyType, Purpose, SecurityLevel, TokenEmergencyActionWASM, TokenPricingScheduleWASM, StateTransitionWASM, BatchTransitionWASM, IdentityPublicKeyWASM, PrivateKeyWASM, DataContractUpdateTransitionWASM, IdentityWASM, IdentityUpdateTransitionWASM, IdentityCreditTransferWASM, MasternodeVoteTransitionWASM, IdentifierLike, PlatformAddressLike } from 'pshenmic-dpp';
|
|
1
|
+
import { AddressFundsFeeStrategyStepWASM, AssetLockProofWASM, CoreScriptWASM, DocumentWASM, GasFeesPaidByWASM, IdentifierLike, IdentifierWASM, InputAddressWASM, KeyType, OrchardAddressWASM, PlatformAddressLike, PlatformAddressWASM, PlatformVersionWASM, PoolingLike, PrivateKeyWASM, Purpose, SecurityLevel, SpendableNoteWASM, TokenEmergencyActionWASM, TokenPricingScheduleWASM, AddressWitnessWASM, IdentityPublicKeyInCreationWASM, OutputAddressWASM, OutputAddressNullableCreditsWASM } from 'pshenmic-dpp';
|
|
2
|
+
export { CoreScriptWASM, DocumentWASM, GasFeesPaidByWASM, IdentifierWASM, KeyType, Purpose, SecurityLevel, TokenEmergencyActionWASM, TokenPricingScheduleWASM, StateTransitionWASM, BatchTransitionWASM, IdentityPublicKeyWASM, PrivateKeyWASM, DataContractUpdateTransitionWASM, IdentityWASM, IdentityUpdateTransitionWASM, IdentityCreditTransferWASM, MasternodeVoteTransitionWASM, IdentifierLike, PlatformAddressLike, InputAddressWASM, OutputAddressWASM, OutputAddressNullableCreditsWASM, AddressFundsFeeStrategyStepWASM, AddressWitnessWASM, IdentityPublicKeyInCreationWASM, AssetLockProofWASM, IdentityCreditTransferToAddressesTransitionWASM, IdentityCreateFromAddressesTransitionWASM, IdentityTopUpFromAddressesTransitionWASM, AddressFundsTransferTransitionWASM, AddressFundingFromAssetLockTransitionWASM, AddressCreditWithdrawalTransitionWASM } from 'pshenmic-dpp';
|
|
3
3
|
export type Network = 'mainnet' | 'testnet';
|
|
4
4
|
export { DashPlatformSDK } from './src/DashPlatformSDK.js';
|
|
5
5
|
export type MasternodeList = Record<string, MasternodeInfo>;
|
|
@@ -294,3 +294,60 @@ export interface ShieldedNullifierStatus {
|
|
|
294
294
|
nullifier: Uint8Array;
|
|
295
295
|
isSpent: boolean;
|
|
296
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Fields shared by the address-funded transitions (the ones spending platform address inputs).
|
|
299
|
+
*
|
|
300
|
+
* The `inputWitness` arrays are produced by the client application (wallet / mobile / browser
|
|
301
|
+
* extension), which is where the address private keys live. The builders only assemble the
|
|
302
|
+
* transition - they never sign or hit the network.
|
|
303
|
+
*/
|
|
304
|
+
export interface AddressFundsBaseParams {
|
|
305
|
+
inputs: InputAddressWASM[];
|
|
306
|
+
feeStrategy: AddressFundsFeeStrategyStepWASM[];
|
|
307
|
+
inputWitness: AddressWitnessWASM[];
|
|
308
|
+
userFeeIncrease?: number;
|
|
309
|
+
}
|
|
310
|
+
/** Identity -> platform addresses (transition type 9). */
|
|
311
|
+
export interface IdentityCreditTransferToAddressesParams {
|
|
312
|
+
identityId: IdentifierLike;
|
|
313
|
+
recipients: OutputAddressWASM[];
|
|
314
|
+
nonce: bigint;
|
|
315
|
+
userFeeIncrease?: number;
|
|
316
|
+
}
|
|
317
|
+
/** Platform addresses -> new identity (transition type 10). */
|
|
318
|
+
export interface IdentityCreateFromAddressesParams extends AddressFundsBaseParams {
|
|
319
|
+
publicKeys: IdentityPublicKeyInCreationWASM[];
|
|
320
|
+
output?: OutputAddressWASM;
|
|
321
|
+
}
|
|
322
|
+
/** Platform addresses -> existing identity (transition type 11). */
|
|
323
|
+
export interface IdentityTopUpFromAddressesParams extends AddressFundsBaseParams {
|
|
324
|
+
identityId: IdentifierLike;
|
|
325
|
+
output?: OutputAddressWASM;
|
|
326
|
+
}
|
|
327
|
+
/** Platform addresses -> platform addresses (transition type 12). */
|
|
328
|
+
export interface AddressFundsTransferParams extends AddressFundsBaseParams {
|
|
329
|
+
outputs: OutputAddressWASM[];
|
|
330
|
+
}
|
|
331
|
+
/** Asset lock -> platform addresses (transition type 13). */
|
|
332
|
+
export interface AddressFundingFromAssetLockParams extends AddressFundsBaseParams {
|
|
333
|
+
assetLockProof: AssetLockProofWASM;
|
|
334
|
+
outputs: OutputAddressNullableCreditsWASM[];
|
|
335
|
+
}
|
|
336
|
+
/** Platform addresses -> core L1 (transition type 14). */
|
|
337
|
+
export interface AddressCreditWithdrawalParams extends AddressFundsBaseParams {
|
|
338
|
+
coreFeePerByte: number;
|
|
339
|
+
pooling: 'Standard' | 'Never' | 'IfAvailable';
|
|
340
|
+
outputScript: CoreScriptWASM;
|
|
341
|
+
output?: OutputAddressWASM;
|
|
342
|
+
}
|
|
343
|
+
/** Maps each platform address transition type to the params it requires. */
|
|
344
|
+
export interface PlatformAddressTransitionParamsMap {
|
|
345
|
+
identityCreditTransferToAddresses: IdentityCreditTransferToAddressesParams;
|
|
346
|
+
identityCreateFromAddresses: IdentityCreateFromAddressesParams;
|
|
347
|
+
identityTopUpFromAddresses: IdentityTopUpFromAddressesParams;
|
|
348
|
+
addressFundsTransfer: AddressFundsTransferParams;
|
|
349
|
+
addressFundingFromAssetLock: AddressFundingFromAssetLockParams;
|
|
350
|
+
addressCreditWithdrawal: AddressCreditWithdrawalParams;
|
|
351
|
+
}
|
|
352
|
+
export type PlatformAddressTransitionType = keyof PlatformAddressTransitionParamsMap;
|
|
353
|
+
export type PlatformAddressTransitionParams = PlatformAddressTransitionParamsMap[PlatformAddressTransitionType];
|
package/types.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CoreScriptWASM, DocumentWASM, GasFeesPaidByWASM, IdentifierWASM, KeyType, Purpose, SecurityLevel, TokenEmergencyActionWASM, TokenPricingScheduleWASM, StateTransitionWASM, BatchTransitionWASM, IdentityPublicKeyWASM, PrivateKeyWASM, DataContractUpdateTransitionWASM, IdentityWASM, IdentityUpdateTransitionWASM, IdentityCreditTransferWASM, MasternodeVoteTransitionWASM } from 'pshenmic-dpp';
|
|
1
|
+
export { CoreScriptWASM, DocumentWASM, GasFeesPaidByWASM, IdentifierWASM, KeyType, Purpose, SecurityLevel, TokenEmergencyActionWASM, TokenPricingScheduleWASM, StateTransitionWASM, BatchTransitionWASM, IdentityPublicKeyWASM, PrivateKeyWASM, DataContractUpdateTransitionWASM, IdentityWASM, IdentityUpdateTransitionWASM, IdentityCreditTransferWASM, MasternodeVoteTransitionWASM, InputAddressWASM, OutputAddressWASM, OutputAddressNullableCreditsWASM, AddressFundsFeeStrategyStepWASM, AddressWitnessWASM, IdentityPublicKeyInCreationWASM, AssetLockProofWASM, IdentityCreditTransferToAddressesTransitionWASM, IdentityCreateFromAddressesTransitionWASM, IdentityTopUpFromAddressesTransitionWASM, AddressFundsTransferTransitionWASM, AddressFundingFromAssetLockTransitionWASM, AddressCreditWithdrawalTransitionWASM } from 'pshenmic-dpp';
|
|
2
2
|
export { DashPlatformSDK } from './src/DashPlatformSDK.js';
|
|
3
3
|
export var ContestedStateResultType;
|
|
4
4
|
(function (ContestedStateResultType) {
|