psffpp 1.0.1 → 1.1.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.md +1 -1
- package/README.md +34 -168
- package/index.js +170 -252
- package/package.json +8 -5
- package/test/mocks/wallet.js +161 -0
- package/test/mocks/write-price-mocks.js +302 -0
- package/test/unit/main-index-unit.js +84 -272
- package/.travis.yml +0 -33
- package/lib/nfts.js +0 -113
- package/lib/util.js +0 -50
- package/test/unit/nfts-unit.js +0 -190
- package/test/unit/util-unit.js +0 -91
- /package/test/{unit/mocks → mocks}/main-index-mocks.js +0 -0
- /package/test/{unit/mocks → mocks}/util-mocks.js +0 -0
package/index.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/*
|
|
2
|
-
This library implement
|
|
2
|
+
This library implement PS010 specification:
|
|
3
3
|
https://github.com/Permissionless-Software-Foundation/specifications/blob/master/ps009-multisig-approval.md
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// global libraries
|
|
7
|
-
|
|
8
|
-
const axios = require('axios')
|
|
7
|
+
import MultisigApproval from 'psf-multisig-approval'
|
|
9
8
|
|
|
10
9
|
// Local libraries
|
|
11
|
-
const NFTs = require('./lib/nfts')
|
|
12
|
-
const UtilLib = require('./lib/util')
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
// Constants
|
|
12
|
+
const PSF_HARDCODE_WRITE_PRICE = 0.08335233
|
|
13
|
+
const WRITE_PRICE_ADDR = 'bitcoincash:qrwe6kxhvu47ve6jvgrf2d93w0q38av7s5xm9xfehr'
|
|
14
|
+
|
|
15
|
+
class PSFFPP {
|
|
15
16
|
constructor (localConfig = {}) {
|
|
16
17
|
// Dependency Injection
|
|
17
18
|
this.wallet = localConfig.wallet
|
|
@@ -19,311 +20,228 @@ class MultisigApproval {
|
|
|
19
20
|
throw new Error('Instance of minimal-slp-wallet must be passed in as a property called \'wallet\', when initializing the psf-multisig-approval library.')
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
// The default IPFS gateway can be overwritten by the user when this library
|
|
23
|
-
// is instantiated.
|
|
24
|
-
this.ipfsGateway = localConfig.ipfsGateway
|
|
25
|
-
if (!this.ipfsGateway) {
|
|
26
|
-
this.ipfsGateway = 'https://p2wdb-gateway-678.fullstack.cash'
|
|
27
|
-
}
|
|
28
|
-
|
|
29
23
|
// Encapsulate dependencies
|
|
30
24
|
this.bchjs = this.wallet.bchjs
|
|
31
|
-
this.
|
|
32
|
-
this.axios = axios
|
|
33
|
-
this.nfts = new NFTs(localConfig)
|
|
34
|
-
this.util = new UtilLib(localConfig)
|
|
25
|
+
this.ps009 = null // placeholder for Multisig Approval library.
|
|
35
26
|
|
|
36
27
|
// Bind the this object to all subfunctions in this class
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
39
|
-
this.
|
|
28
|
+
this._initPs009 = this._initPs009.bind(this)
|
|
29
|
+
this.getMcWritePrice = this.getMcWritePrice.bind(this)
|
|
30
|
+
this.createPinClaim = this.createPinClaim.bind(this)
|
|
40
31
|
|
|
41
|
-
//
|
|
42
|
-
this.
|
|
32
|
+
// State
|
|
33
|
+
this.currentWritePrice = null
|
|
34
|
+
this.filterTxids = []
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
try {
|
|
52
|
-
// console.log('groupTokenId: ', groupTokenId)
|
|
37
|
+
// Initialize the PS009 Multisig Approval library if it hasn't already been
|
|
38
|
+
// initialized.
|
|
39
|
+
async _initPs009 () {
|
|
40
|
+
if (!this.ps009) {
|
|
41
|
+
this.ps009 = new MultisigApproval({ wallet: this.wallet })
|
|
42
|
+
}
|
|
53
43
|
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
return true
|
|
45
|
+
}
|
|
56
46
|
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
// Get the write price set by the PSF Minting Council.
|
|
48
|
+
// This function assumes the transaction history retrieved from the Cash
|
|
49
|
+
// Stack is sorted in descending order with the biggest (newest) block
|
|
50
|
+
// in the first element in the transaction history array.
|
|
51
|
+
async getMcWritePrice () {
|
|
52
|
+
// Hard codeded value. 3/2/24
|
|
53
|
+
// This value is returned if there are any issues returning the write price.
|
|
54
|
+
// It should be higher than actual fee, so that any writes will propegate to
|
|
55
|
+
// the nodes that successfully retrieved the current write price.
|
|
56
|
+
let writePrice = PSF_HARDCODE_WRITE_PRICE
|
|
59
57
|
|
|
60
|
-
|
|
58
|
+
try {
|
|
59
|
+
// Return the saved write price if this function has already been called once.
|
|
60
|
+
if (this.currentWritePrice) return this.currentWritePrice
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
} catch (err) {
|
|
64
|
-
console.error('Error in getNftHolderInfo()')
|
|
65
|
-
throw err
|
|
66
|
-
}
|
|
67
|
-
}
|
|
62
|
+
await this._initPs009()
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
let requiredSigners = inObj.requiredSigners
|
|
64
|
+
// Find the PS009 approval transaction the addresses tx history.
|
|
65
|
+
console.log('\nSearching blockchain for updated write price...')
|
|
66
|
+
const approvalObj = await this.ps009.getApprovalTx({
|
|
67
|
+
address: WRITE_PRICE_ADDR,
|
|
68
|
+
filterTxids: this.filterTxids
|
|
69
|
+
})
|
|
70
|
+
// console.log('approvalObj: ', JSON.stringify(approvalObj, null, 2))
|
|
77
71
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
// Throw an error if no approval transaction can be found in the
|
|
73
|
+
// transaction history.
|
|
74
|
+
if (approvalObj === null) {
|
|
75
|
+
throw new Error(`APPROVAL transaction could not be found in the TX history of ${WRITE_PRICE_ADDR}. Can not reach consensus on write price.`)
|
|
81
76
|
}
|
|
82
77
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
for (let i = 0; i < keys.length; i++) {
|
|
86
|
-
const thisPair = keys[i]
|
|
78
|
+
const { approvalTxid, updateTxid } = approvalObj
|
|
79
|
+
console.log(`New approval txid found (${approvalTxid}), validating...`)
|
|
87
80
|
|
|
88
|
-
|
|
89
|
-
}
|
|
81
|
+
// Get the CID from the update transaction.
|
|
82
|
+
const updateObj = await this.ps009.getUpdateTx({ txid: updateTxid })
|
|
83
|
+
// console.log(`updateObj: ${JSON.stringify(updateObj, null, 2)}`)
|
|
84
|
+
const { cid } = updateObj
|
|
90
85
|
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
requiredSigners = Math.floor(pubKeys.length / 2) + 1
|
|
95
|
-
}
|
|
86
|
+
// Resolve the CID into JSON data from the IPFS gateway.
|
|
87
|
+
const updateData = await this.ps009.getCidData({ cid })
|
|
88
|
+
// console.log(`updateData: ${JSON.stringify(updateData, null, 2)}`)
|
|
96
89
|
|
|
97
|
-
//
|
|
98
|
-
const
|
|
90
|
+
// Validate the approval transaction
|
|
91
|
+
const approvalIsValid = await this.ps009.validateApproval({
|
|
92
|
+
approvalObj,
|
|
93
|
+
updateObj,
|
|
94
|
+
updateData
|
|
95
|
+
})
|
|
99
96
|
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
if (approvalIsValid) {
|
|
98
|
+
console.log('Approval TXID validated.')
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
100
|
+
// Return the write price from the update data.
|
|
101
|
+
writePrice = updateData.p2wdbWritePrice
|
|
102
|
+
} else {
|
|
103
|
+
// Approval transaction failed validation.
|
|
104
|
+
console.log(`Approval TXID was found to be invalid: ${approvalTxid}`)
|
|
109
105
|
|
|
110
|
-
|
|
106
|
+
// Add this invalid TXID to the filter array so that it is skipped.
|
|
107
|
+
this.filterTxids.push(approvalTxid)
|
|
108
|
+
|
|
109
|
+
// Continue looking for the correct approval transaction by recursivly
|
|
110
|
+
// calling this function.
|
|
111
|
+
writePrice = await this.getMcWritePrice()
|
|
112
|
+
}
|
|
111
113
|
} catch (err) {
|
|
112
|
-
console.error('Error in
|
|
113
|
-
|
|
114
|
+
console.error('Error in getMcWritePrice()')
|
|
115
|
+
console.log(`Using hard-coded, safety value of ${writePrice} PSF tokens per write.`)
|
|
114
116
|
}
|
|
117
|
+
// Save the curent write price to the state.
|
|
118
|
+
this.currentWritePrice = writePrice
|
|
119
|
+
return writePrice
|
|
115
120
|
}
|
|
116
121
|
|
|
117
|
-
// Given a
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
// be used to ignore/skip any known, fake approval transactions.
|
|
123
|
-
async getApprovalTx (inObj = {}) {
|
|
122
|
+
// Given information about a file, this function will generate a Pin Claim.
|
|
123
|
+
// This function takes controls of the wallet and uses it to broadcast two
|
|
124
|
+
// transactions: a Proof-of-Burn (pobTxid) and a Pin Claim (climTxid). The
|
|
125
|
+
// function returns an object with the transaction ID of those two transacions.
|
|
126
|
+
async createPinClaim (inObj = {}) {
|
|
124
127
|
try {
|
|
125
|
-
|
|
126
|
-
const { filterTxids } = inObj
|
|
128
|
+
const { cid, filename, fileSizeInMegabytes } = inObj
|
|
127
129
|
|
|
128
130
|
// Input validation
|
|
129
|
-
if (
|
|
130
|
-
|
|
131
|
+
if (!cid) {
|
|
132
|
+
throw new Error('cid required to generate pin claim.')
|
|
131
133
|
}
|
|
132
|
-
if (!
|
|
133
|
-
throw new Error('
|
|
134
|
+
if (!filename) {
|
|
135
|
+
throw new Error('filename required to generate pin claim.')
|
|
134
136
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const txHistory = await this.wallet.getTransactions(address)
|
|
138
|
-
// console.log('txHistory: ', JSON.stringify(txHistory, null, 2))
|
|
139
|
-
|
|
140
|
-
// Loop through the transaction history
|
|
141
|
-
for (let i = 0; i < txHistory.length; i++) {
|
|
142
|
-
const thisTxid = txHistory[i]
|
|
143
|
-
|
|
144
|
-
// const height = thisTxid.height
|
|
145
|
-
const txid = thisTxid.tx_hash
|
|
146
|
-
|
|
147
|
-
// Skip the txid if it is in the filter list.
|
|
148
|
-
if (Array.isArray(filterTxids)) {
|
|
149
|
-
const txidFound = filterTxids.find(x => x === txid)
|
|
150
|
-
// console.log('txidFound: ', txidFound)
|
|
151
|
-
if (txidFound) {
|
|
152
|
-
continue
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Get the transaction details for the transaction
|
|
157
|
-
const txDetails = await this.util.getTxData(txid)
|
|
158
|
-
// console.log('txDetails: ', JSON.stringify(txDetails, null, 2))
|
|
159
|
-
// console.log(`txid: ${txid}`)
|
|
160
|
-
|
|
161
|
-
const out2ascii = Buffer.from(txDetails.vout[0].scriptPubKey.hex, 'hex').toString('ascii')
|
|
162
|
-
// console.log('out2ascii: ', out2ascii)
|
|
163
|
-
|
|
164
|
-
// If the first output is not an OP_RETURN, then the tx can be discarded.
|
|
165
|
-
if (!out2ascii.includes('APPROVE')) {
|
|
166
|
-
continue
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const updateTxid = out2ascii.slice(10)
|
|
170
|
-
// console.log('updateTxid: ', updateTxid)
|
|
171
|
-
|
|
172
|
-
const outObj = {
|
|
173
|
-
approvalTxid: txid,
|
|
174
|
-
updateTxid,
|
|
175
|
-
approvalTxDetails: txDetails,
|
|
176
|
-
opReturn: out2ascii
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return outObj
|
|
137
|
+
if (!fileSizeInMegabytes) {
|
|
138
|
+
throw new Error('fileSizeInMegabytes size in megabytes required to generate pin claim.')
|
|
180
139
|
}
|
|
181
140
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
console.error('Error in getApprovedData()')
|
|
185
|
-
throw err
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// This function will retrieve an update transaction, given its txid. It will
|
|
190
|
-
// return an object with data about the transaction, including the CID and
|
|
191
|
-
// timestamp values encoded in the transactions OP_RETURN.
|
|
192
|
-
async getUpdateTx (inObj = {}) {
|
|
193
|
-
try {
|
|
194
|
-
const { txid } = inObj
|
|
141
|
+
// Initialize the wallet
|
|
142
|
+
await this.wallet.initialize()
|
|
195
143
|
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
throw new Error('txid required')
|
|
199
|
-
}
|
|
144
|
+
// Initialize the PS009 library
|
|
145
|
+
await this._initPs009()
|
|
200
146
|
|
|
201
|
-
// Get the
|
|
202
|
-
const
|
|
203
|
-
// console.log('txDetails: ', JSON.stringify(txDetails, null, 2))
|
|
204
|
-
// console.log(`txid: ${txid}`)
|
|
147
|
+
// Get the cost in PSF tokens to store 1MB
|
|
148
|
+
const writePrice = await this.getMcWritePrice()
|
|
205
149
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
// console.log('out2ascii: ', out2ascii)
|
|
150
|
+
// Create a proof-of-burn (PoB) transaction
|
|
151
|
+
// const WRITE_PRICE = 0.08335233 // Cost in PSF tokens to pin 1MB
|
|
152
|
+
const PSF_TOKEN_ID = '38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
|
|
210
153
|
|
|
211
|
-
|
|
212
|
-
|
|
154
|
+
// Calculate the write cost
|
|
155
|
+
const dataCost = writePrice * fileSizeInMegabytes
|
|
156
|
+
const minCost = writePrice
|
|
157
|
+
let actualCost = minCost
|
|
158
|
+
if (dataCost > minCost) actualCost = dataCost
|
|
159
|
+
console.log(`Burning ${actualCost} PSF tokens for ${fileSizeInMegabytes} MB of data.`)
|
|
213
160
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
throw new Error('Could not parse JSON inside the transaction')
|
|
217
|
-
}
|
|
161
|
+
const pobTxid = await this.wallet.burnTokens(actualCost, PSF_TOKEN_ID)
|
|
162
|
+
// console.log(`Proof-of-burn TX: ${pobTxid}`)
|
|
218
163
|
|
|
219
|
-
|
|
220
|
-
|
|
164
|
+
// Get info and libraries from the wallet.
|
|
165
|
+
const addr = this.wallet.walletInfo.address
|
|
166
|
+
const bchjs = this.wallet.bchjs
|
|
167
|
+
const wif = this.wallet.walletInfo.privateKey
|
|
221
168
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
}
|
|
169
|
+
// Get a UTXO to spend to generate the pin claim TX.
|
|
170
|
+
let utxos = await this.wallet.getUtxos()
|
|
171
|
+
utxos = utxos.bchUtxos
|
|
172
|
+
const utxo = bchjs.Utxo.findBiggestUtxo(utxos)
|
|
228
173
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
async getCidData (inObj = {}) {
|
|
232
|
-
try {
|
|
233
|
-
const { cid } = inObj
|
|
174
|
+
// instance of transaction builder
|
|
175
|
+
const transactionBuilder = new bchjs.TransactionBuilder()
|
|
234
176
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
177
|
+
const originalAmount = utxo.value
|
|
178
|
+
const vout = utxo.tx_pos
|
|
179
|
+
const txid = utxo.tx_hash
|
|
239
180
|
|
|
240
|
-
|
|
241
|
-
|
|
181
|
+
// add input with txid and index of vout
|
|
182
|
+
transactionBuilder.addInput(txid, vout)
|
|
242
183
|
|
|
243
|
-
|
|
184
|
+
// TODO: Compute the 1 sat/byte fee.
|
|
185
|
+
const fee = 500
|
|
244
186
|
|
|
245
|
-
|
|
246
|
-
} catch (err) {
|
|
247
|
-
console.error('Error in getCidData()')
|
|
248
|
-
throw err
|
|
249
|
-
}
|
|
250
|
-
}
|
|
187
|
+
// BEGIN - Construction of OP_RETURN transaction.
|
|
251
188
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
// token used to generate the PSF Minting Council NFTs.
|
|
261
|
-
async validateApproval (inObj = {}) {
|
|
262
|
-
try {
|
|
263
|
-
// console.log('inObj: ', JSON.stringify(inObj, null, 2))
|
|
189
|
+
// Add the OP_RETURN to the transaction.
|
|
190
|
+
const script = [
|
|
191
|
+
bchjs.Script.opcodes.OP_RETURN,
|
|
192
|
+
Buffer.from('00510000', 'hex'),
|
|
193
|
+
Buffer.from(pobTxid, 'hex'),
|
|
194
|
+
Buffer.from(cid),
|
|
195
|
+
Buffer.from(filename)
|
|
196
|
+
]
|
|
264
197
|
|
|
265
|
-
|
|
198
|
+
// Compile the script array into a bitcoin-compliant hex encoded string.
|
|
199
|
+
const data = bchjs.Script.encode(script)
|
|
266
200
|
|
|
267
|
-
|
|
201
|
+
// Add the OP_RETURN output.
|
|
202
|
+
transactionBuilder.addOutput(data, 0)
|
|
268
203
|
|
|
269
|
-
//
|
|
270
|
-
if (!approvalObj) {
|
|
271
|
-
throw new Error('Output object of getApprovalTx() is expected as input to this function, as \'approvalObj\'')
|
|
272
|
-
}
|
|
273
|
-
if (!updateObj) {
|
|
274
|
-
throw new Error('Output object of getUpdateTx() is expected as input to this function, as \'updateObj\'')
|
|
275
|
-
}
|
|
276
|
-
if (!updateData) {
|
|
277
|
-
throw new Error('Update CID JSON data is expected as input to this function, as \'updateData\'')
|
|
278
|
-
}
|
|
204
|
+
// END - Construction of OP_RETURN transaction.
|
|
279
205
|
|
|
280
|
-
//
|
|
281
|
-
|
|
282
|
-
const pubKeys = updateData.walletObj.publicKeys
|
|
283
|
-
const requiredSigners = updateData.walletObj.requiredSigners
|
|
284
|
-
const approvalInputAddr = approvalObj.approvalTxDetails.vin[0].address
|
|
285
|
-
const msAddr = new this.bitcore.Address(pubKeys, requiredSigners).toString()
|
|
286
|
-
if (msAddr !== approvalInputAddr) {
|
|
287
|
-
console.log(`Approval TX input address (${approvalInputAddr}) does not match calculated multisig address ${msAddr}`)
|
|
288
|
-
return validationResult
|
|
289
|
-
}
|
|
206
|
+
// Send the same amount - fee.
|
|
207
|
+
transactionBuilder.addOutput(addr, originalAmount - fee)
|
|
290
208
|
|
|
291
|
-
//
|
|
292
|
-
const
|
|
293
|
-
const tokenPubKeys = nftData.keys
|
|
209
|
+
// Create an EC Key Pair from the user-supplied WIF.
|
|
210
|
+
const ecPair = bchjs.ECPair.fromWIF(wif)
|
|
294
211
|
|
|
295
|
-
//
|
|
296
|
-
let
|
|
297
|
-
|
|
298
|
-
|
|
212
|
+
// Sign the transaction with the HD node.
|
|
213
|
+
let redeemScript
|
|
214
|
+
transactionBuilder.sign(
|
|
215
|
+
0,
|
|
216
|
+
ecPair,
|
|
217
|
+
redeemScript,
|
|
218
|
+
transactionBuilder.hashTypes.SIGHASH_ALL,
|
|
219
|
+
originalAmount
|
|
220
|
+
)
|
|
299
221
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const thisUpdatePubKey = pubKeys[j]
|
|
222
|
+
// build tx
|
|
223
|
+
const tx = transactionBuilder.build()
|
|
303
224
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
}
|
|
225
|
+
// output rawhex
|
|
226
|
+
const hex = tx.toHex()
|
|
227
|
+
// console.log(`TX hex: ${hex}`);
|
|
228
|
+
// console.log(` `);
|
|
310
229
|
|
|
311
|
-
//
|
|
312
|
-
|
|
313
|
-
|
|
230
|
+
// Broadcast transation to the network
|
|
231
|
+
const claimTxid = await this.wallet.broadcast({ hex })
|
|
232
|
+
// console.log(`Claim Transaction ID: ${claimTxid}`)
|
|
233
|
+
// console.log(`https://blockchair.com/bitcoin-cash/transaction/${claimTxid}`)
|
|
314
234
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
validationResult = true
|
|
235
|
+
return {
|
|
236
|
+
pobTxid,
|
|
237
|
+
claimTxid
|
|
319
238
|
}
|
|
320
|
-
|
|
321
|
-
return validationResult
|
|
322
239
|
} catch (err) {
|
|
323
|
-
console.error('Error in
|
|
240
|
+
console.error('Error in ps010/createPinClaim()')
|
|
324
241
|
throw err
|
|
325
242
|
}
|
|
326
243
|
}
|
|
327
244
|
}
|
|
328
245
|
|
|
329
|
-
module.exports =
|
|
246
|
+
// module.exports = PSFFPP
|
|
247
|
+
export default PSFFPP
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "psffpp",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "PS010 PSF File Pinning Protocol",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"start": "node index.js",
|
|
8
|
-
"test": "npm run lint && TEST=unit
|
|
9
|
+
"test": "npm run lint && TEST=unit c8 --reporter=text mocha test/unit/",
|
|
9
10
|
"test:integration": "mocha --timeout 120000 test/integration/",
|
|
10
11
|
"lint": "standard --env mocha --fix",
|
|
11
12
|
"docs": "./node_modules/.bin/apidoc -i src/ -o docs",
|
|
12
|
-
"coverage:report": "
|
|
13
|
+
"coverage:report": "c8 --reporter=html mocha test/unit/ --exit"
|
|
13
14
|
},
|
|
14
15
|
"keywords": [
|
|
15
16
|
"bitcoin",
|
|
@@ -33,16 +34,18 @@
|
|
|
33
34
|
"repository": "Permissionless-Software-Foundation/psffpp",
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"axios": "1.3.5",
|
|
36
|
-
"bitcore-lib-cash": "10.0.2"
|
|
37
|
+
"bitcore-lib-cash": "10.0.2",
|
|
38
|
+
"psf-multisig-approval": "2.0.3"
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
41
|
+
"@psf/bch-js": "^6.7.4",
|
|
39
42
|
"apidoc": "0.54.0",
|
|
43
|
+
"c8": "^9.1.0",
|
|
40
44
|
"chai": "4.3.7",
|
|
41
45
|
"husky": "8.0.3",
|
|
42
46
|
"lodash.clonedeep": "4.5.0",
|
|
43
47
|
"minimal-slp-wallet": "5.8.8",
|
|
44
48
|
"mocha": "10.2.0",
|
|
45
|
-
"nyc": "15.1.0",
|
|
46
49
|
"semantic-release": "19.0.5",
|
|
47
50
|
"sinon": "15.0.3",
|
|
48
51
|
"standard": "17.0.0"
|