psffpp 1.1.13 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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 = {}) {
@@ -26,11 +36,15 @@ class PSFFPP {
26
36
 
27
37
  // Bind the this object to all subfunctions in this class
28
38
  this._initPs009 = this._initPs009.bind(this)
29
- this.getMcWritePrice = this.getMcWritePrice.bind(this)
30
39
  this.createPinClaim = this.createPinClaim.bind(this)
40
+ this.getMcWritePrice = this.getMcWritePrice.bind(this)
41
+ this.getWritePriceHistory = this.getWritePriceHistory.bind(this)
31
42
 
32
43
  // State
33
44
  this.currentWritePrice = null
45
+ this.priceRetrievalSucceeded = false
46
+ this.currentWritePriceHistory = null
47
+ this.priceHistoryRetrievalSucceeded = false
34
48
  this.filterTxids = []
35
49
  }
36
50
 
@@ -44,81 +58,6 @@ class PSFFPP {
44
58
  return true
45
59
  }
46
60
 
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
61
  // Given information about a file, this function will generate a Pin Claim.
123
62
  // This function takes controls of the wallet and uses it to broadcast two
124
63
  // transactions: a Proof-of-Burn (pobTxid) and a Pin Claim (climTxid). The
@@ -247,6 +186,184 @@ class PSFFPP {
247
186
  throw err
248
187
  }
249
188
  }
