@taquito/sapling 14.0.0-beta-RC.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/LICENSE +7 -0
- package/README.md +93 -0
- package/dist/lib/constants.js +8 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/error.js +72 -0
- package/dist/lib/error.js.map +1 -0
- package/dist/lib/sapling-forger/sapling-forger.js +101 -0
- package/dist/lib/sapling-forger/sapling-forger.js.map +1 -0
- package/dist/lib/sapling-keys/helpers.js +30 -0
- package/dist/lib/sapling-keys/helpers.js.map +1 -0
- package/dist/lib/sapling-keys/in-memory-proving-key.js +84 -0
- package/dist/lib/sapling-keys/in-memory-proving-key.js.map +1 -0
- package/dist/lib/sapling-keys/in-memory-spending-key.js +146 -0
- package/dist/lib/sapling-keys/in-memory-spending-key.js.map +1 -0
- package/dist/lib/sapling-keys/in-memory-viewing-key.js +101 -0
- package/dist/lib/sapling-keys/in-memory-viewing-key.js.map +1 -0
- package/dist/lib/sapling-module-wrapper.js +83 -0
- package/dist/lib/sapling-module-wrapper.js.map +1 -0
- package/dist/lib/sapling-state/sapling-state.js +171 -0
- package/dist/lib/sapling-state/sapling-state.js.map +1 -0
- package/dist/lib/sapling-state/utils.js +60 -0
- package/dist/lib/sapling-state/utils.js.map +1 -0
- package/dist/lib/sapling-tx-builder/sapling-transactions-builder.js +288 -0
- package/dist/lib/sapling-tx-builder/sapling-transactions-builder.js.map +1 -0
- package/dist/lib/sapling-tx-viewer/helpers.js +31 -0
- package/dist/lib/sapling-tx-viewer/helpers.js.map +1 -0
- package/dist/lib/sapling-tx-viewer/sapling-transaction-viewer.js +230 -0
- package/dist/lib/sapling-tx-viewer/sapling-transaction-viewer.js.map +1 -0
- package/dist/lib/taquito-sapling.js +293 -0
- package/dist/lib/taquito-sapling.js.map +1 -0
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/version.js +9 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/taquito-sapling.es6.js +1456 -0
- package/dist/taquito-sapling.es6.js.map +1 -0
- package/dist/taquito-sapling.umd.js +1485 -0
- package/dist/taquito-sapling.umd.js.map +1 -0
- package/dist/types/constants.d.ts +5 -0
- package/dist/types/error.d.ts +50 -0
- package/dist/types/sapling-forger/sapling-forger.d.ts +30 -0
- package/dist/types/sapling-keys/helpers.d.ts +2 -0
- package/dist/types/sapling-keys/in-memory-proving-key.d.ts +35 -0
- package/dist/types/sapling-keys/in-memory-spending-key.d.ts +53 -0
- package/dist/types/sapling-keys/in-memory-viewing-key.d.ts +48 -0
- package/dist/types/sapling-module-wrapper.d.ts +19 -0
- package/dist/types/sapling-state/sapling-state.d.ts +55 -0
- package/dist/types/sapling-state/utils.d.ts +22 -0
- package/dist/types/sapling-tx-builder/sapling-transactions-builder.d.ts +32 -0
- package/dist/types/sapling-tx-viewer/helpers.d.ts +11 -0
- package/dist/types/sapling-tx-viewer/sapling-transaction-viewer.d.ts +50 -0
- package/dist/types/taquito-sapling.d.ts +81 -0
- package/dist/types/types.d.ts +147 -0
- package/dist/types/version.d.ts +4 -0
- package/fetch-sapling-params.js +41 -0
- package/package.json +112 -0
|
@@ -0,0 +1,1485 @@
|
|
|
1
|
+
(function (global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('bignumber.js'), require('@taquito/taquito'), require('@taquito/utils'), require('@airgap/sapling-wasm'), require('blakejs'), require('@stablelib/nacl'), require('@stablelib/random'), require('bip39'), require('typedarray-to-buffer'), require('pbkdf2')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'bignumber.js', '@taquito/taquito', '@taquito/utils', '@airgap/sapling-wasm', 'blakejs', '@stablelib/nacl', '@stablelib/random', 'bip39', 'typedarray-to-buffer', 'pbkdf2'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.taquitoSapling = {}, global.BigNumber, global.taquito, global.utils, global.sapling, global.blake, global.nacl, global.random, global.bip39, global.toBuffer, global.pbkdf2));
|
|
5
|
+
})(this, (function (exports, BigNumber, taquito, utils, sapling, blake, nacl, random, bip39, toBuffer, pbkdf2) { 'use strict';
|
|
6
|
+
|
|
7
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
|
+
|
|
9
|
+
function _interopNamespace(e) {
|
|
10
|
+
if (e && e.__esModule) return e;
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n["default"] = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var BigNumber__default = /*#__PURE__*/_interopDefaultLegacy(BigNumber);
|
|
28
|
+
var sapling__namespace = /*#__PURE__*/_interopNamespace(sapling);
|
|
29
|
+
var blake__default = /*#__PURE__*/_interopDefaultLegacy(blake);
|
|
30
|
+
var bip39__namespace = /*#__PURE__*/_interopNamespace(bip39);
|
|
31
|
+
var toBuffer__default = /*#__PURE__*/_interopDefaultLegacy(toBuffer);
|
|
32
|
+
var pbkdf2__default = /*#__PURE__*/_interopDefaultLegacy(pbkdf2);
|
|
33
|
+
|
|
34
|
+
/******************************************************************************
|
|
35
|
+
Copyright (c) Microsoft Corporation.
|
|
36
|
+
|
|
37
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
38
|
+
purpose with or without fee is hereby granted.
|
|
39
|
+
|
|
40
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
41
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
42
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
43
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
44
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
45
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
46
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
47
|
+
***************************************************************************** */
|
|
48
|
+
|
|
49
|
+
function __rest(s, e) {
|
|
50
|
+
var t = {};
|
|
51
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
52
|
+
t[p] = s[p];
|
|
53
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
54
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
55
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
56
|
+
t[p[i]] = s[p[i]];
|
|
57
|
+
}
|
|
58
|
+
return t;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
62
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
63
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
64
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
65
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
66
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
67
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function __classPrivateFieldGet(receiver, state, kind, f) {
|
|
72
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
73
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
74
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
78
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
79
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
80
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
81
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @category Error
|
|
86
|
+
* @description Error indicating that the spending key is invalid
|
|
87
|
+
*/
|
|
88
|
+
class InvalidSpendingKey extends Error {
|
|
89
|
+
constructor(sk, reason = 'The spending key is invalid') {
|
|
90
|
+
super(`${reason}: ${sk}`);
|
|
91
|
+
this.name = 'InvalidSpendingKey';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* @category Error
|
|
96
|
+
* @description Error that indicates an invalid Merkle root being passed
|
|
97
|
+
*/
|
|
98
|
+
class InvalidMerkleRootError extends Error {
|
|
99
|
+
constructor(root) {
|
|
100
|
+
super(`The following Merkle tree is invalid: ${JSON.stringify(root)}`);
|
|
101
|
+
this.root = root;
|
|
102
|
+
this.name = 'InvalidMerkleRootError';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* @category Error
|
|
107
|
+
* @description Error that indicates a failure when trying to construct the Merkle tree
|
|
108
|
+
*/
|
|
109
|
+
class TreeConstructionFailure extends Error {
|
|
110
|
+
constructor(message) {
|
|
111
|
+
super(message);
|
|
112
|
+
this.message = message;
|
|
113
|
+
this.name = 'TreeConstructionFailure';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* @category Error
|
|
118
|
+
* @description Error indicating that the memo is invalid
|
|
119
|
+
*/
|
|
120
|
+
class InvalidMemo extends Error {
|
|
121
|
+
constructor(memo, errorDetail) {
|
|
122
|
+
super(`The memo '${memo}' is invalid. ${errorDetail}`);
|
|
123
|
+
this.name = 'InvalidMemo';
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* @category Error
|
|
128
|
+
* @description Error indicating that there is not enough balance to prepare the sapling transaction
|
|
129
|
+
*/
|
|
130
|
+
class InsufficientBalance extends Error {
|
|
131
|
+
constructor(realBalance, amountToSpend) {
|
|
132
|
+
super(`Unable to spend ${amountToSpend} mutez while the balance is only ${realBalance} mutez.`);
|
|
133
|
+
this.name = 'InsufficientBalance';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* @category Error
|
|
138
|
+
* @description Error indicating that a parameter is invalid
|
|
139
|
+
*/
|
|
140
|
+
class InvalidParameter extends Error {
|
|
141
|
+
constructor(message) {
|
|
142
|
+
super(message);
|
|
143
|
+
this.name = 'InvalidParameter';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function memoHexToUtf8(memo) {
|
|
148
|
+
const memoNoPadding = removeZeroPaddedBytesRight(memo);
|
|
149
|
+
return memoNoPadding === '' ? memoNoPadding : utils.bytes2Char(memoNoPadding);
|
|
150
|
+
}
|
|
151
|
+
function removeZeroPaddedBytesRight(memo) {
|
|
152
|
+
const matchZeroRight = memo.match(/^(.*?)(00)+$/);
|
|
153
|
+
return matchZeroRight ? matchZeroRight[1] : memo;
|
|
154
|
+
}
|
|
155
|
+
function readableFormat(saplingTransactionProperties) {
|
|
156
|
+
return {
|
|
157
|
+
value: convertValueToBigNumber(saplingTransactionProperties.value),
|
|
158
|
+
memo: memoHexToUtf8(Buffer.from(saplingTransactionProperties.memo).toString('hex')),
|
|
159
|
+
paymentAddress: utils.b58cencode(saplingTransactionProperties.paymentAddress, utils.prefix[utils.Prefix.ZET1]),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function convertValueToBigNumber(value) {
|
|
163
|
+
return new BigNumber__default["default"](Buffer.from(value).toString('hex'), 16);
|
|
164
|
+
}
|
|
165
|
+
function bufToUint8Array(buffer) {
|
|
166
|
+
return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength / Uint8Array.BYTES_PER_ELEMENT);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class SaplingForger {
|
|
170
|
+
/**
|
|
171
|
+
* @description Forge sapling transactions
|
|
172
|
+
* @param spendDescriptions the list of spend descriptions
|
|
173
|
+
* @param outputDescriptions the list of output descriptions
|
|
174
|
+
* @param signature signature hash
|
|
175
|
+
* @param balance balance of the Sapling contract (input/output difference)
|
|
176
|
+
* @param root root of the merkle tree
|
|
177
|
+
* @returns Forged sapling transaction of type Buffer
|
|
178
|
+
*/
|
|
179
|
+
forgeSaplingTransaction(tx) {
|
|
180
|
+
const spendBuf = this.forgeSpendDescriptions(tx.inputs);
|
|
181
|
+
const spend = Buffer.concat([utils.toHexBuf(spendBuf.length, 32), spendBuf]);
|
|
182
|
+
const outputBuf = this.forgeOutputDescriptions(tx.outputs);
|
|
183
|
+
const output = Buffer.concat([utils.toHexBuf(outputBuf.length, 32), outputBuf]);
|
|
184
|
+
const root = Buffer.from(tx.root, 'hex');
|
|
185
|
+
return Buffer.concat([
|
|
186
|
+
spend,
|
|
187
|
+
output,
|
|
188
|
+
tx.signature,
|
|
189
|
+
utils.toHexBuf(tx.balance, 64),
|
|
190
|
+
root,
|
|
191
|
+
utils.toHexBuf(tx.boundData.length, 32),
|
|
192
|
+
tx.boundData,
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* @description Forge list of spend descriptions
|
|
197
|
+
* @param spendDescriptions list of spend descriptions
|
|
198
|
+
* @returns concatenated forged bytes of type Buffer
|
|
199
|
+
*/
|
|
200
|
+
forgeSpendDescriptions(spendDescriptions) {
|
|
201
|
+
const descriptions = [];
|
|
202
|
+
for (const i of spendDescriptions) {
|
|
203
|
+
const buff = this.forgeSpendDescription(i);
|
|
204
|
+
descriptions.push(buff);
|
|
205
|
+
}
|
|
206
|
+
return Buffer.concat(descriptions);
|
|
207
|
+
}
|
|
208
|
+
forgeSpendDescription(desc) {
|
|
209
|
+
return Buffer.concat([
|
|
210
|
+
desc.commitmentValue,
|
|
211
|
+
desc.nullifier,
|
|
212
|
+
desc.publicKeyReRandomization,
|
|
213
|
+
desc.proof,
|
|
214
|
+
desc.signature,
|
|
215
|
+
]);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* @description Forge list of output descriptions
|
|
219
|
+
* @param outputDescriptions list of output descriptions
|
|
220
|
+
* @returns concatenated forged bytes of type Buffer
|
|
221
|
+
*/
|
|
222
|
+
forgeOutputDescriptions(outputDescriptions) {
|
|
223
|
+
const descriptions = [];
|
|
224
|
+
for (const i of outputDescriptions) {
|
|
225
|
+
const buff = this.forgeOutputDescription(i);
|
|
226
|
+
descriptions.push(buff);
|
|
227
|
+
}
|
|
228
|
+
return Buffer.concat(descriptions);
|
|
229
|
+
}
|
|
230
|
+
forgeOutputDescription(desc) {
|
|
231
|
+
const ct = desc.ciphertext;
|
|
232
|
+
return Buffer.concat([
|
|
233
|
+
desc.commitment,
|
|
234
|
+
desc.proof,
|
|
235
|
+
ct.commitmentValue,
|
|
236
|
+
ct.ephemeralPublicKey,
|
|
237
|
+
utils.toHexBuf(ct.payloadEnc.length, 32),
|
|
238
|
+
ct.payloadEnc,
|
|
239
|
+
ct.nonceEnc,
|
|
240
|
+
ct.payloadOut,
|
|
241
|
+
ct.nonceOut,
|
|
242
|
+
]);
|
|
243
|
+
}
|
|
244
|
+
forgeUnsignedTxInput(unsignedSpendDescription) {
|
|
245
|
+
return Buffer.concat([
|
|
246
|
+
unsignedSpendDescription.commitmentValue,
|
|
247
|
+
unsignedSpendDescription.nullifier,
|
|
248
|
+
unsignedSpendDescription.publicKeyReRandomization,
|
|
249
|
+
unsignedSpendDescription.proof,
|
|
250
|
+
]);
|
|
251
|
+
}
|
|
252
|
+
forgeTransactionPlaintext(txPlainText) {
|
|
253
|
+
const encodedMemo = Buffer.from(utils.char2Bytes(txPlainText.memo).padEnd(txPlainText.memoSize, '0'), 'hex');
|
|
254
|
+
return Buffer.concat([
|
|
255
|
+
txPlainText.diversifier,
|
|
256
|
+
utils.toHexBuf(new BigNumber__default["default"](txPlainText.amount), 64),
|
|
257
|
+
txPlainText.randomCommitmentTrapdoor,
|
|
258
|
+
utils.toHexBuf(txPlainText.memoSize, 32),
|
|
259
|
+
encodedMemo,
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const KDF_KEY = 'KDFSaplingForTezosV1';
|
|
265
|
+
const OCK_KEY = 'OCK_keystringderivation_TEZOS';
|
|
266
|
+
const DEFAULT_MEMO = '';
|
|
267
|
+
const DEFAULT_BOUND_DATA = Buffer.from('', 'hex');
|
|
268
|
+
|
|
269
|
+
var _viewingKeyProvider, _readProvider$2, _saplingContractId;
|
|
270
|
+
/**
|
|
271
|
+
* @description Allows to retrieve and decrypt sapling transactions using on a viewing key
|
|
272
|
+
*
|
|
273
|
+
* @param inMemoryViewingKey Holds the sapling viewing key
|
|
274
|
+
* @param saplingContractId Address of the sapling contract or sapling id if the smart contract contains multiple sapling states
|
|
275
|
+
* @param readProvider Allows to read data from the blockchain
|
|
276
|
+
*/
|
|
277
|
+
class SaplingTransactionViewer {
|
|
278
|
+
constructor(inMemoryViewingKey, saplingContractId, readProvider) {
|
|
279
|
+
_viewingKeyProvider.set(this, void 0);
|
|
280
|
+
_readProvider$2.set(this, void 0);
|
|
281
|
+
_saplingContractId.set(this, void 0);
|
|
282
|
+
__classPrivateFieldSet(this, _viewingKeyProvider, inMemoryViewingKey);
|
|
283
|
+
__classPrivateFieldSet(this, _saplingContractId, saplingContractId);
|
|
284
|
+
__classPrivateFieldSet(this, _readProvider$2, readProvider);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* @description Retrieve the unspent balance associated with the configured viewing key and sapling state
|
|
288
|
+
*
|
|
289
|
+
* @returns the balance in mutez represented as a BigNumber
|
|
290
|
+
*
|
|
291
|
+
*/
|
|
292
|
+
getBalance() {
|
|
293
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
294
|
+
let balance = new BigNumber__default["default"](0);
|
|
295
|
+
const { commitments_and_ciphertexts, nullifiers } = yield this.getSaplingDiff();
|
|
296
|
+
for (let i = 0; i < commitments_and_ciphertexts.length; i++) {
|
|
297
|
+
const decrypted = yield this.decryptCiphertextAsReceiver(commitments_and_ciphertexts[i]);
|
|
298
|
+
if (decrypted) {
|
|
299
|
+
const valueBigNumber = convertValueToBigNumber(decrypted.value);
|
|
300
|
+
const isSpent = yield this.isSpent(decrypted.paymentAddress, valueBigNumber.toString(), decrypted.randomCommitmentTrapdoor, i, nullifiers);
|
|
301
|
+
if (!isSpent) {
|
|
302
|
+
balance = balance.plus(valueBigNumber);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return balance;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* @description Retrieve all the incoming and outgoing transactions associated with the configured viewing key.
|
|
311
|
+
* The response properties are in Uint8Array format; use the getIncomingAndOutgoingTransactions method for readable properties
|
|
312
|
+
*
|
|
313
|
+
*/
|
|
314
|
+
getIncomingAndOutgoingTransactionsRaw() {
|
|
315
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
316
|
+
const incoming = [];
|
|
317
|
+
const outgoing = [];
|
|
318
|
+
const { commitments_and_ciphertexts, nullifiers } = yield this.getSaplingDiff();
|
|
319
|
+
for (let i = 0; i < commitments_and_ciphertexts.length; i++) {
|
|
320
|
+
const decryptedAsReceiver = yield this.decryptCiphertextAsReceiver(commitments_and_ciphertexts[i]);
|
|
321
|
+
const decryptedAsSender = yield this.decryptCiphertextAsSender(commitments_and_ciphertexts[i]);
|
|
322
|
+
if (decryptedAsReceiver) {
|
|
323
|
+
const balance = convertValueToBigNumber(decryptedAsReceiver.value);
|
|
324
|
+
const isSpent = yield this.isSpent(decryptedAsReceiver.paymentAddress, balance.toString(), decryptedAsReceiver.randomCommitmentTrapdoor, i, nullifiers);
|
|
325
|
+
incoming.push(Object.assign(Object.assign({}, decryptedAsReceiver), { isSpent, position: i }));
|
|
326
|
+
}
|
|
327
|
+
if (decryptedAsSender) {
|
|
328
|
+
outgoing.push(decryptedAsSender);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
incoming,
|
|
333
|
+
outgoing,
|
|
334
|
+
};
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* @description Retrieve all the incoming and outgoing decoded transactions associated with the configured viewing key
|
|
339
|
+
*
|
|
340
|
+
*/
|
|
341
|
+
getIncomingAndOutgoingTransactions() {
|
|
342
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
343
|
+
const tx = yield this.getIncomingAndOutgoingTransactionsRaw();
|
|
344
|
+
const incoming = tx.incoming.map((_a) => {
|
|
345
|
+
var { isSpent } = _a, rest = __rest(_a, ["isSpent"]);
|
|
346
|
+
return Object.assign(Object.assign({}, readableFormat(rest)), { isSpent });
|
|
347
|
+
});
|
|
348
|
+
const outgoing = tx.outgoing.map((outgoingTx) => {
|
|
349
|
+
return readableFormat(outgoingTx);
|
|
350
|
+
});
|
|
351
|
+
return { incoming, outgoing };
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
getSaplingDiff() {
|
|
355
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
356
|
+
let saplingDiffResponse;
|
|
357
|
+
if (__classPrivateFieldGet(this, _saplingContractId).saplingId) {
|
|
358
|
+
saplingDiffResponse = yield __classPrivateFieldGet(this, _readProvider$2).getSaplingDiffById({ id: __classPrivateFieldGet(this, _saplingContractId).saplingId }, 'head');
|
|
359
|
+
}
|
|
360
|
+
else if (__classPrivateFieldGet(this, _saplingContractId).contractAddress) {
|
|
361
|
+
saplingDiffResponse = yield __classPrivateFieldGet(this, _readProvider$2).getSaplingDiffByContract(__classPrivateFieldGet(this, _saplingContractId).contractAddress, 'head');
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
throw new InvalidParameter('A contract address or a sapling id was expected in the SaplingTransactionViewer constructor.');
|
|
365
|
+
}
|
|
366
|
+
return saplingDiffResponse;
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
decryptCiphertextAsReceiver(commitmentsAndCiphertexts) {
|
|
370
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
371
|
+
const commitment = commitmentsAndCiphertexts[0];
|
|
372
|
+
const { epk, payload_enc, nonce_enc } = commitmentsAndCiphertexts[1];
|
|
373
|
+
const incomingViewingKey = yield __classPrivateFieldGet(this, _viewingKeyProvider).getIncomingViewingKey();
|
|
374
|
+
const keyAgreement = yield sapling__namespace.keyAgreement(epk, incomingViewingKey);
|
|
375
|
+
const keyAgreementHash = blake__default["default"].blake2b(keyAgreement, Buffer.from(KDF_KEY), 32);
|
|
376
|
+
const decrypted = yield this.decryptCiphertext(keyAgreementHash, utils.hex2buf(nonce_enc), utils.hex2buf(payload_enc));
|
|
377
|
+
if (decrypted) {
|
|
378
|
+
const { diversifier, value, randomCommitmentTrapdoor: rcm, memo, } = this.extractTransactionProperties(decrypted);
|
|
379
|
+
const paymentAddress = bufToUint8Array(yield sapling__namespace.getRawPaymentAddressFromIncomingViewingKey(incomingViewingKey, diversifier));
|
|
380
|
+
try {
|
|
381
|
+
const valid = yield sapling__namespace.verifyCommitment(commitment, paymentAddress, convertValueToBigNumber(value).toString(), rcm);
|
|
382
|
+
if (valid) {
|
|
383
|
+
return { value, memo, paymentAddress, randomCommitmentTrapdoor: rcm };
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
catch (ex) {
|
|
387
|
+
if (!/invalid value/.test(ex)) {
|
|
388
|
+
throw ex;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
decryptCiphertextAsSender(commitmentsAndCiphertexts) {
|
|
395
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
396
|
+
const commitment = commitmentsAndCiphertexts[0];
|
|
397
|
+
const { epk, payload_enc, nonce_enc, payload_out, nonce_out, cv } = commitmentsAndCiphertexts[1];
|
|
398
|
+
const outgoingViewingKey = yield __classPrivateFieldGet(this, _viewingKeyProvider).getOutgoingViewingKey();
|
|
399
|
+
const concat = cv.concat(commitment, epk, outgoingViewingKey.toString('hex'));
|
|
400
|
+
const outgoingCipherKey = blake__default["default"].blake2b(Buffer.from(concat, 'hex'), Buffer.from(OCK_KEY), 32);
|
|
401
|
+
const decryptedOut = yield this.decryptCiphertext(outgoingCipherKey, utils.hex2buf(nonce_out), utils.hex2buf(payload_out));
|
|
402
|
+
if (decryptedOut) {
|
|
403
|
+
const { recipientDiversifiedTransmissionKey: pkd, ephemeralPrivateKey: esk } = this.extractPkdAndEsk(decryptedOut);
|
|
404
|
+
const keyAgreement = yield sapling__namespace.keyAgreement(pkd, esk);
|
|
405
|
+
const keyAgreementHash = blake__default["default"].blake2b(keyAgreement, Buffer.from(KDF_KEY), 32);
|
|
406
|
+
const decryptedEnc = yield this.decryptCiphertext(keyAgreementHash, utils.hex2buf(nonce_enc), utils.hex2buf(payload_enc));
|
|
407
|
+
if (decryptedEnc) {
|
|
408
|
+
const { diversifier, value, randomCommitmentTrapdoor: rcm, memo, } = this.extractTransactionProperties(decryptedEnc);
|
|
409
|
+
const paymentAddress = utils.mergebuf(diversifier, pkd);
|
|
410
|
+
try {
|
|
411
|
+
const isValid = yield sapling__namespace.verifyCommitment(commitment, paymentAddress, convertValueToBigNumber(value).toString(), rcm);
|
|
412
|
+
if (isValid) {
|
|
413
|
+
return { value, memo, paymentAddress, randomCommitmentTrapdoor: rcm };
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
catch (ex) {
|
|
417
|
+
if (!/invalid value/.test(ex)) {
|
|
418
|
+
throw ex;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
decryptCiphertext(keyAgreementHash, nonce, payload) {
|
|
426
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
427
|
+
return nacl.openSecretBox(keyAgreementHash, nonce, payload);
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
extractTransactionProperties(decrypted) {
|
|
431
|
+
return {
|
|
432
|
+
diversifier: decrypted.slice(0, 11),
|
|
433
|
+
value: decrypted.slice(11, 19),
|
|
434
|
+
randomCommitmentTrapdoor: decrypted.slice(19, 51),
|
|
435
|
+
memoSize: decrypted.slice(51, 55),
|
|
436
|
+
memo: decrypted.slice(55),
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
extractPkdAndEsk(decrypted) {
|
|
440
|
+
return {
|
|
441
|
+
recipientDiversifiedTransmissionKey: decrypted.slice(0, 32),
|
|
442
|
+
ephemeralPrivateKey: decrypted.slice(32),
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
isSpent(address, value, randomCommitmentTrapdoor, position, nullifiers) {
|
|
446
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
447
|
+
const computedNullifier = yield sapling__namespace.computeNullifier(__classPrivateFieldGet(this, _viewingKeyProvider).getFullViewingKey(), address, value, randomCommitmentTrapdoor, position);
|
|
448
|
+
return nullifiers.includes(computedNullifier.toString('hex'));
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
_viewingKeyProvider = new WeakMap(), _readProvider$2 = new WeakMap(), _saplingContractId = new WeakMap();
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
*
|
|
456
|
+
* @param leaves nodes in the tree that we would like to make pairs from
|
|
457
|
+
* @returns a paired/chunked array: [a, b, c, d] => [[a, b], [c, d]]
|
|
458
|
+
*/
|
|
459
|
+
function pairNodes(leaves) {
|
|
460
|
+
const pairs = new Array(Math.ceil(leaves.length / 2));
|
|
461
|
+
for (let i = 0; i < leaves.length / 2; i++) {
|
|
462
|
+
pairs[i] = leaves.slice(i * 2, i * 2 + 2);
|
|
463
|
+
}
|
|
464
|
+
return pairs;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* @description helper function to assist in Lazy initializing an object
|
|
468
|
+
*/
|
|
469
|
+
class Lazy {
|
|
470
|
+
constructor(init) {
|
|
471
|
+
this.init = init;
|
|
472
|
+
this.isInitialized = false;
|
|
473
|
+
this.value = undefined;
|
|
474
|
+
}
|
|
475
|
+
// initializes the lazily initiated object
|
|
476
|
+
get() {
|
|
477
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
478
|
+
if (!this.isInitialized) {
|
|
479
|
+
this.value = yield this.init();
|
|
480
|
+
this.isInitialized = true;
|
|
481
|
+
}
|
|
482
|
+
return this.value;
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
*
|
|
488
|
+
* @param hex hexadecimal string we would like to swap
|
|
489
|
+
* @returns a hexadecimal string with swapped endians
|
|
490
|
+
*/
|
|
491
|
+
const changeEndianness = (hex) => {
|
|
492
|
+
if (hex.length % 2 != 0) {
|
|
493
|
+
hex = '0' + hex;
|
|
494
|
+
}
|
|
495
|
+
const bytes = hex.match(/.{2}/g) || [];
|
|
496
|
+
return bytes.reverse().join('');
|
|
497
|
+
};
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Some code in this file was originally written or inspired by Airgap-it
|
|
501
|
+
* https://github.com/airgap-it/airgap-coin-lib/blob/master/LICENSE.md
|
|
502
|
+
*
|
|
503
|
+
*/
|
|
504
|
+
/**
|
|
505
|
+
* @description The SaplingState class's main purpose is to provide a Merkle path for the forger and the transaction builder, so that it may verify that the Sapling transaction is valid
|
|
506
|
+
*
|
|
507
|
+
*/
|
|
508
|
+
class SaplingState {
|
|
509
|
+
constructor(height) {
|
|
510
|
+
this.height = height;
|
|
511
|
+
this.uncommittedMerkleHash = '0100000000000000000000000000000000000000000000000000000000000000';
|
|
512
|
+
this.uncommittedMerkleHashes = new Lazy(() => this.createUncommittedMerkleHashes());
|
|
513
|
+
}
|
|
514
|
+
getStateTree(stateDiff, constructTree = true) {
|
|
515
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
516
|
+
if (this.stateTree !== undefined && this.stateTree.root === stateDiff.root) {
|
|
517
|
+
return this.stateTree;
|
|
518
|
+
}
|
|
519
|
+
const commitments = stateDiff.commitments_and_ciphertexts.map(([commitment, _]) => commitment);
|
|
520
|
+
let merkleTree;
|
|
521
|
+
if (constructTree) {
|
|
522
|
+
merkleTree = yield this.constructMerkleTree(commitments, 0);
|
|
523
|
+
yield this.validateMerkleTree(merkleTree, stateDiff.root);
|
|
524
|
+
}
|
|
525
|
+
this.stateTree = {
|
|
526
|
+
height: this.height,
|
|
527
|
+
size: commitments.length,
|
|
528
|
+
root: stateDiff.root,
|
|
529
|
+
tree: merkleTree,
|
|
530
|
+
};
|
|
531
|
+
return this.stateTree;
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
*
|
|
536
|
+
* @param stateTree stateTree parameter that holds information details on our Merkle tree
|
|
537
|
+
* @param position position of the hash in the Merkle tree
|
|
538
|
+
* @returns a promise of a string that serves as the Merkle path that can be passed on to the Sapling forger or the transaction builder
|
|
539
|
+
*/
|
|
540
|
+
getWitness(stateTree, position) {
|
|
541
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
542
|
+
const heightBuffer = utils.hex2Bytes(changeEndianness(utils.num2PaddedHex(stateTree.height)));
|
|
543
|
+
const posBuffer = utils.hex2Bytes(changeEndianness(utils.num2PaddedHex(position, 64)));
|
|
544
|
+
const neighbouringHashes = yield this.getNeighbouringHashes([], stateTree.height, position, stateTree.tree);
|
|
545
|
+
const witness = neighbouringHashes
|
|
546
|
+
.map((hash) => Buffer.concat([utils.hex2Bytes(changeEndianness(utils.num2PaddedHex(hash.length))), hash]))
|
|
547
|
+
.reverse()
|
|
548
|
+
.reduce((acc, next) => Buffer.concat([acc, next]));
|
|
549
|
+
return Buffer.concat([heightBuffer, witness, posBuffer]).toString('hex');
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
*
|
|
554
|
+
* @param leaves array of leaves or nodes that we want to construct the Merkle tree from
|
|
555
|
+
* @param height height of the desired Merkle tree
|
|
556
|
+
* @returns a promise of MerkleTree type object
|
|
557
|
+
*/
|
|
558
|
+
constructMerkleTree(leaves, height) {
|
|
559
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
560
|
+
if (height === this.height && leaves.length === 1) {
|
|
561
|
+
return leaves[0];
|
|
562
|
+
}
|
|
563
|
+
if (height === this.height || leaves.length > Math.pow(2, this.height - 1 - height)) {
|
|
564
|
+
throw new TreeConstructionFailure('Children length exceeds maximum number of nodes in a merkle tree');
|
|
565
|
+
}
|
|
566
|
+
const pairedLeaves = pairNodes(leaves);
|
|
567
|
+
const updatedLeaves = yield Promise.all(pairedLeaves.map((chunk) => __awaiter(this, void 0, void 0, function* () {
|
|
568
|
+
const left = yield this.getMerkleHash(chunk[0], height);
|
|
569
|
+
const right = yield this.getMerkleHash(chunk[1], height);
|
|
570
|
+
const parentHash = yield sapling.merkleHash(height, left, right);
|
|
571
|
+
return [parentHash.toString('hex'), chunk[0], chunk[1]];
|
|
572
|
+
})));
|
|
573
|
+
return this.constructMerkleTree(updatedLeaves, height + 1);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
getMerkleHash(tree, height) {
|
|
577
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
578
|
+
if (tree === undefined) {
|
|
579
|
+
return (yield this.uncommittedMerkleHashes.get())[height];
|
|
580
|
+
}
|
|
581
|
+
else if (typeof tree === 'string') {
|
|
582
|
+
return Buffer.from(tree, 'hex');
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
return Buffer.from(tree[0], 'hex');
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
*
|
|
591
|
+
* @returns hashes of empty or null values to fill in the Merkle tree
|
|
592
|
+
*/
|
|
593
|
+
createUncommittedMerkleHashes() {
|
|
594
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
595
|
+
const res = new Array(this.height);
|
|
596
|
+
res[0] = Buffer.from(this.uncommittedMerkleHash, 'hex');
|
|
597
|
+
for (let i = 0; i < this.height; i++) {
|
|
598
|
+
const hash = res[i];
|
|
599
|
+
res[i + 1] = yield sapling.merkleHash(i, hash, hash);
|
|
600
|
+
}
|
|
601
|
+
return res;
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
*
|
|
606
|
+
* @param tree Merkle tree to validate
|
|
607
|
+
* @param expectedRoot the expected merkle root to validate against
|
|
608
|
+
*/
|
|
609
|
+
validateMerkleTree(tree, expectedRoot) {
|
|
610
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
611
|
+
const root = yield this.getMerkleHash(tree, this.height - 1);
|
|
612
|
+
if (root.toString('hex') !== expectedRoot) {
|
|
613
|
+
throw new InvalidMerkleRootError(root.toString('hex'));
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
*
|
|
619
|
+
* @param acc accumulator variable for the recursive function
|
|
620
|
+
* @param height height of the tree
|
|
621
|
+
* @param position position of the hash we would like find the neighbours of
|
|
622
|
+
* @param tree the Merkle tree that we want to traverse
|
|
623
|
+
* @returns the accumulated Buffer array of neighbouring hashes
|
|
624
|
+
*/
|
|
625
|
+
getNeighbouringHashes(acc, height, position, tree) {
|
|
626
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
627
|
+
if (typeof tree === 'undefined') {
|
|
628
|
+
throw new Error();
|
|
629
|
+
}
|
|
630
|
+
else if (typeof tree === 'string') {
|
|
631
|
+
return acc;
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
let nextPos, nextTree, otherTree;
|
|
635
|
+
const fullTree = new BigNumber__default["default"](2).pow(height - 1);
|
|
636
|
+
if (position.lt(fullTree)) {
|
|
637
|
+
nextPos = position;
|
|
638
|
+
nextTree = tree[1];
|
|
639
|
+
otherTree = tree[2];
|
|
640
|
+
}
|
|
641
|
+
else {
|
|
642
|
+
nextPos = position.minus(fullTree);
|
|
643
|
+
nextTree = tree[2];
|
|
644
|
+
otherTree = tree[1];
|
|
645
|
+
}
|
|
646
|
+
return this.getNeighbouringHashes([yield this.getMerkleHash(otherTree, height - 1), ...acc], height - 1, nextPos, nextTree);
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
653
|
+
const saplingOutputParams = require('../saplingOutputParams');
|
|
654
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
655
|
+
const saplingSpendParams = require('../saplingSpendParams');
|
|
656
|
+
class SaplingWrapper {
|
|
657
|
+
withProvingContext(action) {
|
|
658
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
659
|
+
yield this.initSaplingParameters();
|
|
660
|
+
return sapling__namespace.withProvingContext(action);
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
getRandomBytes(length) {
|
|
664
|
+
return random.randomBytes(length);
|
|
665
|
+
}
|
|
666
|
+
randR() {
|
|
667
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
668
|
+
return sapling__namespace.randR();
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
getOutgoingViewingKey(vk) {
|
|
672
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
673
|
+
return sapling__namespace.getOutgoingViewingKey(vk);
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
preparePartialOutputDescription(parametersOutputProof) {
|
|
677
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
678
|
+
const partialOutputDesc = yield sapling__namespace.preparePartialOutputDescription(parametersOutputProof.saplingContext, parametersOutputProof.address, parametersOutputProof.randomCommitmentTrapdoor, parametersOutputProof.ephemeralPrivateKey, parametersOutputProof.amount);
|
|
679
|
+
return {
|
|
680
|
+
commitmentValue: partialOutputDesc.cv,
|
|
681
|
+
commitment: partialOutputDesc.cm,
|
|
682
|
+
proof: partialOutputDesc.proof,
|
|
683
|
+
};
|
|
684
|
+
});
|
|
685
|
+
}
|
|
686
|
+
getDiversifiedFromRawPaymentAddress(decodedDestination) {
|
|
687
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
688
|
+
return sapling__namespace.getDiversifiedFromRawPaymentAddress(decodedDestination);
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
deriveEphemeralPublicKey(diversifier, esk) {
|
|
692
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
693
|
+
return sapling__namespace.deriveEphemeralPublicKey(diversifier, esk);
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
getPkdFromRawPaymentAddress(destination) {
|
|
697
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
698
|
+
return sapling__namespace.getPkdFromRawPaymentAddress(destination);
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
keyAgreement(p, sk) {
|
|
702
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
703
|
+
return sapling__namespace.keyAgreement(p, sk);
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
createBindingSignature(saplingContext, balance, transactionSigHash) {
|
|
707
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
708
|
+
return sapling__namespace.createBindingSignature(saplingContext, balance, transactionSigHash);
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
initSaplingParameters() {
|
|
712
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
713
|
+
const spendParams = Buffer.from(saplingSpendParams.saplingSpendParams, 'base64');
|
|
714
|
+
const outputParams = Buffer.from(saplingOutputParams.saplingOutputParams, 'base64');
|
|
715
|
+
return sapling__namespace.initParameters(spendParams, outputParams);
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
var _inMemorySpendingKey$1, _inMemoryProvingKey, _saplingForger$1, _contractAddress$1, _saplingId$1, _memoSize$1, _readProvider$1, _saplingWrapper, _chainId, _saplingState;
|
|
721
|
+
class SaplingTransactionBuilder {
|
|
722
|
+
constructor(keys, saplingForger, saplingContractDetails, readProvider, saplingWrapper = new SaplingWrapper()) {
|
|
723
|
+
_inMemorySpendingKey$1.set(this, void 0);
|
|
724
|
+
_inMemoryProvingKey.set(this, void 0);
|
|
725
|
+
_saplingForger$1.set(this, void 0);
|
|
726
|
+
_contractAddress$1.set(this, void 0);
|
|
727
|
+
_saplingId$1.set(this, void 0);
|
|
728
|
+
_memoSize$1.set(this, void 0);
|
|
729
|
+
_readProvider$1.set(this, void 0);
|
|
730
|
+
_saplingWrapper.set(this, void 0);
|
|
731
|
+
_chainId.set(this, void 0);
|
|
732
|
+
_saplingState.set(this, void 0);
|
|
733
|
+
__classPrivateFieldSet(this, _saplingForger$1, saplingForger);
|
|
734
|
+
__classPrivateFieldSet(this, _contractAddress$1, saplingContractDetails.contractAddress);
|
|
735
|
+
__classPrivateFieldSet(this, _memoSize$1, saplingContractDetails.memoSize);
|
|
736
|
+
__classPrivateFieldSet(this, _inMemorySpendingKey$1, keys.saplingSigner);
|
|
737
|
+
__classPrivateFieldSet(this, _inMemoryProvingKey, keys.saplingProver);
|
|
738
|
+
__classPrivateFieldSet(this, _saplingState, new SaplingState(32));
|
|
739
|
+
__classPrivateFieldSet(this, _saplingId$1, saplingContractDetails.saplingId);
|
|
740
|
+
__classPrivateFieldSet(this, _saplingWrapper, saplingWrapper);
|
|
741
|
+
__classPrivateFieldSet(this, _readProvider$1, readProvider);
|
|
742
|
+
}
|
|
743
|
+
createShieldedTx(saplingTransactionParams, txTotalAmount, boundData) {
|
|
744
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
745
|
+
const rcm = yield __classPrivateFieldGet(this, _saplingWrapper).randR();
|
|
746
|
+
const balance = this.calculateTransactionBalance('0', txTotalAmount.toString());
|
|
747
|
+
const { signature, inputs, outputs } = yield __classPrivateFieldGet(this, _saplingWrapper).withProvingContext((saplingContext) => __awaiter(this, void 0, void 0, function* () {
|
|
748
|
+
const outputs = [];
|
|
749
|
+
const inputs = [];
|
|
750
|
+
for (const i in saplingTransactionParams) {
|
|
751
|
+
outputs.push(yield this.prepareSaplingOutputDescription({
|
|
752
|
+
saplingContext,
|
|
753
|
+
address: utils.b58cdecode(saplingTransactionParams[i].to, utils.prefix[utils.Prefix.ZET1]),
|
|
754
|
+
amount: saplingTransactionParams[i].amount,
|
|
755
|
+
memo: saplingTransactionParams[i].memo,
|
|
756
|
+
randomCommitmentTrapdoor: rcm,
|
|
757
|
+
}));
|
|
758
|
+
}
|
|
759
|
+
const signature = yield this.createBindingSignature({
|
|
760
|
+
saplingContext,
|
|
761
|
+
inputs,
|
|
762
|
+
outputs,
|
|
763
|
+
balance,
|
|
764
|
+
boundData,
|
|
765
|
+
});
|
|
766
|
+
return { signature, inputs, outputs };
|
|
767
|
+
}));
|
|
768
|
+
return {
|
|
769
|
+
inputs,
|
|
770
|
+
outputs,
|
|
771
|
+
signature,
|
|
772
|
+
balance,
|
|
773
|
+
};
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
createSaplingTx(saplingTransactionParams, txTotalAmount, boundData, chosenInputs) {
|
|
777
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
778
|
+
const randomCommitmentTrapdoor = yield __classPrivateFieldGet(this, _saplingWrapper).randR();
|
|
779
|
+
const saplingViewer = yield __classPrivateFieldGet(this, _inMemorySpendingKey$1).getSaplingViewingKeyProvider();
|
|
780
|
+
const outgoingViewingKey = yield saplingViewer.getOutgoingViewingKey();
|
|
781
|
+
const { signature, balance, inputs, outputs } = yield __classPrivateFieldGet(this, _saplingWrapper).withProvingContext((saplingContext) => __awaiter(this, void 0, void 0, function* () {
|
|
782
|
+
const outputs = [];
|
|
783
|
+
const inputs = [];
|
|
784
|
+
inputs.push(...(yield this.prepareSaplingSpendDescription(saplingContext, chosenInputs.inputsToSpend)));
|
|
785
|
+
let sumAmountOutput = new BigNumber__default["default"](0);
|
|
786
|
+
for (const i in saplingTransactionParams) {
|
|
787
|
+
sumAmountOutput = sumAmountOutput.plus(new BigNumber__default["default"](saplingTransactionParams[i].amount));
|
|
788
|
+
outputs.push(yield this.prepareSaplingOutputDescription({
|
|
789
|
+
saplingContext,
|
|
790
|
+
address: utils.b58cdecode(saplingTransactionParams[i].to, utils.prefix[utils.Prefix.ZET1]),
|
|
791
|
+
amount: saplingTransactionParams[i].amount,
|
|
792
|
+
memo: saplingTransactionParams[i].memo,
|
|
793
|
+
randomCommitmentTrapdoor,
|
|
794
|
+
outgoingViewingKey,
|
|
795
|
+
}));
|
|
796
|
+
}
|
|
797
|
+
if (chosenInputs.sumSelectedInputs.isGreaterThan(sumAmountOutput)) {
|
|
798
|
+
const payBackAddress = (yield saplingViewer.getAddress()).address;
|
|
799
|
+
const { payBackOutput, payBackAmount } = yield this.createPaybackOutput({
|
|
800
|
+
saplingContext,
|
|
801
|
+
address: utils.b58cdecode(payBackAddress, utils.prefix[utils.Prefix.ZET1]),
|
|
802
|
+
amount: txTotalAmount.toString(),
|
|
803
|
+
memo: DEFAULT_MEMO,
|
|
804
|
+
randomCommitmentTrapdoor: randomCommitmentTrapdoor,
|
|
805
|
+
outgoingViewingKey: outgoingViewingKey,
|
|
806
|
+
}, chosenInputs.sumSelectedInputs);
|
|
807
|
+
sumAmountOutput = sumAmountOutput.plus(new BigNumber__default["default"](payBackAmount));
|
|
808
|
+
outputs.push(payBackOutput);
|
|
809
|
+
}
|
|
810
|
+
const balance = this.calculateTransactionBalance(chosenInputs.sumSelectedInputs.toString(), sumAmountOutput.toString());
|
|
811
|
+
const signature = yield this.createBindingSignature({
|
|
812
|
+
saplingContext,
|
|
813
|
+
inputs,
|
|
814
|
+
outputs,
|
|
815
|
+
balance,
|
|
816
|
+
boundData,
|
|
817
|
+
});
|
|
818
|
+
return { signature, balance, inputs, outputs };
|
|
819
|
+
}));
|
|
820
|
+
return {
|
|
821
|
+
inputs,
|
|
822
|
+
outputs,
|
|
823
|
+
signature,
|
|
824
|
+
balance,
|
|
825
|
+
};
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
// sum of values of inputs minus sums of values of output equals balance
|
|
829
|
+
calculateTransactionBalance(inputTotal, outputTotal) {
|
|
830
|
+
return new BigNumber__default["default"](inputTotal).minus(new BigNumber__default["default"](outputTotal));
|
|
831
|
+
}
|
|
832
|
+
prepareSaplingOutputDescription(parametersOutputDescription) {
|
|
833
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
834
|
+
const ephemeralPrivateKey = yield __classPrivateFieldGet(this, _saplingWrapper).randR();
|
|
835
|
+
const { commitmentValue, commitment, proof } = yield __classPrivateFieldGet(this, _saplingWrapper).preparePartialOutputDescription({
|
|
836
|
+
saplingContext: parametersOutputDescription.saplingContext,
|
|
837
|
+
address: parametersOutputDescription.address,
|
|
838
|
+
randomCommitmentTrapdoor: parametersOutputDescription.randomCommitmentTrapdoor,
|
|
839
|
+
ephemeralPrivateKey,
|
|
840
|
+
amount: parametersOutputDescription.amount,
|
|
841
|
+
});
|
|
842
|
+
const diversifier = yield __classPrivateFieldGet(this, _saplingWrapper).getDiversifiedFromRawPaymentAddress(parametersOutputDescription.address);
|
|
843
|
+
const ephemeralPublicKey = yield __classPrivateFieldGet(this, _saplingWrapper).deriveEphemeralPublicKey(diversifier, ephemeralPrivateKey);
|
|
844
|
+
const outgoingCipherKey = parametersOutputDescription.outgoingViewingKey
|
|
845
|
+
? blake__default["default"].blake2b(Buffer.concat([
|
|
846
|
+
commitmentValue,
|
|
847
|
+
commitment,
|
|
848
|
+
ephemeralPublicKey,
|
|
849
|
+
parametersOutputDescription.outgoingViewingKey,
|
|
850
|
+
]), Buffer.from(OCK_KEY), 32)
|
|
851
|
+
: __classPrivateFieldGet(this, _saplingWrapper).getRandomBytes(32);
|
|
852
|
+
const ciphertext = yield this.encryptCiphertext({
|
|
853
|
+
address: parametersOutputDescription.address,
|
|
854
|
+
ephemeralPrivateKey,
|
|
855
|
+
diversifier,
|
|
856
|
+
outgoingCipherKey,
|
|
857
|
+
amount: parametersOutputDescription.amount,
|
|
858
|
+
randomCommitmentTrapdoor: parametersOutputDescription.randomCommitmentTrapdoor,
|
|
859
|
+
memo: parametersOutputDescription.memo,
|
|
860
|
+
});
|
|
861
|
+
return {
|
|
862
|
+
commitment,
|
|
863
|
+
proof,
|
|
864
|
+
ciphertext: Object.assign(Object.assign({}, ciphertext), { commitmentValue,
|
|
865
|
+
ephemeralPublicKey }),
|
|
866
|
+
};
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
prepareSaplingSpendDescription(saplingContext, inputsToSpend) {
|
|
870
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
871
|
+
const publicKeyReRandomization = yield __classPrivateFieldGet(this, _saplingWrapper).randR();
|
|
872
|
+
let stateDiff;
|
|
873
|
+
if (__classPrivateFieldGet(this, _saplingId$1)) {
|
|
874
|
+
stateDiff = yield __classPrivateFieldGet(this, _readProvider$1).getSaplingDiffById({ id: __classPrivateFieldGet(this, _saplingId$1) }, 'head');
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
stateDiff = yield __classPrivateFieldGet(this, _readProvider$1).getSaplingDiffByContract(__classPrivateFieldGet(this, _contractAddress$1), 'head');
|
|
878
|
+
}
|
|
879
|
+
const stateTree = yield __classPrivateFieldGet(this, _saplingState).getStateTree(stateDiff, true);
|
|
880
|
+
const saplingSpendDescriptions = [];
|
|
881
|
+
for (let i = 0; i < inputsToSpend.length; i++) {
|
|
882
|
+
const amount = convertValueToBigNumber(inputsToSpend[i].value).toString();
|
|
883
|
+
const witness = yield __classPrivateFieldGet(this, _saplingState).getWitness(stateTree, new BigNumber__default["default"](inputsToSpend[i].position));
|
|
884
|
+
const unsignedSpendDescription = __classPrivateFieldGet(this, _inMemoryProvingKey) ? yield __classPrivateFieldGet(this, _inMemoryProvingKey).prepareSpendDescription({
|
|
885
|
+
saplingContext,
|
|
886
|
+
address: inputsToSpend[i].paymentAddress,
|
|
887
|
+
randomCommitmentTrapdoor: inputsToSpend[i].randomCommitmentTrapdoor,
|
|
888
|
+
publicKeyReRandomization,
|
|
889
|
+
amount,
|
|
890
|
+
root: stateDiff.root,
|
|
891
|
+
witness,
|
|
892
|
+
})
|
|
893
|
+
: yield __classPrivateFieldGet(this, _inMemorySpendingKey$1).prepareSpendDescription({
|
|
894
|
+
saplingContext,
|
|
895
|
+
address: inputsToSpend[i].paymentAddress,
|
|
896
|
+
randomCommitmentTrapdoor: inputsToSpend[i].randomCommitmentTrapdoor,
|
|
897
|
+
publicKeyReRandomization,
|
|
898
|
+
amount,
|
|
899
|
+
root: stateDiff.root,
|
|
900
|
+
witness,
|
|
901
|
+
});
|
|
902
|
+
const unsignedSpendDescriptionBytes = __classPrivateFieldGet(this, _saplingForger$1).forgeUnsignedTxInput(unsignedSpendDescription);
|
|
903
|
+
const hash = blake__default["default"].blake2b(unsignedSpendDescriptionBytes, yield this.getAntiReplay(), 32);
|
|
904
|
+
const spendDescription = yield __classPrivateFieldGet(this, _inMemorySpendingKey$1).signSpendDescription({
|
|
905
|
+
publicKeyReRandomization,
|
|
906
|
+
unsignedSpendDescription,
|
|
907
|
+
hash,
|
|
908
|
+
});
|
|
909
|
+
if (spendDescription.signature === undefined) {
|
|
910
|
+
throw new Error('Spend signing failed');
|
|
911
|
+
}
|
|
912
|
+
saplingSpendDescriptions.push(spendDescription);
|
|
913
|
+
}
|
|
914
|
+
return saplingSpendDescriptions;
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
encryptCiphertext(parametersCiphertext) {
|
|
918
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
919
|
+
const recipientDiversifiedTransmissionKey = yield __classPrivateFieldGet(this, _saplingWrapper).getPkdFromRawPaymentAddress(parametersCiphertext.address);
|
|
920
|
+
const keyAgreement = yield __classPrivateFieldGet(this, _saplingWrapper).keyAgreement(recipientDiversifiedTransmissionKey, parametersCiphertext.ephemeralPrivateKey);
|
|
921
|
+
const keyAgreementHash = blake__default["default"].blake2b(keyAgreement, Buffer.from(KDF_KEY), 32);
|
|
922
|
+
const nonceEnc = Buffer.from(__classPrivateFieldGet(this, _saplingWrapper).getRandomBytes(24));
|
|
923
|
+
const transactionPlaintext = __classPrivateFieldGet(this, _saplingForger$1).forgeTransactionPlaintext({
|
|
924
|
+
diversifier: parametersCiphertext.diversifier,
|
|
925
|
+
amount: parametersCiphertext.amount,
|
|
926
|
+
randomCommitmentTrapdoor: parametersCiphertext.randomCommitmentTrapdoor,
|
|
927
|
+
memoSize: __classPrivateFieldGet(this, _memoSize$1) * 2,
|
|
928
|
+
memo: parametersCiphertext.memo,
|
|
929
|
+
});
|
|
930
|
+
const nonceOut = Buffer.from(__classPrivateFieldGet(this, _saplingWrapper).getRandomBytes(24));
|
|
931
|
+
const payloadEnc = Buffer.from(nacl.secretBox(keyAgreementHash, nonceEnc, transactionPlaintext));
|
|
932
|
+
const payloadOut = Buffer.from(nacl.secretBox(parametersCiphertext.outgoingCipherKey, nonceOut, Buffer.concat([
|
|
933
|
+
recipientDiversifiedTransmissionKey,
|
|
934
|
+
parametersCiphertext.ephemeralPrivateKey,
|
|
935
|
+
])));
|
|
936
|
+
return { payloadEnc, nonceEnc, payloadOut, nonceOut };
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
createPaybackOutput(params, sumSelectedInputs) {
|
|
940
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
941
|
+
const payBackAmount = sumSelectedInputs.minus(params.amount).toString();
|
|
942
|
+
const payBackOutput = yield this.prepareSaplingOutputDescription({
|
|
943
|
+
saplingContext: params.saplingContext,
|
|
944
|
+
address: params.address,
|
|
945
|
+
amount: payBackAmount,
|
|
946
|
+
memo: params.memo,
|
|
947
|
+
randomCommitmentTrapdoor: params.randomCommitmentTrapdoor,
|
|
948
|
+
outgoingViewingKey: params.outgoingViewingKey,
|
|
949
|
+
});
|
|
950
|
+
return { payBackOutput, payBackAmount };
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
createBindingSignature(parametersBindingSig) {
|
|
954
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
955
|
+
const outputs = __classPrivateFieldGet(this, _saplingForger$1).forgeOutputDescriptions(parametersBindingSig.outputs);
|
|
956
|
+
const inputs = __classPrivateFieldGet(this, _saplingForger$1).forgeSpendDescriptions(parametersBindingSig.inputs);
|
|
957
|
+
const transactionSigHash = blake__default["default"].blake2b(Buffer.concat([inputs, outputs, parametersBindingSig.boundData]), yield this.getAntiReplay(), 32);
|
|
958
|
+
return __classPrivateFieldGet(this, _saplingWrapper).createBindingSignature(parametersBindingSig.saplingContext, parametersBindingSig.balance.toFixed(), transactionSigHash);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
getAntiReplay() {
|
|
962
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
963
|
+
let chainId = __classPrivateFieldGet(this, _chainId);
|
|
964
|
+
if (!chainId) {
|
|
965
|
+
chainId = yield __classPrivateFieldGet(this, _readProvider$1).getChainId();
|
|
966
|
+
__classPrivateFieldSet(this, _chainId, chainId);
|
|
967
|
+
}
|
|
968
|
+
return Buffer.from(`${__classPrivateFieldGet(this, _contractAddress$1)}${chainId}`);
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
_inMemorySpendingKey$1 = new WeakMap(), _inMemoryProvingKey = new WeakMap(), _saplingForger$1 = new WeakMap(), _contractAddress$1 = new WeakMap(), _saplingId$1 = new WeakMap(), _memoSize$1 = new WeakMap(), _readProvider$1 = new WeakMap(), _saplingWrapper = new WeakMap(), _chainId = new WeakMap(), _saplingState = new WeakMap();
|
|
973
|
+
|
|
974
|
+
function decryptKey(spendingKey, password) {
|
|
975
|
+
const keyArr = utils.b58cdecode(spendingKey, utils.prefix[utils.Prefix.SASK]);
|
|
976
|
+
// exit first if no password and key is encrypted
|
|
977
|
+
if (!password && spendingKey.slice(0, 4) !== 'sask') {
|
|
978
|
+
throw new InvalidSpendingKey(spendingKey, 'no password Provided to decrypt');
|
|
979
|
+
}
|
|
980
|
+
if (password && spendingKey.slice(0, 4) !== 'sask') {
|
|
981
|
+
const salt = toBuffer__default["default"](keyArr.slice(0, 8));
|
|
982
|
+
const encryptedSk = toBuffer__default["default"](keyArr.slice(8));
|
|
983
|
+
const encryptionKey = pbkdf2__default["default"].pbkdf2Sync(password, salt, 32768, 32, 'sha512');
|
|
984
|
+
const decrypted = nacl.openSecretBox(new Uint8Array(encryptionKey), new Uint8Array(24), new Uint8Array(encryptedSk));
|
|
985
|
+
if (!decrypted) {
|
|
986
|
+
throw new InvalidSpendingKey(spendingKey, 'Encrypted Spending Key or Password Incorrect');
|
|
987
|
+
}
|
|
988
|
+
return toBuffer__default["default"](decrypted);
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
return toBuffer__default["default"](keyArr);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
var _spendingKeyBuf, _saplingViewingKey;
|
|
996
|
+
/**
|
|
997
|
+
* @description holds the spending key, create proof and signature for spend descriptions
|
|
998
|
+
* can instantiate from mnemonic word list or decrypt a encrypted spending key
|
|
999
|
+
* with access to instantiate a InMemoryViewingKey
|
|
1000
|
+
*/
|
|
1001
|
+
class InMemorySpendingKey {
|
|
1002
|
+
/**
|
|
1003
|
+
*
|
|
1004
|
+
* @param spendingKey unencrypted sask... or encrypted MMXj...
|
|
1005
|
+
* @param password required for MMXj encrypted keys
|
|
1006
|
+
*/
|
|
1007
|
+
constructor(spendingKey, password) {
|
|
1008
|
+
_spendingKeyBuf.set(this, void 0);
|
|
1009
|
+
_saplingViewingKey.set(this, void 0);
|
|
1010
|
+
__classPrivateFieldSet(this, _spendingKeyBuf, decryptKey(spendingKey, password));
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
*
|
|
1014
|
+
* @param mnemonic string of words
|
|
1015
|
+
* @param derivationPath tezos current standard 'm/'
|
|
1016
|
+
* @returns InMemorySpendingKey class instantiated
|
|
1017
|
+
*/
|
|
1018
|
+
static fromMnemonic(mnemonic, derivationPath = 'm/') {
|
|
1019
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1020
|
+
// no password passed here. password provided only changes from sask -> MMXj
|
|
1021
|
+
const fullSeed = yield bip39__namespace.mnemonicToSeed(mnemonic);
|
|
1022
|
+
const first32 = fullSeed.slice(0, 32);
|
|
1023
|
+
const second32 = fullSeed.slice(32);
|
|
1024
|
+
// reduce seed bytes must be 32 bytes reflecting both halves
|
|
1025
|
+
const seed = Buffer.from(first32.map((byte, index) => byte ^ second32[index]));
|
|
1026
|
+
const spendingKeyArr = new Uint8Array(yield sapling__namespace.getExtendedSpendingKey(seed, derivationPath));
|
|
1027
|
+
const spendingKey = utils.b58cencode(spendingKeyArr, utils.prefix[utils.Prefix.SASK]);
|
|
1028
|
+
if (utils.ValidationResult.VALID !== 3) {
|
|
1029
|
+
throw new InvalidSpendingKey(spendingKey);
|
|
1030
|
+
}
|
|
1031
|
+
return new InMemorySpendingKey(spendingKey);
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
*
|
|
1036
|
+
* @returns InMemoryViewingKey instantiated class
|
|
1037
|
+
*/
|
|
1038
|
+
getSaplingViewingKeyProvider() {
|
|
1039
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1040
|
+
let viewingKey;
|
|
1041
|
+
if (!__classPrivateFieldGet(this, _saplingViewingKey)) {
|
|
1042
|
+
viewingKey = yield sapling__namespace.getExtendedFullViewingKeyFromSpendingKey(__classPrivateFieldGet(this, _spendingKeyBuf));
|
|
1043
|
+
__classPrivateFieldSet(this, _saplingViewingKey, new InMemoryViewingKey(viewingKey.toString('hex')));
|
|
1044
|
+
}
|
|
1045
|
+
return __classPrivateFieldGet(this, _saplingViewingKey);
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* @description Prepare an unsigned sapling spend description using the spending key
|
|
1050
|
+
* @param parametersSpendProof.saplingContext The sapling proving context
|
|
1051
|
+
* @param parametersSpendProof.address The address of the input
|
|
1052
|
+
* @param parametersSpendProof.randomCommitmentTrapdoor The randomness of the commitment
|
|
1053
|
+
* @param parametersSpendProof.publicKeyReRandomization The re-randomization of the public key
|
|
1054
|
+
* @param parametersSpendProof.amount The value of the input
|
|
1055
|
+
* @param parametersSpendProof.root The root of the merkle tree
|
|
1056
|
+
* @param parametersSpendProof.witness The path of the commitment in the tree
|
|
1057
|
+
* @param derivationPath tezos current standard 'm/'
|
|
1058
|
+
* @returns The unsigned spend description
|
|
1059
|
+
*/
|
|
1060
|
+
prepareSpendDescription(parametersSpendProof) {
|
|
1061
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1062
|
+
const spendDescription = yield sapling__namespace.prepareSpendDescriptionWithSpendingKey(parametersSpendProof.saplingContext, __classPrivateFieldGet(this, _spendingKeyBuf), parametersSpendProof.address, parametersSpendProof.randomCommitmentTrapdoor, parametersSpendProof.publicKeyReRandomization, parametersSpendProof.amount, parametersSpendProof.root, parametersSpendProof.witness);
|
|
1063
|
+
return {
|
|
1064
|
+
commitmentValue: spendDescription.cv,
|
|
1065
|
+
nullifier: spendDescription.nf,
|
|
1066
|
+
publicKeyReRandomization: spendDescription.rk,
|
|
1067
|
+
rtAnchor: spendDescription.rt,
|
|
1068
|
+
proof: spendDescription.proof,
|
|
1069
|
+
};
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* @description Sign a sapling spend description
|
|
1074
|
+
* @param parametersSpendSig.publicKeyReRandomization The re-randomization of the public key
|
|
1075
|
+
* @param parametersSpendSig.unsignedSpendDescription The unsigned Spend description
|
|
1076
|
+
* @param parametersSpendSig.hash The data to be signed
|
|
1077
|
+
* @returns The signed spend description
|
|
1078
|
+
*/
|
|
1079
|
+
signSpendDescription(parametersSpendSig) {
|
|
1080
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1081
|
+
const signedSpendDescription = yield sapling__namespace.signSpendDescription({
|
|
1082
|
+
cv: parametersSpendSig.unsignedSpendDescription.commitmentValue,
|
|
1083
|
+
rt: parametersSpendSig.unsignedSpendDescription.rtAnchor,
|
|
1084
|
+
nf: parametersSpendSig.unsignedSpendDescription.nullifier,
|
|
1085
|
+
rk: parametersSpendSig.unsignedSpendDescription.publicKeyReRandomization,
|
|
1086
|
+
proof: parametersSpendSig.unsignedSpendDescription.proof,
|
|
1087
|
+
}, __classPrivateFieldGet(this, _spendingKeyBuf), parametersSpendSig.publicKeyReRandomization, parametersSpendSig.hash);
|
|
1088
|
+
return {
|
|
1089
|
+
commitmentValue: signedSpendDescription.cv,
|
|
1090
|
+
nullifier: signedSpendDescription.nf,
|
|
1091
|
+
publicKeyReRandomization: signedSpendDescription.rk,
|
|
1092
|
+
proof: signedSpendDescription.proof,
|
|
1093
|
+
signature: signedSpendDescription.spendAuthSig,
|
|
1094
|
+
};
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* @description Return a proof authorizing key from the configured spending key
|
|
1099
|
+
*/
|
|
1100
|
+
getProvingKey() {
|
|
1101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1102
|
+
const provingKey = yield sapling__namespace.getProofAuthorizingKey(__classPrivateFieldGet(this, _spendingKeyBuf));
|
|
1103
|
+
return provingKey.toString('hex');
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
_spendingKeyBuf = new WeakMap(), _saplingViewingKey = new WeakMap();
|
|
1108
|
+
|
|
1109
|
+
var _fullViewingKey;
|
|
1110
|
+
/**
|
|
1111
|
+
* @description Holds the viewing key
|
|
1112
|
+
*/
|
|
1113
|
+
class InMemoryViewingKey {
|
|
1114
|
+
constructor(fullViewingKey) {
|
|
1115
|
+
_fullViewingKey.set(this, void 0);
|
|
1116
|
+
__classPrivateFieldSet(this, _fullViewingKey, Buffer.from(fullViewingKey, 'hex'));
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* @description Allows to instantiate the InMemoryViewingKey from an encrypted/unencrypted spending key
|
|
1120
|
+
*
|
|
1121
|
+
* @param spendingKey Base58Check-encoded spending key
|
|
1122
|
+
* @param password Optional password to decrypt the spending key
|
|
1123
|
+
* @example
|
|
1124
|
+
* ```
|
|
1125
|
+
* await InMemoryViewingKey.fromSpendingKey('sask27SLmU9herddHz4qFJBLMjWYMbJF8RtS579w9ej9mfCYK7VUdyCJPHK8AzW9zMsopGZEkYeNjAY7Zz1bkM7CGu8eKLzrjBLTMC5wWJDhxiK91ahA29rhDRsHdJDV2u2jFwb2MNUix8JW7sAkAqYVaJpCehTBPgRQ1KqKwqqUaNmuD8kazd4Q8MCWmgbWs21Yuomdqyi9FLigjRp7oY4m5adaVU19Nj1AHvsMY2tePeU2L')
|
|
1126
|
+
* ```
|
|
1127
|
+
*
|
|
1128
|
+
*/
|
|
1129
|
+
static fromSpendingKey(spendingKey, password) {
|
|
1130
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1131
|
+
const inMemorySpendingkey = new InMemorySpendingKey(spendingKey, password);
|
|
1132
|
+
return inMemorySpendingkey.getSaplingViewingKeyProvider();
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* @description Retrieve the full viewing key
|
|
1137
|
+
* @returns Buffer representing the full viewing key
|
|
1138
|
+
*
|
|
1139
|
+
*/
|
|
1140
|
+
getFullViewingKey() {
|
|
1141
|
+
return __classPrivateFieldGet(this, _fullViewingKey);
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* @description Retrieve the outgoing viewing key
|
|
1145
|
+
* @returns Buffer representing the outgoing viewing key
|
|
1146
|
+
*
|
|
1147
|
+
*/
|
|
1148
|
+
getOutgoingViewingKey() {
|
|
1149
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1150
|
+
return sapling__namespace.getOutgoingViewingKey(__classPrivateFieldGet(this, _fullViewingKey));
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* @description Retrieve the incoming viewing key
|
|
1155
|
+
* @returns Buffer representing the incoming viewing key
|
|
1156
|
+
*
|
|
1157
|
+
*/
|
|
1158
|
+
getIncomingViewingKey() {
|
|
1159
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1160
|
+
return sapling__namespace.getIncomingViewingKey(__classPrivateFieldGet(this, _fullViewingKey));
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* @description Retrieve a payment address
|
|
1165
|
+
* @param addressIndex used to determine which diversifier should be used to derive the address, default is 0
|
|
1166
|
+
* @returns Base58Check-encoded address and its index
|
|
1167
|
+
*
|
|
1168
|
+
*/
|
|
1169
|
+
getAddress(addressIndex) {
|
|
1170
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1171
|
+
const { index, raw } = yield sapling__namespace.getPaymentAddressFromViewingKey(__classPrivateFieldGet(this, _fullViewingKey), addressIndex);
|
|
1172
|
+
return {
|
|
1173
|
+
address: utils.b58cencode(raw, utils.prefix[utils.Prefix.ZET1]),
|
|
1174
|
+
addressIndex: index.readInt32LE(),
|
|
1175
|
+
};
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
_fullViewingKey = new WeakMap();
|
|
1180
|
+
|
|
1181
|
+
var _provingKey;
|
|
1182
|
+
/**
|
|
1183
|
+
* @description holds the proving key, create proof for spend descriptions
|
|
1184
|
+
* The class can be instantiated from a proving key or a spending key
|
|
1185
|
+
*/
|
|
1186
|
+
class InMemoryProvingKey {
|
|
1187
|
+
constructor(provingKey) {
|
|
1188
|
+
_provingKey.set(this, void 0);
|
|
1189
|
+
__classPrivateFieldSet(this, _provingKey, Buffer.from(provingKey, 'hex'));
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* @description Allows to instantiate the InMemoryProvingKey from an encrypted/unencrypted spending key
|
|
1193
|
+
*
|
|
1194
|
+
* @param spendingKey Base58Check-encoded spending key
|
|
1195
|
+
* @param password Optional password to decrypt the spending key
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```
|
|
1198
|
+
* await InMemoryProvingKey.fromSpendingKey('sask27SLmU9herddHz4qFJBLMjWYMbJF8RtS579w9ej9mfCYK7VUdyCJPHK8AzW9zMsopGZEkYeNjAY7Zz1bkM7CGu8eKLzrjBLTMC5wWJDhxiK91ahA29rhDRsHdJDV2u2jFwb2MNUix8JW7sAkAqYVaJpCehTBPgRQ1KqKwqqUaNmuD8kazd4Q8MCWmgbWs21Yuomdqyi9FLigjRp7oY4m5adaVU19Nj1AHvsMY2tePeU2L')
|
|
1199
|
+
* ```
|
|
1200
|
+
*
|
|
1201
|
+
*/
|
|
1202
|
+
static fromSpendingKey(spendingKey, password) {
|
|
1203
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1204
|
+
const decodedSpendingKey = decryptKey(spendingKey, password);
|
|
1205
|
+
const provingKey = yield sapling__namespace.getProofAuthorizingKey(decodedSpendingKey);
|
|
1206
|
+
return new InMemoryProvingKey(provingKey.toString('hex'));
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* @description Prepare an unsigned sapling spend description using the proving key
|
|
1211
|
+
*
|
|
1212
|
+
* @param parametersSpendProof.saplingContext The sapling proving context
|
|
1213
|
+
* @param parametersSpendProof.address The address of the input
|
|
1214
|
+
* @param parametersSpendProof.randomCommitmentTrapdoor The randomness of the commitment
|
|
1215
|
+
* @param parametersSpendProof.publicKeyReRandomization The re-randomization of the public key
|
|
1216
|
+
* @param parametersSpendProof.amount The value of the input
|
|
1217
|
+
* @param parametersSpendProof.root The root of the merkle tree
|
|
1218
|
+
* @param parametersSpendProof.witness The path of the commitment in the tree
|
|
1219
|
+
* @param derivationPath tezos current standard 'm/'
|
|
1220
|
+
* @returns The unsinged spend description
|
|
1221
|
+
*/
|
|
1222
|
+
prepareSpendDescription(parametersSpendProof) {
|
|
1223
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1224
|
+
const spendDescription = yield sapling__namespace.prepareSpendDescriptionWithAuthorizingKey(parametersSpendProof.saplingContext, __classPrivateFieldGet(this, _provingKey), parametersSpendProof.address, parametersSpendProof.randomCommitmentTrapdoor, parametersSpendProof.publicKeyReRandomization, parametersSpendProof.amount, parametersSpendProof.root, parametersSpendProof.witness);
|
|
1225
|
+
return {
|
|
1226
|
+
commitmentValue: spendDescription.cv,
|
|
1227
|
+
nullifier: spendDescription.nf,
|
|
1228
|
+
publicKeyReRandomization: spendDescription.rk,
|
|
1229
|
+
rtAnchor: spendDescription.rt,
|
|
1230
|
+
proof: spendDescription.proof,
|
|
1231
|
+
};
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
_provingKey = new WeakMap();
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* @packageDocumentation
|
|
1239
|
+
* @module @taquito/sapling
|
|
1240
|
+
*/
|
|
1241
|
+
var _inMemorySpendingKey, _saplingId, _contractAddress, _memoSize, _readProvider, _packer, _saplingForger, _saplingTxBuilder, _saplingTransactionViewer;
|
|
1242
|
+
/**
|
|
1243
|
+
* @description Class that surfaces all of the sapling capability allowing to read from a sapling state and prepare transactions
|
|
1244
|
+
*
|
|
1245
|
+
* @param keys.saplingSigner Holds the sapling spending key
|
|
1246
|
+
* @param keys.saplingProver (Optional) Allows to generate the proofs with the proving key rather than the spending key
|
|
1247
|
+
* @param saplingContractDetails Contains the address of the sapling contract, the memo size, and an optional sapling id that must be defined if the sapling contract contains more than one sapling state
|
|
1248
|
+
* @param readProvider Allows to read data from the blockchain
|
|
1249
|
+
* @param packer (Optional) Allows packing data. Use the `MichelCodecPacker` by default.
|
|
1250
|
+
* @param saplingForger (Optional) Allows serializing the sapling transactions. Use the `SaplingForger` by default.
|
|
1251
|
+
* @param saplingTxBuilder (Optional) Allows to prepare the sapling transactions. Use the `SaplingTransactionBuilder` by default.
|
|
1252
|
+
* @example
|
|
1253
|
+
* ```
|
|
1254
|
+
* const inMemorySpendingKey = await InMemorySpendingKey.fromMnemonic('YOUR_MNEMONIC');
|
|
1255
|
+
* const readProvider = new RpcReadAdapter(new RpcClient('https://YOUR_PREFERRED_RPC_URL'))
|
|
1256
|
+
*
|
|
1257
|
+
* const saplingToolkit = new SaplingToolkit(
|
|
1258
|
+
* { saplingSigner: inMemorySpendingKey },
|
|
1259
|
+
* { contractAddress: SAPLING_CONTRACT_ADDRESS, memoSize: 8 },
|
|
1260
|
+
* readProvider
|
|
1261
|
+
* )
|
|
1262
|
+
* ```
|
|
1263
|
+
*/
|
|
1264
|
+
class SaplingToolkit {
|
|
1265
|
+
constructor(keys, saplingContractDetails, readProvider, packer = new taquito.MichelCodecPacker(), saplingForger = new SaplingForger(), saplingTxBuilder = new SaplingTransactionBuilder(keys, saplingForger, saplingContractDetails, readProvider)) {
|
|
1266
|
+
_inMemorySpendingKey.set(this, void 0);
|
|
1267
|
+
_saplingId.set(this, void 0);
|
|
1268
|
+
_contractAddress.set(this, void 0);
|
|
1269
|
+
_memoSize.set(this, void 0);
|
|
1270
|
+
_readProvider.set(this, void 0);
|
|
1271
|
+
_packer.set(this, void 0);
|
|
1272
|
+
_saplingForger.set(this, void 0);
|
|
1273
|
+
_saplingTxBuilder.set(this, void 0);
|
|
1274
|
+
_saplingTransactionViewer.set(this, void 0);
|
|
1275
|
+
__classPrivateFieldSet(this, _inMemorySpendingKey, keys.saplingSigner);
|
|
1276
|
+
__classPrivateFieldSet(this, _saplingId, saplingContractDetails.saplingId);
|
|
1277
|
+
__classPrivateFieldSet(this, _contractAddress, saplingContractDetails.contractAddress);
|
|
1278
|
+
__classPrivateFieldSet(this, _memoSize, saplingContractDetails.memoSize);
|
|
1279
|
+
__classPrivateFieldSet(this, _readProvider, readProvider);
|
|
1280
|
+
__classPrivateFieldSet(this, _packer, packer);
|
|
1281
|
+
__classPrivateFieldSet(this, _saplingForger, saplingForger);
|
|
1282
|
+
__classPrivateFieldSet(this, _saplingTxBuilder, saplingTxBuilder);
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* @description Get an instance of `SaplingTransactionViewer` which allows to retrieve and decrypt sapling transactions and calculate the unspent balance.
|
|
1286
|
+
*/
|
|
1287
|
+
getSaplingTransactionViewer() {
|
|
1288
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1289
|
+
let saplingTransactionViewer;
|
|
1290
|
+
if (!__classPrivateFieldGet(this, _saplingTransactionViewer)) {
|
|
1291
|
+
const saplingViewingKey = yield __classPrivateFieldGet(this, _inMemorySpendingKey).getSaplingViewingKeyProvider();
|
|
1292
|
+
saplingTransactionViewer = new SaplingTransactionViewer(saplingViewingKey, this.getSaplingContractId(), __classPrivateFieldGet(this, _readProvider));
|
|
1293
|
+
__classPrivateFieldSet(this, _saplingTransactionViewer, saplingTransactionViewer);
|
|
1294
|
+
}
|
|
1295
|
+
return __classPrivateFieldGet(this, _saplingTransactionViewer);
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* @description Prepare a shielded transaction
|
|
1300
|
+
* @param shieldedTxParams `to` is the payment address that will receive the shielded tokens (zet).
|
|
1301
|
+
* `amount` is the amount of shielded tokens in tez by default.
|
|
1302
|
+
* `mutez` needs to be set to true if the amount of shielded tokens is in mutez.
|
|
1303
|
+
* `memo` is an empty string by default.
|
|
1304
|
+
* @returns a string representing the sapling transaction
|
|
1305
|
+
*/
|
|
1306
|
+
prepareShieldedTransaction(shieldedTxParams) {
|
|
1307
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1308
|
+
const { formatedParams, totalAmount } = this.formatTransactionParams(shieldedTxParams, this.validateDestinationSaplingAddress);
|
|
1309
|
+
const root = yield this.getRoot();
|
|
1310
|
+
const { inputs, outputs, signature, balance } = yield __classPrivateFieldGet(this, _saplingTxBuilder).createShieldedTx(formatedParams, totalAmount, DEFAULT_BOUND_DATA);
|
|
1311
|
+
const forgedSaplingTx = __classPrivateFieldGet(this, _saplingForger).forgeSaplingTransaction({
|
|
1312
|
+
inputs,
|
|
1313
|
+
outputs,
|
|
1314
|
+
balance,
|
|
1315
|
+
root,
|
|
1316
|
+
boundData: DEFAULT_BOUND_DATA,
|
|
1317
|
+
signature,
|
|
1318
|
+
});
|
|
1319
|
+
return forgedSaplingTx.toString('hex');
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* @description Prepare an unshielded transaction
|
|
1324
|
+
* @param unshieldedTxParams `to` is the Tezos address that will receive the unshielded tokens (tz1, tz2 or tz3).
|
|
1325
|
+
* `amount` is the amount of unshielded tokens in tez by default.
|
|
1326
|
+
* `mutez` needs to be set to true if the amount of unshielded tokens is in mutez.
|
|
1327
|
+
* @returns a string representing the sapling transaction.
|
|
1328
|
+
*/
|
|
1329
|
+
prepareUnshieldedTransaction(unshieldedTxParams) {
|
|
1330
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1331
|
+
const { formatedParams, totalAmount } = this.formatTransactionParams([unshieldedTxParams], this.validateDestinationImplicitAddress);
|
|
1332
|
+
const boundData = yield this.createBoundData(formatedParams[0].to);
|
|
1333
|
+
const root = yield this.getRoot();
|
|
1334
|
+
const chosenInputs = yield this.selectInputsToSpend(new BigNumber__default["default"](formatedParams[0].amount));
|
|
1335
|
+
const { inputs, outputs, signature, balance } = yield __classPrivateFieldGet(this, _saplingTxBuilder).createSaplingTx([], totalAmount, boundData, chosenInputs);
|
|
1336
|
+
const forgedSaplingTx = __classPrivateFieldGet(this, _saplingForger).forgeSaplingTransaction({
|
|
1337
|
+
inputs,
|
|
1338
|
+
outputs,
|
|
1339
|
+
balance,
|
|
1340
|
+
root,
|
|
1341
|
+
boundData,
|
|
1342
|
+
signature,
|
|
1343
|
+
});
|
|
1344
|
+
return forgedSaplingTx.toString('hex');
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* @description Prepare a sapling transaction (zet to zet)
|
|
1349
|
+
* @param saplingTxParams `to` is the payment address that will receive the shielded tokens (zet).
|
|
1350
|
+
* `amount` is the amount of unshielded tokens in tez by default.
|
|
1351
|
+
* `mutez` needs to be set to true if the amount of unshielded tokens is in mutez.
|
|
1352
|
+
* `memo` is an empty string by default.
|
|
1353
|
+
* @returns a string representing the sapling transaction.
|
|
1354
|
+
*/
|
|
1355
|
+
prepareSaplingTransaction(saplingTxParams) {
|
|
1356
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1357
|
+
const { formatedParams, totalAmount } = this.formatTransactionParams(saplingTxParams, this.validateDestinationSaplingAddress);
|
|
1358
|
+
const root = yield this.getRoot();
|
|
1359
|
+
const chosenInputs = yield this.selectInputsToSpend(totalAmount);
|
|
1360
|
+
const { inputs, outputs, signature, balance } = yield __classPrivateFieldGet(this, _saplingTxBuilder).createSaplingTx(formatedParams, totalAmount, DEFAULT_BOUND_DATA, chosenInputs);
|
|
1361
|
+
const forgedSaplingTx = __classPrivateFieldGet(this, _saplingForger).forgeSaplingTransaction({
|
|
1362
|
+
inputs,
|
|
1363
|
+
outputs,
|
|
1364
|
+
balance,
|
|
1365
|
+
root,
|
|
1366
|
+
boundData: DEFAULT_BOUND_DATA,
|
|
1367
|
+
signature,
|
|
1368
|
+
});
|
|
1369
|
+
return forgedSaplingTx.toString('hex');
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
formatTransactionParams(txParams, validateDestination) {
|
|
1373
|
+
const formatedParams = [];
|
|
1374
|
+
let totalAmount = new BigNumber__default["default"](0);
|
|
1375
|
+
txParams.forEach((param) => {
|
|
1376
|
+
var _a;
|
|
1377
|
+
validateDestination(param.to);
|
|
1378
|
+
const amountMutez = param.mutez
|
|
1379
|
+
? param.amount.toString()
|
|
1380
|
+
: utils.format('tz', 'mutez', param.amount).toString();
|
|
1381
|
+
totalAmount = totalAmount.plus(new BigNumber__default["default"](amountMutez));
|
|
1382
|
+
const memo = (_a = param.memo) !== null && _a !== void 0 ? _a : DEFAULT_MEMO;
|
|
1383
|
+
if (memo.length > __classPrivateFieldGet(this, _memoSize)) {
|
|
1384
|
+
throw new InvalidMemo(memo, 'The memo is too long.');
|
|
1385
|
+
}
|
|
1386
|
+
formatedParams.push({ to: param.to, amount: amountMutez, memo });
|
|
1387
|
+
});
|
|
1388
|
+
return { formatedParams, totalAmount };
|
|
1389
|
+
}
|
|
1390
|
+
getRoot() {
|
|
1391
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1392
|
+
if (__classPrivateFieldGet(this, _saplingId)) {
|
|
1393
|
+
const { root } = yield __classPrivateFieldGet(this, _readProvider).getSaplingDiffById({ id: __classPrivateFieldGet(this, _saplingId) }, 'head');
|
|
1394
|
+
return root;
|
|
1395
|
+
}
|
|
1396
|
+
else {
|
|
1397
|
+
const { root } = yield __classPrivateFieldGet(this, _readProvider).getSaplingDiffByContract(__classPrivateFieldGet(this, _contractAddress), 'head');
|
|
1398
|
+
return root;
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
createBoundData(destination) {
|
|
1403
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1404
|
+
const pref = destination.substr(0, 3);
|
|
1405
|
+
let pad;
|
|
1406
|
+
switch (pref) {
|
|
1407
|
+
case 'tz1': {
|
|
1408
|
+
pad = Buffer.from('00', 'hex');
|
|
1409
|
+
break;
|
|
1410
|
+
}
|
|
1411
|
+
case 'tz2': {
|
|
1412
|
+
pad = Buffer.from('01', 'hex');
|
|
1413
|
+
break;
|
|
1414
|
+
}
|
|
1415
|
+
case 'tz3': {
|
|
1416
|
+
pad = Buffer.from('02', 'hex');
|
|
1417
|
+
break;
|
|
1418
|
+
}
|
|
1419
|
+
default: {
|
|
1420
|
+
throw new utils.InvalidKeyError(destination, "The 'to' parameter contains an invalid prefix.");
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
const decodedDestination = utils.b58cdecode(destination, utils.prefix[pref]);
|
|
1424
|
+
const padDestination = Buffer.concat([pad, Buffer.from(decodedDestination)]);
|
|
1425
|
+
const packedDestination = yield __classPrivateFieldGet(this, _packer).packData({
|
|
1426
|
+
data: { bytes: padDestination.toString('hex') },
|
|
1427
|
+
type: { prim: 'bytes' },
|
|
1428
|
+
});
|
|
1429
|
+
return Buffer.from(packedDestination.packed, 'hex');
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
validateDestinationImplicitAddress(to) {
|
|
1433
|
+
if (utils.validateKeyHash(to) !== utils.ValidationResult.VALID) {
|
|
1434
|
+
throw new utils.InvalidAddressError(to, "The 'to' parameter must be a Tezos public key hash (tz1, tz2, tz3).");
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
validateDestinationSaplingAddress(to) {
|
|
1438
|
+
if (!to.startsWith(utils.Prefix.ZET1)) {
|
|
1439
|
+
throw new utils.InvalidAddressError(to, "The 'to' parameter must be a sapling address (zet1).");
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
getSaplingContractId() {
|
|
1443
|
+
let saplingContractId;
|
|
1444
|
+
if (__classPrivateFieldGet(this, _saplingId)) {
|
|
1445
|
+
saplingContractId = { saplingId: __classPrivateFieldGet(this, _saplingId) };
|
|
1446
|
+
}
|
|
1447
|
+
else {
|
|
1448
|
+
saplingContractId = { contractAddress: __classPrivateFieldGet(this, _contractAddress) };
|
|
1449
|
+
}
|
|
1450
|
+
return saplingContractId;
|
|
1451
|
+
}
|
|
1452
|
+
selectInputsToSpend(amountMutez) {
|
|
1453
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1454
|
+
const saplingTxViewer = yield this.getSaplingTransactionViewer();
|
|
1455
|
+
const { incoming } = yield saplingTxViewer.getIncomingAndOutgoingTransactionsRaw();
|
|
1456
|
+
const inputsToSpend = [];
|
|
1457
|
+
let sumSelectedInputs = new BigNumber__default["default"](0);
|
|
1458
|
+
incoming.forEach((input) => {
|
|
1459
|
+
if (!input.isSpent && sumSelectedInputs.isLessThan(amountMutez)) {
|
|
1460
|
+
const txAmount = convertValueToBigNumber(input.value);
|
|
1461
|
+
sumSelectedInputs = sumSelectedInputs.plus(txAmount);
|
|
1462
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1463
|
+
const rest = __rest(input, ["isSpent"]);
|
|
1464
|
+
inputsToSpend.push(rest);
|
|
1465
|
+
}
|
|
1466
|
+
});
|
|
1467
|
+
if (sumSelectedInputs.isLessThan(new BigNumber__default["default"](amountMutez))) {
|
|
1468
|
+
throw new InsufficientBalance(sumSelectedInputs.toString(), amountMutez.toString());
|
|
1469
|
+
}
|
|
1470
|
+
return { inputsToSpend, sumSelectedInputs };
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
_inMemorySpendingKey = new WeakMap(), _saplingId = new WeakMap(), _contractAddress = new WeakMap(), _memoSize = new WeakMap(), _readProvider = new WeakMap(), _packer = new WeakMap(), _saplingForger = new WeakMap(), _saplingTxBuilder = new WeakMap(), _saplingTransactionViewer = new WeakMap();
|
|
1475
|
+
|
|
1476
|
+
exports.InMemoryProvingKey = InMemoryProvingKey;
|
|
1477
|
+
exports.InMemorySpendingKey = InMemorySpendingKey;
|
|
1478
|
+
exports.InMemoryViewingKey = InMemoryViewingKey;
|
|
1479
|
+
exports.SaplingToolkit = SaplingToolkit;
|
|
1480
|
+
exports.SaplingTransactionViewer = SaplingTransactionViewer;
|
|
1481
|
+
|
|
1482
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1483
|
+
|
|
1484
|
+
}));
|
|
1485
|
+
//# sourceMappingURL=taquito-sapling.umd.js.map
|