pshenmic-dpp 2.0.0-dev.9 → 2.0.0
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 +164 -77
- package/dist/binaries/bindingsTypes.d.ts +903 -18
- package/dist/binaries/bindingsTypes.js +13 -0
- package/dist/binaries/memory.cjs +7 -0
- package/dist/binaries/memory.d.cts +2 -0
- package/dist/binaries/native/aarch64-apple-darwin/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/aarch64-pc-windows-msvc/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/aarch64-unknown-linux-gnu/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/aarch64-unknown-linux-musl/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/x86_64-apple-darwin/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/x86_64-pc-windows-msvc/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/x86_64-unknown-linux-gnu/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/x86_64-unknown-linux-musl/pshenmic_dpp.node +0 -0
- package/dist/binaries/node.cjs +71 -0
- package/dist/binaries/node.d.cts +2 -0
- package/dist/binaries/pshenmic_dpp.android.node/arm64-v8a/libpshenmic_dpp.so +0 -0
- package/dist/binaries/pshenmic_dpp.apple.node/Info.plist +29 -0
- package/dist/binaries/pshenmic_dpp.apple.node/ios-arm64-simulator/libpshenmic_dpp.framework/Info.plist +24 -0
- package/dist/binaries/pshenmic_dpp.apple.node/ios-arm64-simulator/libpshenmic_dpp.framework/libpshenmic_dpp +0 -0
- package/dist/binaries/pshenmic_dpp.apple.node/react-native-node-api-module +0 -0
- package/dist/binaries/pshenmic_dpp.d.ts +60 -0
- package/dist/binaries/pshenmic_dpp.js +1 -1
- package/dist/binaries/wasm/wasmBytes.cjs +4 -0
- package/dist/binaries/wasm/wasmBytes.d.cts +2 -0
- package/dist/binaries/wasm/workerBundle.cjs +6 -0
- package/dist/binaries/wasm/workerBundle.d.cts +2 -0
- package/dist/binaries/wasm.d.ts +60 -0
- package/dist/binaries/wasm.js +2 -44
- package/dist/binaries/wasmCreation.cjs +127 -0
- package/dist/binaries/wasmCreation.d.cts +4 -0
- package/dist/src/dpp/dpp.d.ts +32 -0
- package/dist/src/dpp/dpp.js +32 -0
- package/dist/src/dpp/enums.d.ts +1 -1
- package/dist/src/dpp/enums.js +1 -1
- package/dist/src/dpp/structs/AddressTransitions/AddressCreditWithdrawalTransition.d.ts +3 -1
- package/dist/src/dpp/structs/AddressTransitions/AddressCreditWithdrawalTransition.js +6 -0
- package/dist/src/dpp/structs/AddressTransitions/AddressFundingFromAssetLockTransition.d.ts +2 -1
- package/dist/src/dpp/structs/AddressTransitions/AddressFundingFromAssetLockTransition.js +3 -0
- package/dist/src/dpp/structs/AddressTransitions/AddressFundsTransferTransition.d.ts +3 -1
- package/dist/src/dpp/structs/AddressTransitions/AddressFundsTransferTransition.js +6 -0
- package/dist/src/dpp/structs/AddressTransitions/IdentityCreateFromAddressesTransition.d.ts +2 -1
- package/dist/src/dpp/structs/AddressTransitions/IdentityCreateFromAddressesTransition.js +3 -0
- package/dist/src/dpp/structs/AddressTransitions/IdentityCreditTransferToAddressesTransition.d.ts +2 -1
- package/dist/src/dpp/structs/AddressTransitions/IdentityCreditTransferToAddressesTransition.js +3 -0
- package/dist/src/dpp/structs/AddressTransitions/IdentityTopUpFromAddressesTransition.d.ts +2 -1
- package/dist/src/dpp/structs/AddressTransitions/IdentityTopUpFromAddressesTransition.js +3 -0
- package/dist/src/dpp/structs/Batch/BatchTransition.d.ts +2 -1
- package/dist/src/dpp/structs/Batch/BatchTransition.js +3 -0
- package/dist/src/dpp/structs/DataContractTransitions/DataContractCreateTransition.d.ts +2 -1
- package/dist/src/dpp/structs/DataContractTransitions/DataContractCreateTransition.js +3 -0
- package/dist/src/dpp/structs/DataContractTransitions/DataContractUpdateTransition.d.ts +2 -1
- package/dist/src/dpp/structs/DataContractTransitions/DataContractUpdateTransition.js +3 -0
- package/dist/src/dpp/structs/Identifier.js +3 -0
- package/dist/src/dpp/structs/IdentityTransitions/IdentityCreateTransition.d.ts +2 -1
- package/dist/src/dpp/structs/IdentityTransitions/IdentityCreateTransition.js +3 -0
- package/dist/src/dpp/structs/IdentityTransitions/IdentityCreditTransfer.d.ts +2 -1
- package/dist/src/dpp/structs/IdentityTransitions/IdentityCreditTransfer.js +3 -0
- package/dist/src/dpp/structs/IdentityTransitions/IdentityCreditWithdrawalTransition.d.ts +2 -1
- package/dist/src/dpp/structs/IdentityTransitions/IdentityCreditWithdrawalTransition.js +3 -0
- package/dist/src/dpp/structs/IdentityTransitions/IdentityTopUpTransition.d.ts +2 -1
- package/dist/src/dpp/structs/IdentityTransitions/IdentityTopUpTransition.js +3 -0
- package/dist/src/dpp/structs/IdentityTransitions/IdentityUpdateTransition.d.ts +2 -1
- package/dist/src/dpp/structs/IdentityTransitions/IdentityUpdateTransition.js +3 -0
- package/dist/src/dpp/structs/MasternodeVote/MasternodeVoteTransition.d.ts +2 -3
- package/dist/src/dpp/structs/MasternodeVote/MasternodeVoteTransition.js +3 -6
- package/dist/src/dpp/structs/Orchard/CommitmentTree.d.ts +14 -0
- package/dist/src/dpp/structs/Orchard/CommitmentTree.js +31 -0
- package/dist/src/dpp/structs/Orchard/FullViewingKey.d.ts +27 -0
- package/dist/src/dpp/structs/Orchard/FullViewingKey.js +45 -0
- package/dist/src/dpp/structs/Orchard/IdentityCreateFromShieldedPoolResult.d.ts +21 -0
- package/dist/src/dpp/structs/Orchard/IdentityCreateFromShieldedPoolResult.js +38 -0
- package/dist/src/dpp/structs/Orchard/IncomingViewingKey.d.ts +29 -0
- package/dist/src/dpp/structs/Orchard/IncomingViewingKey.js +44 -0
- package/dist/src/dpp/structs/Orchard/MerklePath.d.ts +11 -0
- package/dist/src/dpp/structs/Orchard/MerklePath.js +25 -0
- package/dist/src/dpp/structs/Orchard/Note.d.ts +18 -0
- package/dist/src/dpp/structs/Orchard/Note.js +42 -0
- package/dist/src/dpp/structs/Orchard/OrchardAddress.d.ts +27 -0
- package/dist/src/dpp/structs/Orchard/OrchardAddress.js +45 -0
- package/dist/src/dpp/structs/Orchard/OrchardProver.d.ts +19 -0
- package/dist/src/dpp/structs/Orchard/OrchardProver.js +34 -0
- package/dist/src/dpp/structs/Orchard/RecoveredNote.d.ts +19 -0
- package/dist/src/dpp/structs/Orchard/RecoveredNote.js +32 -0
- package/dist/src/dpp/structs/Orchard/ShieldedBuilder.d.ts +64 -0
- package/dist/src/dpp/structs/Orchard/ShieldedBuilder.js +79 -0
- package/dist/src/dpp/structs/Orchard/ShieldedMemo.d.ts +11 -0
- package/dist/src/dpp/structs/Orchard/ShieldedMemo.js +25 -0
- package/dist/src/dpp/structs/Orchard/ShieldedOutput.d.ts +23 -0
- package/dist/src/dpp/structs/Orchard/ShieldedOutput.js +41 -0
- package/dist/src/dpp/structs/Orchard/ShieldedWithdrawalResult.d.ts +11 -0
- package/dist/src/dpp/structs/Orchard/ShieldedWithdrawalResult.js +18 -0
- package/dist/src/dpp/structs/Orchard/SpendableNote.d.ts +13 -0
- package/dist/src/dpp/structs/Orchard/SpendableNote.js +27 -0
- package/dist/src/dpp/structs/PlatformAddress/PlatformAddress.d.ts +9 -1
- package/dist/src/dpp/structs/PlatformAddress/PlatformAddress.js +10 -0
- package/dist/src/dpp/structs/ShieldedTransitions/IdentityCreateFromShieldedPoolTransition.d.ts +32 -0
- package/dist/src/dpp/structs/ShieldedTransitions/IdentityCreateFromShieldedPoolTransition.js +76 -0
- package/dist/src/dpp/structs/ShieldedTransitions/SerializedAction.d.ts +19 -0
- package/dist/src/dpp/structs/ShieldedTransitions/SerializedAction.js +49 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldFromAssetLockTransition.d.ts +31 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldFromAssetLockTransition.js +80 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldTransition.d.ts +33 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldTransition.js +81 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldedTransferTransition.d.ts +22 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldedTransferTransition.js +54 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldedWithdrawalTransition.d.ts +30 -0
- package/dist/src/dpp/structs/ShieldedTransitions/ShieldedWithdrawalTransition.js +74 -0
- package/dist/src/dpp/structs/ShieldedTransitions/UnshieldTransition.d.ts +26 -0
- package/dist/src/dpp/structs/ShieldedTransitions/UnshieldTransition.js +62 -0
- package/dist/src/dpp/structs/StateTransition.d.ts +2 -1
- package/dist/src/dpp/structs/StateTransition.js +3 -0
- package/dist/src/dpp/types.d.ts +177 -3
- package/dist/src/dpp/verify/AddressFunds/utils.d.ts +5 -0
- package/dist/src/dpp/verify/AddressFunds/utils.js +28 -0
- package/dist/src/dpp/verify/AddressFunds/verifyAddressesBranchState.d.ts +12 -0
- package/dist/src/dpp/verify/AddressFunds/verifyAddressesBranchState.js +29 -0
- package/dist/src/dpp/verify/AddressFunds/verifyAddressesTrunkState.d.ts +9 -0
- package/dist/src/dpp/verify/AddressFunds/verifyAddressesTrunkState.js +30 -0
- package/dist/src/dpp/verify/AddressFunds/verifyRecentAddressBalanceChanges.d.ts +9 -0
- package/dist/src/dpp/verify/AddressFunds/verifyRecentAddressBalanceChanges.js +24 -0
- package/dist/src/dpp/verify/AddressFunds/verifyRecentCompactedAddressBalanceChanges.d.ts +10 -0
- package/dist/src/dpp/verify/AddressFunds/verifyRecentCompactedAddressBalanceChanges.js +30 -0
- package/dist/src/dpp/verify/Contested/verifyVotePollVoteStateProof.d.ts +1 -1
- package/dist/src/dpp/verify/Contested/verifyVotePollVoteStateProof.js +1 -1
- package/dist/src/dpp/verify/Shielded/verifyMostRecentShieldedAnchorProof.d.ts +2 -0
- package/dist/src/dpp/verify/Shielded/verifyMostRecentShieldedAnchorProof.js +9 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedAnchorsProof.d.ts +2 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedAnchorsProof.js +9 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedEncryptedNotesProof.d.ts +2 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedEncryptedNotesProof.js +15 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedNotesCountProof.d.ts +2 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedNotesCountProof.js +9 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedNullifiersProof.d.ts +2 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedNullifiersProof.js +12 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedPoolStateProof.d.ts +2 -0
- package/dist/src/dpp/verify/Shielded/verifyShieldedPoolStateProof.js +9 -0
- package/dist/src/dpp/verify/StateTransition/utils.js +76 -11
- package/dist/src/dpp/verify/StateTransition/verifyStateTransitionResult.js +2 -1
- package/dist/src/dpp/verify/System/verifyFinalizedEpochInfosProof.d.ts +2 -0
- package/dist/src/dpp/verify/System/verifyFinalizedEpochInfosProof.js +27 -0
- package/dist/src/native.d.ts +3 -0
- package/dist/src/native.js +8 -0
- package/dist/utils/{base122.js → base122.cjs} +3 -1
- package/package.json +17 -27
- package/tests/unit/AddressTransitionsFees.spec.ts +274 -0
- package/tests/unit/DataContract.spec.ts +281 -0
- package/tests/unit/DynamicValue.spec.ts +2 -2
- package/tests/unit/Identifier.spec.ts +1 -1
- package/tests/unit/Identity.spec.ts +1 -1
- package/tests/unit/IdentityPublicKey.spec.ts +1 -1
- package/tests/unit/NodeApi.spec.ts +49 -0
- package/tests/unit/Shielded.spec.ts +555 -0
- package/tests/unit/ShieldedTransitions.spec.ts +877 -0
- package/tests/unit/StateTransitionFees.spec.ts +177 -0
- package/tests/unit/TokenConfiguration.spec.ts +114 -0
- package/tests/unit/WebAssembly.spec.ts +88 -0
- package/tests/unit/utils/buildTokenConfiguration.ts +66 -0
- package/dist/binaries/pshenmic_dpp.android.node/x86_64/libpshenmic_dpp.so +0 -0
- package/dist/binaries/wasm/wasmBytes.d.ts +0 -2
- package/dist/binaries/wasm/wasmBytes.js +0 -2
- /package/dist/utils/{base122.d.ts → base122.d.cts} +0 -0
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ShieldedMemoWASM,
|
|
3
|
+
OrchardAddressWASM,
|
|
4
|
+
FullViewingKeyWASM,
|
|
5
|
+
IncomingViewingKeyWASM,
|
|
6
|
+
orchardOvkFromSeed,
|
|
7
|
+
NoteWASM,
|
|
8
|
+
MerklePathWASM,
|
|
9
|
+
SpendableNoteWASM,
|
|
10
|
+
CommitmentTreeWASM,
|
|
11
|
+
ShieldedBuilderWASM,
|
|
12
|
+
OrchardProverWASM,
|
|
13
|
+
InputAddressWASM,
|
|
14
|
+
AddressFundsFeeStrategyStepWASM,
|
|
15
|
+
PrivateKeyWASM,
|
|
16
|
+
PlatformAddressWASM,
|
|
17
|
+
ShieldTransitionWASM,
|
|
18
|
+
StateTransitionWASM
|
|
19
|
+
} from 'pshenmic-dpp'
|
|
20
|
+
|
|
21
|
+
// Deterministic 64-byte BIP-39-style seed. Orchard derives via ZIP-32
|
|
22
|
+
// (m/32'/coinType'/account'), so any 64 bytes is a valid seed for derivation.
|
|
23
|
+
const SEED = new Uint8Array(64)
|
|
24
|
+
for (let i = 0; i < 64; i++) SEED[i] = (i * 7 + 1) & 0xff
|
|
25
|
+
|
|
26
|
+
const COIN_TYPE = 1 // testnets
|
|
27
|
+
const ACCOUNT = 0
|
|
28
|
+
|
|
29
|
+
// A funded testnet WIF reused across the builder/deposit tests.
|
|
30
|
+
const WIF = 'cUy4wbim4y9NDwC24omx8oWY5WqfmjSU2gdcZtTXza2xDCAkQXRP'
|
|
31
|
+
|
|
32
|
+
// The memo payload field is a fixed 32 bytes (MEMO_PAYLOAD_SIZE) on the wire.
|
|
33
|
+
// Text memos may be shorter and are zero-padded to it; `other` payloads are
|
|
34
|
+
// taken verbatim and so must match it exactly.
|
|
35
|
+
const MEMO_PAYLOAD_SIZE = 32
|
|
36
|
+
|
|
37
|
+
const DASH = 100_000_000_000n
|
|
38
|
+
|
|
39
|
+
function hexToBytes (hex: string): Uint8Array {
|
|
40
|
+
return Uint8Array.from(hex.match(/../g)!.map((x) => parseInt(x, 16)))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// A canonical Orchard note: rho is a valid Pallas base-field element (value 1),
|
|
44
|
+
// rseed is non-degenerate. Produces a valid commitment (cmx) the tree accepts.
|
|
45
|
+
function createTestNote (value: bigint = 1000n): NoteWASM {
|
|
46
|
+
const address = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
47
|
+
const rho = new Uint8Array(32)
|
|
48
|
+
rho[0] = 1
|
|
49
|
+
const rseed = new Uint8Array(32).fill(0x42)
|
|
50
|
+
return new NoteWASM(address, value, rho, rseed)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Platform P2PKH address (21 bytes: 0x00 type + 20-byte pubkey hash) for a key.
|
|
54
|
+
function platformAddressFromPrivateKey (pk: PrivateKeyWASM): PlatformAddressWASM {
|
|
55
|
+
const hash = hexToBytes(pk.getPublicKeyHash())
|
|
56
|
+
const bytes = new Uint8Array(21)
|
|
57
|
+
bytes[0] = 0x00
|
|
58
|
+
bytes.set(hash, 1)
|
|
59
|
+
return PlatformAddressWASM.fromBytes(bytes)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('ShieldedMemo', function () {
|
|
63
|
+
describe('empty', function () {
|
|
64
|
+
test('should create an empty memo', function () {
|
|
65
|
+
const memo = ShieldedMemoWASM.empty()
|
|
66
|
+
|
|
67
|
+
expect(memo).toBeInstanceOf(ShieldedMemoWASM)
|
|
68
|
+
expect(memo.toBytes().length).toEqual(36) // on-wire memo size
|
|
69
|
+
expect(memo.toString()).toEqual('')
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('fromString', function () {
|
|
74
|
+
test('should create a text memo from a 32-char string', function () {
|
|
75
|
+
const text = 'A'.repeat(MEMO_PAYLOAD_SIZE)
|
|
76
|
+
const memo = ShieldedMemoWASM.fromString(text)
|
|
77
|
+
|
|
78
|
+
expect(memo).toBeInstanceOf(ShieldedMemoWASM)
|
|
79
|
+
expect(memo.toBytes().length).toEqual(36)
|
|
80
|
+
expect(memo.toString()).toEqual(text)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test('should accept text shorter than the payload', function () {
|
|
84
|
+
const text = 'thanks for lunch' // 16 bytes, half the payload
|
|
85
|
+
const memo = ShieldedMemoWASM.fromString(text)
|
|
86
|
+
const bytes = memo.toBytes()
|
|
87
|
+
|
|
88
|
+
// The wire memo stays a fixed 36 bytes: a 4-byte little-endian kind tag
|
|
89
|
+
// (1 = text), the utf-8 text, then zero padding out to the 32-byte
|
|
90
|
+
// payload. The padding is not part of the decoded text.
|
|
91
|
+
expect(bytes.length).toEqual(36)
|
|
92
|
+
expect(Array.from(bytes.slice(0, 4))).toEqual([1, 0, 0, 0])
|
|
93
|
+
expect(new TextDecoder().decode(bytes.slice(4, 4 + text.length))).toEqual(text)
|
|
94
|
+
expect(bytes.slice(4 + text.length).every((byte) => byte === 0)).toBe(true)
|
|
95
|
+
expect(memo.toString()).toEqual(text)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('should accept an empty string', function () {
|
|
99
|
+
const memo = ShieldedMemoWASM.fromString('')
|
|
100
|
+
|
|
101
|
+
expect(memo.toBytes().length).toEqual(36)
|
|
102
|
+
expect(memo.toString()).toEqual('')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('should count multi-byte characters by their utf-8 byte length', function () {
|
|
106
|
+
// 8 x U+1F355 = 32 bytes, exactly the payload; 9 would be 36 bytes.
|
|
107
|
+
const memo = ShieldedMemoWASM.fromString('🍕'.repeat(8))
|
|
108
|
+
|
|
109
|
+
expect(memo.toString()).toEqual('🍕'.repeat(8))
|
|
110
|
+
expect(() => ShieldedMemoWASM.fromString('🍕'.repeat(9))).toThrow()
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('should reject text longer than 32 bytes', function () {
|
|
114
|
+
expect(() => ShieldedMemoWASM.fromString('A'.repeat(MEMO_PAYLOAD_SIZE + 1))).toThrow()
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
describe('other', function () {
|
|
119
|
+
test('should create a typed memo from a 32-byte payload', function () {
|
|
120
|
+
const payload = new Uint8Array(MEMO_PAYLOAD_SIZE).fill(9)
|
|
121
|
+
const memo = ShieldedMemoWASM.other(7, payload)
|
|
122
|
+
|
|
123
|
+
expect(memo).toBeInstanceOf(ShieldedMemoWASM)
|
|
124
|
+
expect(memo.toBytes().length).toEqual(36)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test('should reject a payload that is not 32 bytes', function () {
|
|
128
|
+
expect(() => ShieldedMemoWASM.other(7, new Uint8Array([1, 2, 3]))).toThrow()
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
describe('OrchardAddress', function () {
|
|
134
|
+
describe('fromSeed', function () {
|
|
135
|
+
test('should derive an address from a seed', function () {
|
|
136
|
+
const address = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
137
|
+
|
|
138
|
+
expect(address).toBeInstanceOf(OrchardAddressWASM)
|
|
139
|
+
expect(address.bytes().length).toEqual(43)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('should be deterministic for the same seed', function () {
|
|
143
|
+
const a = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
144
|
+
const b = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
145
|
+
|
|
146
|
+
expect(a.bytes()).toEqual(b.bytes())
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
describe('serialization', function () {
|
|
151
|
+
test('should roundtrip through bytes', function () {
|
|
152
|
+
const address = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
153
|
+
const restored = OrchardAddressWASM.fromBytes(address.bytes())
|
|
154
|
+
|
|
155
|
+
expect(restored.bytes()).toEqual(address.bytes())
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test('should roundtrip through bech32m', function () {
|
|
159
|
+
const address = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
160
|
+
const bech32m = address.toBech32m('testnet')
|
|
161
|
+
const restored = OrchardAddressWASM.fromBech32m(bech32m)
|
|
162
|
+
|
|
163
|
+
expect(restored.bytes()).toEqual(address.bytes())
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
describe('orchardOvkFromSeed', function () {
|
|
168
|
+
test('should derive a 32-byte outgoing viewing key', function () {
|
|
169
|
+
const ovk = orchardOvkFromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
170
|
+
|
|
171
|
+
expect(ovk.length).toEqual(32)
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
describe('fromFullViewingKey', function () {
|
|
176
|
+
test('should match the address derived from the same seed', function () {
|
|
177
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
178
|
+
|
|
179
|
+
expect(OrchardAddressWASM.fromFullViewingKey(fvk).bytes())
|
|
180
|
+
.toEqual(OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT).bytes())
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
test('should derive a different address per diversifier index', function () {
|
|
184
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
185
|
+
|
|
186
|
+
expect(OrchardAddressWASM.fromFullViewingKey(fvk, 1).bytes())
|
|
187
|
+
.not.toEqual(OrchardAddressWASM.fromFullViewingKey(fvk, 0).bytes())
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
test('should derive a different address per scope', function () {
|
|
191
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
192
|
+
|
|
193
|
+
expect(OrchardAddressWASM.fromFullViewingKey(fvk, 0, 'internal').bytes())
|
|
194
|
+
.not.toEqual(OrchardAddressWASM.fromFullViewingKey(fvk, 0, 'external').bytes())
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
test('should reject an unknown scope', function () {
|
|
198
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
199
|
+
|
|
200
|
+
expect(() => OrchardAddressWASM.fromFullViewingKey(fvk, 0, 'nope' as any)).toThrow()
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
describe('fromIncomingViewingKey', function () {
|
|
205
|
+
test('should match the address derived from the same seed', function () {
|
|
206
|
+
const ivk = IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
207
|
+
|
|
208
|
+
expect(OrchardAddressWASM.fromIncomingViewingKey(ivk).bytes())
|
|
209
|
+
.toEqual(OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT).bytes())
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
test('should derive a different address per diversifier index', function () {
|
|
213
|
+
const ivk = IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
214
|
+
|
|
215
|
+
expect(OrchardAddressWASM.fromIncomingViewingKey(ivk, 7).bytes())
|
|
216
|
+
.not.toEqual(OrchardAddressWASM.fromIncomingViewingKey(ivk, 0).bytes())
|
|
217
|
+
})
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
describe('fromSeed scope', function () {
|
|
221
|
+
test('should derive the internal-scope address', function () {
|
|
222
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
223
|
+
|
|
224
|
+
expect(OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT, 0, 'internal').bytes())
|
|
225
|
+
.toEqual(OrchardAddressWASM.fromFullViewingKey(fvk, 0, 'internal').bytes())
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
describe('FullViewingKey', function () {
|
|
231
|
+
describe('fromSeed', function () {
|
|
232
|
+
test('should derive a 96-byte key deterministically', function () {
|
|
233
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
234
|
+
|
|
235
|
+
expect(fvk).toBeInstanceOf(FullViewingKeyWASM)
|
|
236
|
+
expect(fvk.bytes().length).toEqual(96)
|
|
237
|
+
expect(fvk.bytes()).toEqual(FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT).bytes())
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
test('should differ per account', function () {
|
|
241
|
+
expect(FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, 1).bytes())
|
|
242
|
+
.not.toEqual(FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, 0).bytes())
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
test('should reject a hardened account index', function () {
|
|
246
|
+
expect(() => FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, 0x80000000)).toThrow()
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
describe('serialization', function () {
|
|
251
|
+
test('should roundtrip through bytes', function () {
|
|
252
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
253
|
+
|
|
254
|
+
expect(FullViewingKeyWASM.fromBytes(fvk.bytes()).bytes()).toEqual(fvk.bytes())
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
test('should reject bytes of the wrong length', function () {
|
|
258
|
+
expect(() => FullViewingKeyWASM.fromBytes(new Uint8Array(64))).toThrow()
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
test('should reject bytes that are not a valid key', function () {
|
|
262
|
+
expect(() => FullViewingKeyWASM.fromBytes(new Uint8Array(96).fill(0xff))).toThrow()
|
|
263
|
+
})
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
describe('toOvk', function () {
|
|
267
|
+
test('should match orchardOvkFromSeed for the external scope', function () {
|
|
268
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
269
|
+
|
|
270
|
+
expect(fvk.toOvk()).toEqual(orchardOvkFromSeed(SEED, COIN_TYPE, ACCOUNT))
|
|
271
|
+
expect(fvk.toOvk('internal')).not.toEqual(fvk.toOvk('external'))
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
describe('toIvk', function () {
|
|
276
|
+
test('should derive the same key as IncomingViewingKey.fromSeed', function () {
|
|
277
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
278
|
+
|
|
279
|
+
expect(fvk.toIvk().bytes())
|
|
280
|
+
.toEqual(IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT).bytes())
|
|
281
|
+
expect(fvk.toIvk('internal').bytes()).not.toEqual(fvk.toIvk('external').bytes())
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
describe('scopeForAddress', function () {
|
|
286
|
+
test('should report the scope of its own addresses', function () {
|
|
287
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
288
|
+
|
|
289
|
+
expect(fvk.scopeForAddress(fvk.address(0, 'external'))).toEqual('External')
|
|
290
|
+
expect(fvk.scopeForAddress(fvk.address(0, 'internal'))).toEqual('Internal')
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
test('should return null for a foreign address', function () {
|
|
294
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
295
|
+
const other = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, 1)
|
|
296
|
+
|
|
297
|
+
expect(fvk.scopeForAddress(other.address())).toBeNull()
|
|
298
|
+
})
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
describe('IncomingViewingKey', function () {
|
|
303
|
+
describe('fromSeed', function () {
|
|
304
|
+
test('should derive a 64-byte key deterministically', function () {
|
|
305
|
+
const ivk = IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
306
|
+
|
|
307
|
+
expect(ivk).toBeInstanceOf(IncomingViewingKeyWASM)
|
|
308
|
+
expect(ivk.bytes().length).toEqual(64)
|
|
309
|
+
expect(ivk.bytes()).toEqual(IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT).bytes())
|
|
310
|
+
})
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
describe('fromFullViewingKey', function () {
|
|
314
|
+
test('should match the key derived from the same seed', function () {
|
|
315
|
+
const fvk = FullViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
316
|
+
|
|
317
|
+
expect(IncomingViewingKeyWASM.fromFullViewingKey(fvk).bytes())
|
|
318
|
+
.toEqual(IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT).bytes())
|
|
319
|
+
})
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
describe('serialization', function () {
|
|
323
|
+
test('should roundtrip through bytes', function () {
|
|
324
|
+
const ivk = IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
325
|
+
|
|
326
|
+
expect(IncomingViewingKeyWASM.fromBytes(ivk.bytes()).bytes()).toEqual(ivk.bytes())
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
test('should reject bytes of the wrong length', function () {
|
|
330
|
+
expect(() => IncomingViewingKeyWASM.fromBytes(new Uint8Array(96))).toThrow()
|
|
331
|
+
})
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
describe('diversifierIndex', function () {
|
|
335
|
+
test('should recover the index of its own address', function () {
|
|
336
|
+
const ivk = IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
337
|
+
|
|
338
|
+
expect(ivk.diversifierIndex(ivk.address(5))).toEqual(5)
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
test('should return null for a foreign address', function () {
|
|
342
|
+
const ivk = IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
343
|
+
const other = IncomingViewingKeyWASM.fromSeed(SEED, COIN_TYPE, 1)
|
|
344
|
+
|
|
345
|
+
expect(ivk.diversifierIndex(other.address())).toBeNull()
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
describe('Note', function () {
|
|
351
|
+
describe('constructor', function () {
|
|
352
|
+
test('should create a note from valid parts', function () {
|
|
353
|
+
const note = createTestNote()
|
|
354
|
+
|
|
355
|
+
expect(note).toBeInstanceOf(NoteWASM)
|
|
356
|
+
})
|
|
357
|
+
|
|
358
|
+
test('should reject an invalid rho', function () {
|
|
359
|
+
const address = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
360
|
+
const invalidRho = new Uint8Array(32).fill(0xff) // not a canonical field element
|
|
361
|
+
const rseed = new Uint8Array(32).fill(0x42)
|
|
362
|
+
|
|
363
|
+
expect(() => new NoteWASM(address, 1000n, invalidRho, rseed)).toThrow()
|
|
364
|
+
})
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
describe('getters', function () {
|
|
368
|
+
test('should return all fields', function () {
|
|
369
|
+
const note = createTestNote(1234n)
|
|
370
|
+
|
|
371
|
+
expect(note.address).toBeInstanceOf(OrchardAddressWASM)
|
|
372
|
+
expect(note.value).toEqual(1234n)
|
|
373
|
+
expect(note.rho.length).toEqual(32)
|
|
374
|
+
expect(note.rseed.length).toEqual(32)
|
|
375
|
+
expect(note.cmx.length).toEqual(32)
|
|
376
|
+
})
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
describe('setters', function () {
|
|
380
|
+
test('should set the value', function () {
|
|
381
|
+
const note = createTestNote()
|
|
382
|
+
|
|
383
|
+
note.value = 5000n
|
|
384
|
+
expect(note.value).toEqual(5000n)
|
|
385
|
+
})
|
|
386
|
+
})
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
describe('CommitmentTree', function () {
|
|
390
|
+
describe('append / witness / anchor', function () {
|
|
391
|
+
test('should append a commitment and produce a witness and anchor', function () {
|
|
392
|
+
const note = createTestNote()
|
|
393
|
+
const tree = new CommitmentTreeWASM()
|
|
394
|
+
|
|
395
|
+
tree.append(note.cmx, true)
|
|
396
|
+
tree.checkpoint(1)
|
|
397
|
+
|
|
398
|
+
expect(tree.maxLeafPosition()).toEqual(0)
|
|
399
|
+
|
|
400
|
+
const path = tree.witness(0)
|
|
401
|
+
expect(path).toBeInstanceOf(MerklePathWASM)
|
|
402
|
+
expect(path!.authPath.length).toEqual(32)
|
|
403
|
+
|
|
404
|
+
expect(tree.anchor().length).toEqual(32)
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
test('should reject a cmx that is not 32 bytes', function () {
|
|
408
|
+
const tree = new CommitmentTreeWASM()
|
|
409
|
+
|
|
410
|
+
expect(() => tree.append(new Uint8Array(16), true)).toThrow()
|
|
411
|
+
})
|
|
412
|
+
})
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
describe('MerklePath', function () {
|
|
416
|
+
let position: number
|
|
417
|
+
let authPath: Uint8Array[]
|
|
418
|
+
|
|
419
|
+
beforeAll(function () {
|
|
420
|
+
const note = createTestNote()
|
|
421
|
+
const tree = new CommitmentTreeWASM()
|
|
422
|
+
tree.append(note.cmx, true)
|
|
423
|
+
tree.checkpoint(1)
|
|
424
|
+
const path = tree.witness(0)!
|
|
425
|
+
position = path.position
|
|
426
|
+
authPath = path.authPath
|
|
427
|
+
})
|
|
428
|
+
|
|
429
|
+
describe('constructor', function () {
|
|
430
|
+
test('should create a MerklePath from parts', function () {
|
|
431
|
+
const path = new MerklePathWASM(position, authPath)
|
|
432
|
+
|
|
433
|
+
expect(path).toBeInstanceOf(MerklePathWASM)
|
|
434
|
+
})
|
|
435
|
+
})
|
|
436
|
+
|
|
437
|
+
describe('getters', function () {
|
|
438
|
+
test('should return all fields', function () {
|
|
439
|
+
const path = new MerklePathWASM(position, authPath)
|
|
440
|
+
|
|
441
|
+
expect(path.position).toEqual(position)
|
|
442
|
+
expect(path.authPath.length).toEqual(32)
|
|
443
|
+
expect(path.authPath[0].length).toEqual(32)
|
|
444
|
+
})
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
describe('setters', function () {
|
|
448
|
+
test('should set the position', function () {
|
|
449
|
+
const path = new MerklePathWASM(position, authPath)
|
|
450
|
+
|
|
451
|
+
path.position = 0
|
|
452
|
+
expect(path.position).toEqual(0)
|
|
453
|
+
})
|
|
454
|
+
})
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
describe('SpendableNote', function () {
|
|
458
|
+
let note: NoteWASM
|
|
459
|
+
let merklePath: MerklePathWASM
|
|
460
|
+
|
|
461
|
+
beforeAll(function () {
|
|
462
|
+
note = createTestNote()
|
|
463
|
+
const tree = new CommitmentTreeWASM()
|
|
464
|
+
tree.append(note.cmx, true)
|
|
465
|
+
tree.checkpoint(1)
|
|
466
|
+
merklePath = tree.witness(0)!
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
describe('constructor', function () {
|
|
470
|
+
test('should create a SpendableNote from a note and witness', function () {
|
|
471
|
+
const spendable = new SpendableNoteWASM(note, merklePath)
|
|
472
|
+
|
|
473
|
+
expect(spendable).toBeInstanceOf(SpendableNoteWASM)
|
|
474
|
+
})
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
describe('getters', function () {
|
|
478
|
+
test('should return the note and merkle path', function () {
|
|
479
|
+
const spendable = new SpendableNoteWASM(note, merklePath)
|
|
480
|
+
|
|
481
|
+
expect(spendable.note).toBeInstanceOf(NoteWASM)
|
|
482
|
+
expect(spendable.note.value).toEqual(note.value)
|
|
483
|
+
expect(spendable.merklePath).toBeInstanceOf(MerklePathWASM)
|
|
484
|
+
expect(spendable.merklePath.position).toEqual(merklePath.position)
|
|
485
|
+
})
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
describe('setters', function () {
|
|
489
|
+
test('should set the note', function () {
|
|
490
|
+
const spendable = new SpendableNoteWASM(note, merklePath)
|
|
491
|
+
const newNote = createTestNote(2000n)
|
|
492
|
+
|
|
493
|
+
spendable.note = newNote
|
|
494
|
+
expect(spendable.note.value).toEqual(2000n)
|
|
495
|
+
})
|
|
496
|
+
})
|
|
497
|
+
})
|
|
498
|
+
|
|
499
|
+
describe('OrchardProver', function () {
|
|
500
|
+
// Initializing the prover builds the Halo 2 proving key (~seconds).
|
|
501
|
+
test('should construct a prover', async function () {
|
|
502
|
+
const prover = new OrchardProverWASM()
|
|
503
|
+
await prover.init()
|
|
504
|
+
|
|
505
|
+
expect(prover).toBeInstanceOf(OrchardProverWASM)
|
|
506
|
+
}, 30000)
|
|
507
|
+
})
|
|
508
|
+
|
|
509
|
+
describe('ShieldedBuilder', function () {
|
|
510
|
+
// The builder builds its own Halo 2 proving key on init (~seconds),
|
|
511
|
+
// so build it once and reuse it across the deposit test.
|
|
512
|
+
let builder: ShieldedBuilderWASM
|
|
513
|
+
|
|
514
|
+
beforeAll(async function () {
|
|
515
|
+
builder = new ShieldedBuilderWASM()
|
|
516
|
+
await builder.init()
|
|
517
|
+
}, 30000)
|
|
518
|
+
|
|
519
|
+
describe('constructor', function () {
|
|
520
|
+
test('should construct a builder', function () {
|
|
521
|
+
expect(builder).toBeInstanceOf(ShieldedBuilderWASM)
|
|
522
|
+
})
|
|
523
|
+
})
|
|
524
|
+
|
|
525
|
+
describe('shield (transparent -> pool deposit)', function () {
|
|
526
|
+
test('should build and prove a shield transition', async function () {
|
|
527
|
+
const recipient = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
528
|
+
const senderOvk = orchardOvkFromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
529
|
+
|
|
530
|
+
const privateKey = PrivateKeyWASM.fromWIF(WIF)
|
|
531
|
+
const inputAddress = platformAddressFromPrivateKey(privateKey)
|
|
532
|
+
// address, nonce, balance — balance must cover amount + fee.
|
|
533
|
+
const input = new InputAddressWASM(inputAddress, 0, DASH / 2n)
|
|
534
|
+
|
|
535
|
+
const st = await builder.shield(
|
|
536
|
+
recipient,
|
|
537
|
+
(DASH * 4n) / 10n, // 0.4 DASH into the pool
|
|
538
|
+
[input],
|
|
539
|
+
[privateKey],
|
|
540
|
+
[AddressFundsFeeStrategyStepWASM.DeductFromInput(0)],
|
|
541
|
+
0, // user fee increase
|
|
542
|
+
ShieldedMemoWASM.empty(),
|
|
543
|
+
senderOvk
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
expect(st).toBeInstanceOf(StateTransitionWASM)
|
|
547
|
+
|
|
548
|
+
const transition = ShieldTransitionWASM.fromStateTransition(st)
|
|
549
|
+
expect(transition).toBeInstanceOf(ShieldTransitionWASM)
|
|
550
|
+
expect(transition.amount).toEqual((DASH * 4n) / 10n)
|
|
551
|
+
expect(transition.actions.length).toBeGreaterThanOrEqual(1)
|
|
552
|
+
expect(transition.proof.length).toBeGreaterThan(0)
|
|
553
|
+
}, 30000)
|
|
554
|
+
})
|
|
555
|
+
})
|