@aioha/tx-digest 2.0.0 → 2.0.2

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 ADDED
@@ -0,0 +1,48 @@
1
+ # @aioha/tx-digest
2
+
3
+ Hive transaction serializer and digest. Useful for generating ID for a transaction. Serializers extracted from hive-tx and adapted for HF26 serialization. Intended for browser use as it uses `window.crypto` for sha256.
4
+
5
+ ## Usage
6
+
7
+ ```js
8
+ import { transactionDigest } from '@aioha/tx-digest'
9
+
10
+ // https://hafscan.techcoderx.com/tx/543058b4465cd93132b2843b751d5dcdd8efd341
11
+ const recurrent_transfer = {
12
+ ref_block_num: 23679,
13
+ ref_block_prefix: 291568045,
14
+ expiration: '2025-11-20T07:59:08',
15
+ operations: [
16
+ {
17
+ type: 'recurrent_transfer_operation',
18
+ value: {
19
+ to: 'techcoderx.vsc',
20
+ from: 'techcoderx',
21
+ memo: '',
22
+ amount: {
23
+ nai: '@@000000021',
24
+ amount: '2',
25
+ precision: 3
26
+ },
27
+ executions: 5,
28
+ extensions: [
29
+ {
30
+ type: 'recurrent_transfer_pair_id',
31
+ value: {
32
+ pair_id: 1
33
+ }
34
+ }
35
+ ],
36
+ recurrence: 48
37
+ }
38
+ }
39
+ ],
40
+ signatures: [
41
+ '1f3f2ddfc755936e0b998c78a1aec35a9663d1d9011cd4a83be84c6340f1b8689826fbd0e32c918afca38ab1e6ec44eac85a0e281c39bf1400f5e53c8b810a3bf5'
42
+ ],
43
+ extensions: []
44
+ }
45
+
46
+ const serialized = await transactionDigest(recurrent_transfer)
47
+ console.log(serialized.txId) // 85db372428a47aba8aeb154df8650a900c612fa5
48
+ ```
@@ -3,7 +3,8 @@ import { HexBuffer } from './HexBuffer.js'
3
3
 
4
4
  const Extensions = {
5
5
  comment_payout_beneficiaries: 0,
6
- update_proposal_end_date: 1
6
+ update_proposal_end_date: 1,
7
+ recurrent_transfer_pair_id: 1
7
8
  }
8
9
 
