psffpp 1.1.13 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -72,6 +72,21 @@ claimTxid: db338fdb7edc6ce6685c9897a9d9fd6f0e26d194bf12e1c87470b7dc2103a3e3
72
72
  */
73
73
  ```
74
74
 
75
+ ## Get Write Price History
76
+
77
+ The write price changs over time. This function returns an array of objects, where each object returns the price change and the block height the change went into effect.
78
+
79
+ ```javascript
80
+ const writeHistory = await psffpp.getWritePriceHistory()
81
+ console.log(writeHistory)
82
+
83
+ /*
84
+ [
85
+ { writePrice: 0.03570889, height: 893165 },
86
+ { writePrice: 0.08335233, height: 780917 }
87
+ ]
88
+ */
89
+ ```
75
90
 
76
91
  # License
77
92
  [MIT](LICENSE.md)
@@ -0,0 +1,46 @@
1
+ /* >
2
+ This example shows how to get the write price update history.
3
+ */
4
+
5
+ import SlpWallet from 'minimal-slp-wallet'
6
+ import PSFFPP from '../index.js'
7
+
8
+ async function start () {
9
+ try {
10
+ let now = new Date()
11
+ console.log('Start time: ', now.toLocaleString())
12
+
13
+ // Instance the BCH wallet
14
+ const wallet = new SlpWallet(undefined, {
15
+ interface: 'consumer-api',
16
+ // restURL: 'https://free-bch.fullstack.cash'
17
+ // restURL: 'https://dev-consumer.psfoundation.info'
18
+ restURL: 'http://localhost:5015'
19
+ })
20
+ await wallet.initialize()
21
+
22
+ // Instance this library
23
+ const psffpp = new PSFFPP({ wallet })
24
+
25
+ now = new Date()
26
+ console.log(`1st write price lookup started at ${now.toLocaleString()}`)
27
+
28
+ // Get the current write price
29
+ const writePrice = await psffpp.getWritePriceHistory()
30
+ console.log('1st writePrice: ', writePrice)
31
+
32
+ now = new Date()
33
+ console.log(`2nd write price lookup started at ${now.toLocaleString()}`)
34
+
35
+ // Get the current write price
36
+ const writePrice2 = await psffpp.getWritePriceHistory()
37
+ console.log('2nd writePrice: ', writePrice2)
38
+
39
+ now = new Date()
40
+ console.log(`Finished at ${now.toLocaleString()}`)
41
+ } catch (err) {
42
+ console.error(err)
43
+ }
44
+ }
45
+
46
+ start()
@@ -13,7 +13,9 @@ async function start () {
13
13
  // Instance the BCH wallet
14
14
  const wallet = new SlpWallet(undefined, {
15
15
  interface: 'consumer-api',
16
- restURL: 'https://free-bch.fullstack.cash'
16
+ // restURL: 'https://free-bch.fullstack.cash'
17
+ // restURL: 'https://dev-consumer.psfoundation.info'
18
+ restURL: 'http://localhost:5015'
17
19
  })
18
20
  await wallet.initialize()
19
21
 
package/index.js CHANGED
@@ -9,8 +9,18 @@ import MultisigApproval from 'psf-multisig-approval'
9
9
  // Local libraries
10
10
 
11
11
  // Constants
12
- const PSF_HARDCODE_WRITE_PRICE = 0.08335233
12
+ const PSF_HARDCODE_WRITE_PRICE = 0.03570889
13
13
  const WRITE_PRICE_ADDR = 'bitcoincash:qrwe6kxhvu47ve6jvgrf2d93w0q38av7s5xm9xfehr'
14
+ const PSF_HARDCODE_WRITE_PRICE_HISTORY = [
15
+ {
16
+ writePrice: 0.03570889,
17
+ height: 893165
18
+ },
19
+ {
20
+ writePrice: 0.08335233,
21
+ blockHeight: 780917
22
+ }
23
+ ]
14
24
 
15
25
  class PSFFPP {
16
26
  constructor (localConfig = {}) {
@@ -20,17 +30,27 @@ class PSFFPP {
20
30
  throw new Error('Instance of minimal-slp-wallet must be passed in as a property called \'wallet\', when initializing the psf-multisig-approval library.')
21
31
  }
22
32
 
33
+ // Allow user to pass in alternative IPFS gateway.
34
+ this.ipfsGateway = localConfig.ipfsGateway
35
+ if (!this.ipfsGateway) {
36
+ this.ipfsGateway = 'https://free-bch.fullstack.cash'
37
+ }
38
+
23
39
  // Encapsulate dependencies
24
40
  this.bchjs = this.wallet.bchjs
25
41
  this.ps009 = null // placeholder for Multisig Approval library.
26
42
 
27
43
  // Bind the this object to all subfunctions in this class
28
44
  this._initPs009 = this._initPs009.bind(this)
29
- this.getMcWritePrice = this.getMcWritePrice.bind(this)
30
45
  this.createPinClaim = this.createPinClaim.bind(this)
46
+ this.getMcWritePrice = this.getMcWritePrice.bind(this)
47
+ this.getWritePriceHistory = this.getWritePriceHistory.bind(this)
31
48
 
32
49
  // State
33
50
  this.currentWritePrice = null
51
+ this.priceRetrievalSucceeded = false
52
+ this.currentWritePriceHistory = null
53
+ this.priceHistoryRetrievalSucceeded = false
34
54
  this.filterTxids = []
35
55
  }
36
56
 
@@ -38,87 +58,17 @@ class PSFFPP {
38
58
  // initialized.
39
59
  async _initPs009 () {
40
60
  if (!this.ps009) {
41
- this.ps009 = new MultisigApproval({ wallet: this.wallet })
61
+ const inObj = {
62
+ wallet: this.wallet,
63
+ ipfsGateway: this.ipfsGateway
64
+ }
65
+ // console.log('inObj: ', inObj)
66
+ this.ps009 = new MultisigApproval(inObj)
42
67
  }
43
68
 
44
69
  return true
45
70
  }
46
71
 
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
57
-
58
- try {
59
- // Return the saved write price if this function has already been called once.
60
- if (this.currentWritePrice) return this.currentWritePrice
61
-
62
- await this._initPs009()
63
-
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))
71
-
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.`)
76
- }
77
-
78
- const { approvalTxid, updateTxid } = approvalObj
79
- console.log(`New approval txid found (${approvalTxid}), validating...`)
80
-
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
85
-
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)}`)
89
-
90
- // Validate the approval transaction
91
- const approvalIsValid = await this.ps009.validateApproval({
92
- approvalObj,
93
- updateObj,
94
- updateData
95
- })
96
-
97
- if (approvalIsValid) {
98
- console.log('Approval TX validated.')
99
-
100
- // Return the write price from the update data.
101
- writePrice = updateData.p2wdbWritePrice
102
- } else {
103
- // Approval transaction failed validation.
104
- console.log(`Approval TX was found to be invalid: ${approvalTxid}`)
105
-
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
- }
113
- } catch (err) {
114
- console.error('Error in getMcWritePrice(): ', err)
115
- console.log(`Using hard-coded, safety value of ${writePrice} PSF tokens per write.`)
116
- }
117
- // Save the curent write price to the state.
118
- this.currentWritePrice = writePrice
119
- return writePrice
120
- }
121
-
122
72
  // Given information about a file, this function will generate a Pin Claim.
123
73
  // This function takes controls of the wallet and uses it to broadcast two
124
74
  // transactions: a Proof-of-Burn (pobTxid) and a Pin Claim (climTxid). The
@@ -247,6 +197,184 @@ class PSFFPP {
247
197
  throw err
248
198
  }
249
199
  }
200
+
201
+ // Get the write price set by the PSF Minting Council.
202
+ // This function assumes the transaction history retrieved from the Cash
203
+ // Stack is sorted in descending order with the biggest (newest) block
204
+ // in the first element in the transaction history array.
205
+ async getMcWritePrice () {
206
+ // Hard codeded value. 3/2/24
207
+ // This value is returned if there are any issues returning the write price.
208
+ // It should be higher than actual fee, so that any writes will propegate to
209
+ // the nodes that successfully retrieved the current write price.
210
+ let writePrice = PSF_HARDCODE_WRITE_PRICE
211
+
212
+ try {
213
+ // Return the saved write price if this function has already been called once.
214
+ if (this.currentWritePrice && this.priceRetrievalSucceeded) return this.currentWritePrice
215
+
216
+ await this._initPs009()
217
+
218
+ // Find the PS009 approval transaction the addresses tx history.
219
+ console.log('\nSearching blockchain for updated write price...')
220
+ const approvalObj = await this.ps009.getApprovalTx({
221
+ address: WRITE_PRICE_ADDR,
222
+ filterTxids: this.filterTxids
223
+ })
224
+ // console.log('approvalObj: ', JSON.stringify(approvalObj, null, 2))
225
+
226
+ // Throw an error if no approval transaction can be found in the
227
+ // transaction history.
228
+ if (approvalObj === null) {
229
+ throw new Error(`APPROVAL transaction could not be found in the TX history of ${WRITE_PRICE_ADDR}. Can not reach consensus on write price.`)
230
+ }
231
+
232
+ const { approvalTxid, updateTxid } = approvalObj
233
+ console.log(`New approval txid found (${approvalTxid}), validating...`)
234
+
235
+ // Get the CID from the update transaction.
236
+ const updateObj = await this.ps009.getUpdateTx({ txid: updateTxid })
237
+ // console.log(`updateObj: ${JSON.stringify(updateObj, null, 2)}`)
238
+ const { cid } = updateObj
239
+
240
+ // Resolve the CID into JSON data from the IPFS gateway.
241
+ const updateData = await this.ps009.getCidData({ cid })
242
+ // console.log(`updateData: ${JSON.stringify(updateData, null, 2)}`)
243
+
244
+ // Validate the approval transaction
245
+ const approvalIsValid = await this.ps009.validateApproval({
246
+ approvalObj,
247
+ updateObj,
248
+ updateData
249
+ })
250
+
251
+ if (approvalIsValid) {
252
+ console.log('Approval TX validated.')
253
+ // console.log('updateData: ', updateData)
254
+
255
+ // Return the write price from the update data.
256
+ writePrice = updateData.p2wdbWritePrice || updateData.writePrice
257
+
258
+ this.priceRetrievalSucceeded = true
259
+ } else {
260
+ // Approval transaction failed validation.
261
+ console.log(`Approval TX was found to be invalid: ${approvalTxid}`)
262
+
263
+ // Add this invalid TXID to the filter array so that it is skipped.
264
+ this.filterTxids.push(approvalTxid)
265
+
266
+ // Continue looking for the correct approval transaction by recursivly
267
+ // calling this function.
268
+ writePrice = await this.getMcWritePrice()
269
+ }
270
+ } catch (err) {
271
+ console.error('Error in getMcWritePrice(): ', err)
272
+ console.log(`Using hard-coded, safety value of ${writePrice} PSF tokens per write.`)
273
+ }
274
+
275
+ // Save the curent write price to the state.
276
+ if (this.priceRetrievalSucceeded) {
277
+ this.currentWritePrice = writePrice
278
+ }
279
+ return writePrice
280
+ }
281
+
282
+ // Get the write price history from the PSF Minting Council.
283
+ // Where getMcWritePrice() gets the current write price, this function
284
+ // returns an array of objects. Each object contains a validated
285
+ // price change, and the block height when the change took effect.
286
+ async getWritePriceHistory () {
287
+ // Hard codeded value. 3/2/24
288
+ // This value is returned if there are any issues returning the write price.
289
+ // It should be higher than actual fee, so that any writes will propagate to
290
+ // the nodes that successfully retrieved the current write price.
291
+ // let writePrice = PSF_HARDCODE_WRITE_PRICE
292
+ const writePriceHistory = []
293
+
294
+ try {
295
+ // Return the saved write price if this function has already been called once.
296
+ if (this.currentWritePriceHistory && this.priceHistoryRetrievalSucceeded) {
297
+ return this.currentWritePriceHistory
298
+ }
299
+
300
+ await this._initPs009()
301
+
302
+ // Find the PS009 approval transaction the addresses tx history.
303
+ console.log('\nSearching blockchain for PSF write price update history...')
304
+ const approvals = await this.ps009.getAllApprovalTxs({
305
+ address: WRITE_PRICE_ADDR,
306
+ filterTxids: this.filterTxids
307
+ })
308
+ // console.log('approvals: ', JSON.stringify(approvals, null, 2))
309
+
310
+ // Throw an error if no approval transaction can be found in the
311
+ // transaction history.
312
+ if (!approvals || !approvals.length) {
313
+ throw new Error(`APPROVAL transaction could not be found in the TX history of ${WRITE_PRICE_ADDR}. Can not reach consensus on write price.`)
314
+ }
315
+
316
+ for (let i = 0; i < approvals.length; i++) {
317
+ const approvalObj = approvals[i]
318
+
319
+ // Retrieve the block height for the transaction. This data was made
320
+ // available in bch-api 2.6.2.
321
+ const height = approvalObj.approvalTxDetails.height
322
+ if (!height) {
323
+ throw new Error('TX block height not available. Be sure your back end is using bch-api 2.6.2 or later.')
324
+ }
325
+
326
+ const { approvalTxid, updateTxid } = approvalObj
327
+ console.log(`Validating approval txid ${approvalTxid}...`)
328
+
329
+ // Get the CID from the update transaction.
330
+ const updateObj = await this.ps009.getUpdateTx({ txid: updateTxid })
331
+ // console.log(`updateObj: ${JSON.stringify(updateObj, null, 2)}`)
332
+ const { cid } = updateObj
333
+
334
+ // Resolve the CID into JSON data from the IPFS gateway.
335
+ const updateData = await this.ps009.getCidData({ cid })
336
+ // console.log(`updateData: ${JSON.stringify(updateData, null, 2)}`)
337
+
338
+ // Validate the approval transaction
339
+ const approvalIsValid = await this.ps009.validateApproval({
340
+ approvalObj,
341
+ updateObj,
342
+ updateData
343
+ })
344
+
345
+ if (approvalIsValid) {
346
+ console.log('Approval TX validated.')
347
+ // console.log('updateData: ', updateData)
348
+
349
+ // Return the write price from the update data.
350
+ const writePrice = updateData.p2wdbWritePrice || updateData.writePrice
351
+
352
+ const entry = {
353
+ writePrice,
354
+ height
355
+ }
356
+
357
+ writePriceHistory.push(entry)
358
+ console.log(`writePriceHistory: ${JSON.stringify(writePriceHistory, null, 2)}`)
359
+ } else {
360
+ // Approval transaction failed validation.
361
+ console.log(`Approval TX was found to be invalid: ${approvalTxid}`)
362
+
363
+ // Add this invalid TXID to the filter array so that it is skipped.
364
+ this.filterTxids.push(approvalTxid)
365
+ }
366
+ }
367
+
368
+ this.priceHistoryRetrievalSucceeded = true
369
+ this.currentWritePriceHistory = writePriceHistory
370
+
371
+ return writePriceHistory
372
+ } catch (err) {
373
+ console.error('Error in getWritePriceHistory(): ', err)
374
+ console.log('Returning hard-coded write price history.')
375
+ return PSF_HARDCODE_WRITE_PRICE_HISTORY
376
+ }
377
+ }
250
378
  }
251
379
 
252
380
  // module.exports = PSFFPP
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "psffpp",
3
- "version": "1.1.13",
3
+ "version": "1.2.1",
4
4
  "description": "PS010 PSF File Pinning Protocol",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -34,7 +34,7 @@
34
34
  "repository": "Permissionless-Software-Foundation/psffpp",
35
35
  "dependencies": {
36
36
  "axios": "1.3.5",
37
- "psf-multisig-approval": "2.0.10"
37
+ "psf-multisig-approval": "2.1.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@psf/bch-js": "6.8.0",
@@ -91,7 +91,8 @@ describe('#PSFFPP-index.js', () => {
91
91
  const result = await uut.getMcWritePrice()
92
92
  // console.log('result: ', result)
93
93
 
94
- assert.equal(result, 0.08335233)
94
+ // assert.equal(result, 0.08335233)
95
+ assert.equal(result, 0.03570889)
95
96
  })
96
97
 
97
98
  it('should throw error and return safety price if wallet is not initialized', async () => {
@@ -100,7 +101,9 @@ describe('#PSFFPP-index.js', () => {
100
101
 
101
102
  const result = await uut.getMcWritePrice()
102
103
  // console.log('result: ', result)
103
- assert.equal(result, 0.08335233)
104
+
105
+ // assert.equal(result, 0.08335233)
106
+ assert.equal(result, 0.03570889)
104
107
  })
105
108
  })
106
109