189
+
190
+ // Get the write price set by the PSF Minting Council.
191
+ // This function assumes the transaction history retrieved from the Cash
192
+ // Stack is sorted in descending order with the biggest (newest) block
193
+ // in the first element in the transaction history array.
194
+ async getMcWritePrice () {
195
+ // Hard codeded value. 3/2/24
196
+ // This value is returned if there are any issues returning the write price.
197
+ // It should be higher than actual fee, so that any writes will propegate to
198
+ // the nodes that successfully retrieved the current write price.
199
+ let writePrice = PSF_HARDCODE_WRITE_PRICE
200
+
201
+ try {
202
+ // Return the saved write price if this function has already been called once.
203
+ if (this.currentWritePrice && this.priceRetrievalSucceeded) return this.currentWritePrice
204
+
205
+ await this._initPs009()
206
+
207
+ // Find the PS009 approval transaction the addresses tx history.
208
+ console.log('\nSearching blockchain for updated write price...')
209
+ const approvalObj = await this.ps009.getApprovalTx({
210
+ address: WRITE_PRICE_ADDR,
211
+ filterTxids: this.filterTxids
212
+ })
213
+ // console.log('approvalObj: ', JSON.stringify(approvalObj, null, 2))
214
+
215
+ // Throw an error if no approval transaction can be found in the
216
+ // transaction history.
217
+ if (approvalObj === null) {
218
+ throw new Error(`APPROVAL transaction could not be found in the TX history of ${WRITE_PRICE_ADDR}. Can not reach consensus on write price.`)
219
+ }
220
+
221
+ const { approvalTxid, updateTxid } = approvalObj
222
+ console.log(`New approval txid found (${approvalTxid}), validating...`)
223
+
224
+ // Get the CID from the update transaction.
225
+ const updateObj = await this.ps009.getUpdateTx({ txid: updateTxid })
226
+ // console.log(`updateObj: ${JSON.stringify(updateObj, null, 2)}`)
227
+ const { cid } = updateObj
228
+
229
+ // Resolve the CID into JSON data from the IPFS gateway.
230
+ const updateData = await this.ps009.getCidData({ cid })
231
+ // console.log(`updateData: ${JSON.stringify(updateData, null, 2)}`)
232
+
233
+ // Validate the approval transaction
234
+ const approvalIsValid = await this.ps009.validateApproval({
235
+ approvalObj,
236
+ updateObj,
237
+ updateData
238
+ })
239
+
240
+ if (approvalIsValid) {
241
+ console.log('Approval TX validated.')
242
+ // console.log('updateData: ', updateData)
243
+
244
+ // Return the write price from the update data.
245
+ writePrice = updateData.p2wdbWritePrice || updateData.writePrice
246
+
247
+ this.priceRetrievalSucceeded = true
248
+ } else {
249
+ // Approval transaction failed validation.
250
+ console.log(`Approval TX was found to be invalid: ${approvalTxid}`)
251
+
252
+ // Add this invalid TXID to the filter array so that it is skipped.
253
+ this.filterTxids.push(approvalTxid)
254
+
255
+ // Continue looking for the correct approval transaction by recursivly
256
+ // calling this function.
257
+ writePrice = await this.getMcWritePrice()
258
+ }
259
+ } catch (err) {
260
+ console.error('Error in getMcWritePrice(): ', err)
261
+ console.log(`Using hard-coded, safety value of ${writePrice} PSF tokens per write.`)
262
+ }
263
+
264
+ // Save the curent write price to the state.
265
+ if (this.priceRetrievalSucceeded) {
266
+ this.currentWritePrice = writePrice
267
+ }
268
+ return writePrice
269
+ }
270
+
271
+ // Get the write price history from the PSF Minting Council.
272
+ // Where getMcWritePrice() gets the current write price, this function
273
+ // returns an array of objects. Each object contains a validated
274
+ // price change, and the block height when the change took effect.
275
+ async getWritePriceHistory () {
276
+ // Hard codeded value. 3/2/24
277
+ // This value is returned if there are any issues returning the write price.
278
+ // It should be higher than actual fee, so that any writes will propagate to
279
+ // the nodes that successfully retrieved the current write price.
280
+ // let writePrice = PSF_HARDCODE_WRITE_PRICE
281
+ const writePriceHistory = []
282
+
283
+ try {
284
+ // Return the saved write price if this function has already been called once.
285
+ if (this.currentWritePriceHistory && this.priceHistoryRetrievalSucceeded) {
286
+ return this.currentWritePriceHistory
287
+ }
288
+
289
+ await this._initPs009()
290
+
291
+ // Find the PS009 approval transaction the addresses tx history.
292
+ console.log('\nSearching blockchain for PSF write price update history...')
293
+ const approvals = await this.ps009.getAllApprovalTxs({
294
+ address: WRITE_PRICE_ADDR,
295
+ filterTxids: this.filterTxids
296
+ })
297
+ // console.log('approvals: ', JSON.stringify(approvals, null, 2))
298
+
299
+ // Throw an error if no approval transaction can be found in the
300
+ // transaction history.
301
+ if (!approvals || !approvals.length) {
302
+ throw new Error(`APPROVAL transaction could not be found in the TX history of ${WRITE_PRICE_ADDR}. Can not reach consensus on write price.`)
303
+ }
304
+
305
+ for (let i = 0; i < approvals.length; i++) {
306
+ const approvalObj = approvals[i]
307
+
308
+ // Retrieve the block height for the transaction. This data was made
309
+ // available in bch-api 2.6.2.
310
+ const height = approvalObj.approvalTxDetails.height
311
+ if (!height) {
312
+ throw new Error('TX block height not available. Be sure your back end is using bch-api 2.6.2 or later.')
313
+ }
314
+
315
+ const { approvalTxid, updateTxid } = approvalObj
316
+ console.log(`Validating approval txid ${approvalTxid}...`)
317
+
318
+ // Get the CID from the update transaction.
319
+ const updateObj = await this.ps009.getUpdateTx({ txid: updateTxid })
320
+ // console.log(`updateObj: ${JSON.stringify(updateObj, null, 2)}`)
321
+ const { cid } = updateObj
322
+
323
+ // Resolve the CID into JSON data from the IPFS gateway.
324
+ const updateData = await this.ps009.getCidData({ cid })
325
+ // console.log(`updateData: ${JSON.stringify(updateData, null, 2)}`)
326
+
327
+ // Validate the approval transaction
328
+ const approvalIsValid = await this.ps009.validateApproval({
329
+ approvalObj,
330
+ updateObj,
331
+ updateData
332
+ })
333
+
334
+ if (approvalIsValid) {
335
+ console.log('Approval TX validated.')
336
+ // console.log('updateData: ', updateData)
337
+
338
+ // Return the write price from the update data.
339
+ const writePrice = updateData.p2wdbWritePrice || updateData.writePrice
340
+
341
+ const entry = {
342
+ writePrice,
343
+ height
344
+ }
345
+
346
+ writePriceHistory.push(entry)
347
+ console.log(`writePriceHistory: ${JSON.stringify(writePriceHistory, null, 2)}`)
348
+ } else {
349
+ // Approval transaction failed validation.
350
+ console.log(`Approval TX was found to be invalid: ${approvalTxid}`)
351
+
352
+ // Add this invalid TXID to the filter array so that it is skipped.
353
+ this.filterTxids.push(approvalTxid)
354
+ }
355
+ }
356
+
357
+ this.priceHistoryRetrievalSucceeded = true
358
+ this.currentWritePriceHistory = writePriceHistory
359
+
360
+ return writePriceHistory
361
+ } catch (err) {
362
+ console.error('Error in getWritePriceHistory(): ', err)
363
+ console.log('Returning hard-coded write price history.')
364
+ return PSF_HARDCODE_WRITE_PRICE_HISTORY
365
+ }
366
+ }
250
367
  }
251
368
 
252
369
  // 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.0",
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