9
10
  const NaiUint32 = (nai) => {
@@ -369,14 +370,14 @@ OperationSerializers.escrow_release_operation = OperationDataSerializer(29, [
369
370
  OperationSerializers.escrow_transfer_operation = OperationDataSerializer(27, [
370
371
  ['from', StringSerializer],
371
372
  ['to', StringSerializer],
372
- ['agent', StringSerializer],
373
- ['escrow_id', UInt32Serializer],
374
373
  ['hbd_amount', AssetSerializer],
375
374
  ['hive_amount', AssetSerializer],
375
+ ['escrow_id', UInt32Serializer],
376
+ ['agent', StringSerializer],
376
377
  ['fee', AssetSerializer],
378
+ ['json_meta', StringSerializer],
377
379
  ['ratification_deadline', DateSerializer],
378
- ['escrow_expiration', DateSerializer],
379
- ['json_meta', StringSerializer]
380
+ ['escrow_expiration', DateSerializer]
380
381
  ])
381
382
 
382
383
  OperationSerializers.feed_publish_operation = OperationDataSerializer(7, [
@@ -559,7 +560,7 @@ OperationSerializers.recurrent_transfer_operation = OperationDataSerializer(49,
559
560
  ['memo', StringSerializer],
560
561
  ['recurrence', UInt16Serializer],
561
562
  ['executions', UInt16Serializer],
562
- ['extensions', ArraySerializer(VoidSerializer)]
563
+ ['extensions', ArraySerializer(ExtensionSerializer(ObjectSerializer([['pair_id', UInt8Serializer]])))]
563
564
  ])
564
565
 
565
566
  const OperationSerializer = (buffer, operation) => {
package/index.d.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  export const transactionDigest: (
2
2
  transaction: any,
3
- chainId?: Uint8Array
3
+ chainId?: Uint8Array | string,
4
+ sha256?: (message: any) => Promise<Uint8Array> | Uint8Array
4
5
  ) => Promise<{
5
6
  digest: Uint8Array
6
7
  txId: string
8
+ bin: Uint8Array<ArrayBuffer>
7
9
  }>
10
+
11
+ export const MAINNET_CHAIN_ID: Uint8Array
package/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import { ByteBuffer } from './helpers/ByteBuffer.js'
2
2
  import { Serializer } from './helpers/serializer.js'
3
3
  import { hexToUint8Array, uint8ArrayToHex } from './helpers/uint8Array.js'
4
- // import { sha256 } from '@noble/hashes/sha2'
5
4
 
6
- export const sha256 = async (message) => {
5
+ export const sha256Browser = async (message) => {
7
6
  const hashBuffer = await window.crypto.subtle.digest('SHA-256', message)
8
7
  return new Uint8Array(hashBuffer)
9
8
  }
10
9
 
11
- const CHAIN_ID = hexToUint8Array('beeab0de00000000000000000000000000000000000000000000000000000000')
10
+ export const MAINNET_CHAIN_ID = hexToUint8Array('beeab0de00000000000000000000000000000000000000000000000000000000')
12
11
 
13
- export const transactionDigest = async (transaction, chainId = CHAIN_ID) => {
12
+ export const transactionDigest = async (transaction, chainId = MAINNET_CHAIN_ID, sha256 = sha256Browser) => {
13
+ if (typeof chainId === 'string') chainId = hexToUint8Array(chainId)
14
14
  const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN)
15
15
  const temp = { ...transaction }
16
16
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aioha/tx-digest",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Hive transaction serializer and digest",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -17,7 +17,11 @@
17
17
  "dependencies": {
18
18
  "bs58": "^6.0.0"
19
19
  },
20
+ "devDependencies": {
21
+ "@noble/hashes": "^2.0.1",
22
+ "vitest": "^4.0.17"
23
+ },
20
24
  "scripts": {
21
- "test": "echo \"Error: no test specified\" && exit 1"
25
+ "test": "vitest"
22
26
  }
23
27
  }
@@ -0,0 +1,194 @@
1
+ import { transactionDigest, MAINNET_CHAIN_ID } from './index.js'
2
+ import { uint8ArrayToHex } from './helpers/uint8Array.js'
3
+ import { sha256 } from '@noble/hashes/sha2.js'
4
+ import { describe, it, expect } from 'vitest'
5
+
6
+ // b17c2f23e2a6c90ad02879f24b0e42a0d18b5590
7
+ const claim = {
8
+ expiration: '2025-09-27T15:28:10',
9
+ extensions: [],
10
+ operations: [
11
+ {
12
+ type: 'claim_reward_balance_operation',
13
+ value: {
14
+ account: 'techcoderx',
15
+ reward_hbd: {
16
+ nai: '@@000000013',
17
+ amount: '0',
18
+ precision: 3
19
+ },
20
+ reward_hive: {
21
+ nai: '@@000000021',
22
+ amount: '0',
23
+ precision: 3
24
+ },
25
+ reward_vests: {
26
+ nai: '@@000000037',
27
+ amount: '14537722209',
28
+ precision: 6
29
+ }
30
+ }
31
+ }
32
+ ],
33
+ signatures: [
34
+ '20439158a011f59ca21f513287e7f1a131b654681d34d9dbecbea147565bf5cbe65ba440f19da6ec52c089497b9d26c22828ede8d0893b5977cc97ef50a20e4dbc'
35
+ ],
36
+ ref_block_num: 52283,
37
+ ref_block_prefix: 3934909655
38
+ }
39
+
40
+ // a931bb64b6208f61db80c5c3d1f9846b3e71a4a4
41
+ const updateProposal = {
42
+ expiration: '2021-07-09T20:47:48',
43
+ extensions: [],
44
+ operations: [
45
+ {
46
+ type: 'update_proposal_operation',
47
+ value: {
48
+ creator: 'gtg',
49
+ subject: 'Return Proposal',
50
+ permlink: 'dhf',
51
+ daily_pay: {
52
+ nai: '@@000000013',
53
+ amount: '240000000000',
54
+ precision: 3
55
+ },
56
+ extensions: [
57
+ {
58
+ type: 'update_proposal_end_date',
59
+ value: {
60
+ end_date: '2029-12-31T23:59:59'
61
+ }
62
+ }
63
+ ],
64
+ proposal_id: 0
65
+ }
66
+ }
67
+ ],
68
+ signatures: [
69
+ '1f24cfcb492e114ed3dcc94b5db3f723bb1dd0bc83ecf8173c5d0b8961b77cab2b304822d49c08a8c4819d00edc2543a1bc5d15ae3d67a0d4c7d2f62de9fcf5635'
70
+ ],
71
+ ref_block_num: 58226,
72
+ ref_block_prefix: 2691348452
73
+ }
74
+
75
+ // e22731db90536bd7c3f8f479222df1bfeee0a7d4
76
+ const comment = {
77
+ expiration: '2025-09-22T14:13:21',
78
+ extensions: [],
79
+ operations: [
80
+ {
81
+ type: 'comment_operation',
82
+ value: {
83
+ body: "![Swarm of Swarms.png](https://files.peakd.com/file/peakd-hive/hivetoday/23tRtDT6aA76uLofgm6esw7paCg95LwmhXfqBykzaoopU8sN3yJqLRj4qR4LmHUtQHgwV.png)\n\nIf you missed our earlier blog post, scroll to the bottom for an explanation of what a Swarm of Swarms is. \n\n--- \n\n# This Week’s Developer Updates\n\nFive teams responded this week to share updates on their active projects. In no particular order:\n\n---\n\n# Team Ureka.Social (@ura-soul / @ureka.social)\n\n## Ureka:\n- Added: Advanced real-time notifications - via custom setup of Peakd Open Notification Server\n- Added: Audible notifications\n- Added: Desktop notifications\n- Added: Delegation Tracking System.\n- Added: Feed pages for public tracking of follower posts\n- Improved: Terms / Privacy / FAQ Documents\n- Improved: Widened main page content on larger screens\n- Improved: Formatting of Threads posts\n- Fixed: User avatar incorrect alignment\n- Fixed: Negative reputations defaulting to 25\n- Fixed: Reblogs not always being tracked correctly\n- Fixed: Delegations issuance failed\n- Fixed: Currency conversion labels now update correctly on wallet popups\n- Fixed: Sitemap updated to correct domain\n- Fixed: Extensive rework of comment indenting on mobile\n- Fixed: Incorrect individual vote values when downvotes are present\n- Fixed: Editing posts did not complete in the UI\n- Fixed: Overlay BG was improperly aligned\n\n---\n\n# Team Techcoderx (@techcoderx / @aioha)\n\n## VSC\n* Output contract error symbols\n* Contract owner accessible from `system.get_env` and `system.get_env_key` SDK method call\n* SDK method for retrieving contract state by key of another contract\n* SDK method for intercontract calls\n\n---\n\n# Team Threespeak Witness (@sagarkothari88 / @threespeak)\n\n## Distriator\n\n- Reports sorted ascending, added tooltips with profile pics,\n- Reports CSV/PDF export added\n- Business reviews & photos cached, hide/unhide with proper permissions.\n- Added Skeleton loaders\n- Added auto-login for AtiHotel\n- Reports optimization - faster reports & analytics\n- Added wallet overview\n\n## Checkinwith.xyz\n\n- Added Rank column to onboarding reports\n- Simplified graphs (removed extra toggles, hidden line chart)\n- Export CSV/PDF added\n- Hive Joiners \"This Week/Month\" bug fixed\n\n## Hive-Authentication Package\n\n- Custom bottom toolbar UI and light mode removed\n- Exported VideoFeed & Wallet components for reuse\n\n---\n# Team Blocktrades (@blocktrades)\n\n* New API calls for hivesense (AI-based semantic search)\n* Deployed the latest versions of the Hive API stack to api.syncad.com\n* Added pgbouncer to the stack\n* Added nfttracker app to stack\n* Added hafsql to the stack as an option\n* Added swagger docs for Hive JSON API\n* Added denser UI to stack as an option (e.g. https://api.syncad.com/blog)\n* Added block explorer UI to stack (e.g. https://api.syncad.com/explorer)\n* Preparing to tag a release candidate for the stack in the next day or two\n\n---\n# Team Actifit (@mcfarhat / @actifit)\n\n## Block Explorer, BT and HC:\n- New search criteria based on ID in the proposals page\n- Linking all proposal transactions to the relevant proposal page(id)\n- Improve VESTS/HP switching setting, including on-the-fly change\n- Fix for the last active value in the user profile\n- Implementing optimization for the balance history page\n- Fix proposal fee transaction wording\n- Improvements to single post page display\n- Working on new Richlist page\n- BE UI latest version deployed on testexplore.openhive.network\n- Sanity checks on all Swagger API calls are still in progress\n- API data for savings withdrawals is almost ready\n- Implement improvements for the get_account_balances endpoint relying on precalculated balances\n\n## Actifit:\n- New searchable workout exercises(under works)\n- New editable workouts (under works)\n- Optimized AI workout generation + fixing related issues \n- Remove wallet page appended text\n- Update several packages on the Actifit web\n\n---\n\n## Beneficiaries\n\nTeams are invited to opt in to sharing the post rewards by providing their Hive account information. Two teams opted in.\n\n- @sagarkothari88\n- @techcoderx\n\n---\n\n\n## What is Swarm of Swarms?\n\nThis is a new series of blogs where we will share updates from the Hive development community. The content consists of meeting notes from a virtual developer meeting, titled 'Swarm of Swarms,' which adheres to the Bee Hive theme. We have been doing this for around 30 weeks, without posting the content on-chain or elsewhere. As we broadcast more widely, I hope everyone can gain greater visibility into all the Hive project development.\n\nThe Swarm of Swarms is a virtual gathering where blockchain developers building on the Hive network converge to share project updates, insights, and knowledge. This decentralized meet-up brings together a collective of innovators and visionaries from the Hive ecosystem, specifically those developing applications and use cases on the blockchain. As participants join the Swarm, they are exposed to ideas, solutions, and experiences, allowing them to expand their professional networks and gain a deeper understanding of the rapidly evolving Hive ecosystem. Through this virtual convergence, the Swarm of Swarms aims to cultivate a culture of open communication, mutual support, and collective growth among its members.\n\nI send weekly reminders to the participating development teams, encouraging them to share their progress in the Mattermost 'Swarm of Swarms' channel. Other developers can visit this channel to learn about the projects other teams are working on. The hope is that open communication will inspire more side conversations and collaborations. I appreciate the development team leaders who take a few minutes each week to share their latest achievements. There is room for more participation, and the coffee is free.\n\n---\n\nPlease let me know how I can improve it, and forgive any mistakes. We will iterate!\n",
84
+ title: 'Swarm of Swarms #53 - Hive Development Updates for Week of September 15th',
85
+ author: 'hivetoday',
86
+ permlink: 'swarm-of-swarms-53',
87
+ json_metadata:
88
+ '{"app":"peakd/2025.9.2","format":"markdown","description":"The latest updates from the Hive development community, featuring progress on new projects and initiatives.","tags":["swarmofswarms","development","hive"],"users":["ura-soul","ureka.social","techcoderx","aioha","sagarkothari88","threespeak","blocktrades","mcfarhat","actifit"],"image":["https://files.peakd.com/file/peakd-hive/hivetoday/23tRtDT6aA76uLofgm6esw7paCg95LwmhXfqBykzaoopU8sN3yJqLRj4qR4LmHUtQHgwV.png"]}',
89
+ parent_author: '',
90
+ parent_permlink: 'hive-139531'
91
+ }
92
+ },
93
+ {
94
+ type: 'comment_options_operation',
95
+ value: {
96
+ author: 'hivetoday',
97
+ permlink: 'swarm-of-swarms-53',
98
+ extensions: [
99
+ {
100
+ type: 'comment_payout_beneficiaries',
101
+ value: {
102
+ beneficiaries: [
103
+ {
104
+ weight: 4500,
105
+ account: 'sagarkothari88'
106
+ },
107
+ {
108
+ weight: 4500,
109
+ account: 'techcoderx'
110
+ }
111
+ ]
112
+ }
113
+ }
114
+ ],
115
+ allow_votes: true,
116
+ percent_hbd: 10000,
117
+ max_accepted_payout: {
118
+ nai: '@@000000013',
119
+ amount: '1000000000',
120
+ precision: 3
121
+ },
122
+ allow_curation_rewards: true
123
+ }
124
+ }
125
+ ],
126
+ signatures: [
127
+ '1f3d02406ebbb2c9af99f26ed6c95c0edc599444029233918650181893a6f107c27820212c966f5164fddb4874dc5097d4c52215c8d11ba943bbf161c2e7703701'
128
+ ],
129
+ ref_block_num: 38020,
130
+ ref_block_prefix: 2999500557
131
+ }
132
+
133
+ // 85db372428a47aba8aeb154df8650a900c612fa5
134
+ const recurrent_transfer = {
135
+ expiration: '2025-11-20T07:59:08',
136
+ extensions: [],
137
+ operations: [
138
+ {
139
+ type: 'recurrent_transfer_operation',
140
+ value: {
141
+ to: 'techcoderx.vsc',
142
+ from: 'techcoderx',
143
+ memo: '',
144
+ amount: {
145
+ nai: '@@000000021',
146
+ amount: '2',
147
+ precision: 3
148
+ },
149
+ executions: 5,
150
+ extensions: [
151
+ {
152
+ type: 'recurrent_transfer_pair_id',
153
+ value: {
154
+ pair_id: 1
155
+ }
156
+ }
157
+ ],
158
+ recurrence: 48
159
+ }
160
+ }
161
+ ],
162
+ signatures: [
163
+ '1f3f2ddfc755936e0b998c78a1aec35a9663d1d9011cd4a83be84c6340f1b8689826fbd0e32c918afca38ab1e6ec44eac85a0e281c39bf1400f5e53c8b810a3bf5'
164
+ ],
165
+ ref_block_num: 23679,
166
+ ref_block_prefix: 291568045,
167
+ transactionSize: '125 bytes'
168
+ }
169
+
170
+ describe('transactionDigest', () => {
171
+ it('should correctly compute digest for claim_reward_balance_operation', async () => {
172
+ const result = await transactionDigest(claim, MAINNET_CHAIN_ID, sha256)
173
+ expect(result.txId).toBe('d992be1237dad6a9643d1d1b0d09cca42cee83f9')
174
+ })
175
+
176
+ it('should correctly compute digest for update_proposal_operation', async () => {
177
+ const result = await transactionDigest(updateProposal, MAINNET_CHAIN_ID, sha256)
178
+ expect(result.txId).toBe('4d01373a67a4911acc2a39d6fac47421e760ec47')
179
+ })
180
+
181
+ it('should correctly compute digest for comment_operation', async () => {
182
+ const result = await transactionDigest(comment, MAINNET_CHAIN_ID, sha256)
183
+ expect(result.txId).toBe('c4661343cde8e79872f1ba1d2708d6cbe0643c83')
184
+ })
185
+
186
+ it('should correctly compute digest for recurrent_transfer_operation', async () => {
187
+ const result = await transactionDigest(recurrent_transfer, MAINNET_CHAIN_ID, sha256)
188
+ expect(result.txId).toBe('85db372428a47aba8aeb154df8650a900c612fa5')
189
+ expect(uint8ArrayToHex(result.digest)).toBe('766af9c77a5ae87644370a384b93a5b2763b50837b656d22f19a90118e10526f')
190
+ expect(uint8ArrayToHex(result.bin)).toBe(
191
+ 'beeab0de000000000000000000000000000000000000000000000000000000007f5cadf960114cca1e6901310a74656368636f646572780e74656368636f646572782e76736302000000000000002320bcbe003000050001010100'
192
+ )
193
+ })
194
+ })