@bsv/sdk 1.10.4 → 2.0.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.
Files changed (156) hide show
  1. package/dist/cjs/mod.js +1 -0
  2. package/dist/cjs/mod.js.map +1 -1
  3. package/dist/cjs/package.json +2 -3
  4. package/dist/cjs/src/auth/Peer.js +18 -20
  5. package/dist/cjs/src/auth/Peer.js.map +1 -1
  6. package/dist/cjs/src/identity/IdentityClient.js +20 -124
  7. package/dist/cjs/src/identity/IdentityClient.js.map +1 -1
  8. package/dist/cjs/src/primitives/TransactionSignature.js +115 -10
  9. package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
  10. package/dist/cjs/src/primitives/utils.js +13 -112
  11. package/dist/cjs/src/primitives/utils.js.map +1 -1
  12. package/dist/cjs/src/remittance/CommsLayer.js +3 -0
  13. package/dist/cjs/src/remittance/CommsLayer.js.map +1 -0
  14. package/dist/cjs/src/remittance/IdentityLayer.js +3 -0
  15. package/dist/cjs/src/remittance/IdentityLayer.js.map +1 -0
  16. package/dist/cjs/src/remittance/RemittanceManager.js +1245 -0
  17. package/dist/cjs/src/remittance/RemittanceManager.js.map +1 -0
  18. package/dist/cjs/src/remittance/RemittanceModule.js +3 -0
  19. package/dist/cjs/src/remittance/RemittanceModule.js.map +1 -0
  20. package/dist/cjs/src/remittance/index.js +23 -0
  21. package/dist/cjs/src/remittance/index.js.map +1 -0
  22. package/dist/cjs/src/remittance/modules/BasicBRC29.js +225 -0
  23. package/dist/cjs/src/remittance/modules/BasicBRC29.js.map +1 -0
  24. package/dist/cjs/src/remittance/modules/index.js +18 -0
  25. package/dist/cjs/src/remittance/modules/index.js.map +1 -0
  26. package/dist/cjs/src/remittance/types.js +22 -0
  27. package/dist/cjs/src/remittance/types.js.map +1 -0
  28. package/dist/cjs/src/script/OP.js +15 -13
  29. package/dist/cjs/src/script/OP.js.map +1 -1
  30. package/dist/cjs/src/script/Script.js +4 -1
  31. package/dist/cjs/src/script/Script.js.map +1 -1
  32. package/dist/cjs/src/script/Spend.js +128 -46
  33. package/dist/cjs/src/script/Spend.js.map +1 -1
  34. package/dist/cjs/src/transaction/BeefTx.js +2 -2
  35. package/dist/cjs/src/transaction/Transaction.js +160 -0
  36. package/dist/cjs/src/transaction/Transaction.js.map +1 -1
  37. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  38. package/dist/esm/mod.js +1 -0
  39. package/dist/esm/mod.js.map +1 -1
  40. package/dist/esm/src/auth/Peer.js +18 -20
  41. package/dist/esm/src/auth/Peer.js.map +1 -1
  42. package/dist/esm/src/identity/IdentityClient.js +20 -124
  43. package/dist/esm/src/identity/IdentityClient.js.map +1 -1
  44. package/dist/esm/src/primitives/TransactionSignature.js +115 -10
  45. package/dist/esm/src/primitives/TransactionSignature.js.map +1 -1
  46. package/dist/esm/src/primitives/utils.js +13 -112
  47. package/dist/esm/src/primitives/utils.js.map +1 -1
  48. package/dist/esm/src/remittance/CommsLayer.js +2 -0
  49. package/dist/esm/src/remittance/CommsLayer.js.map +1 -0
  50. package/dist/esm/src/remittance/IdentityLayer.js +2 -0
  51. package/dist/esm/src/remittance/IdentityLayer.js.map +1 -0
  52. package/dist/esm/src/remittance/RemittanceManager.js +1254 -0
  53. package/dist/esm/src/remittance/RemittanceManager.js.map +1 -0
  54. package/dist/esm/src/remittance/RemittanceModule.js +2 -0
  55. package/dist/esm/src/remittance/RemittanceModule.js.map +1 -0
  56. package/dist/esm/src/remittance/index.js +7 -0
  57. package/dist/esm/src/remittance/index.js.map +1 -0
  58. package/dist/esm/src/remittance/modules/BasicBRC29.js +227 -0
  59. package/dist/esm/src/remittance/modules/BasicBRC29.js.map +1 -0
  60. package/dist/esm/src/remittance/modules/index.js +2 -0
  61. package/dist/esm/src/remittance/modules/index.js.map +1 -0
  62. package/dist/esm/src/remittance/types.js +19 -0
  63. package/dist/esm/src/remittance/types.js.map +1 -0
  64. package/dist/esm/src/script/OP.js +15 -13
  65. package/dist/esm/src/script/OP.js.map +1 -1
  66. package/dist/esm/src/script/Script.js +4 -1
  67. package/dist/esm/src/script/Script.js.map +1 -1
  68. package/dist/esm/src/script/Spend.js +129 -46
  69. package/dist/esm/src/script/Spend.js.map +1 -1
  70. package/dist/esm/src/transaction/BeefTx.js +3 -3
  71. package/dist/esm/src/transaction/BeefTx.js.map +1 -1
  72. package/dist/esm/src/transaction/Transaction.js +160 -0
  73. package/dist/esm/src/transaction/Transaction.js.map +1 -1
  74. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  75. package/dist/types/mod.d.ts +1 -0
  76. package/dist/types/mod.d.ts.map +1 -1
  77. package/dist/types/src/auth/Peer.d.ts +3 -7
  78. package/dist/types/src/auth/Peer.d.ts.map +1 -1
  79. package/dist/types/src/identity/IdentityClient.d.ts +0 -8
  80. package/dist/types/src/identity/IdentityClient.d.ts.map +1 -1
  81. package/dist/types/src/primitives/TransactionSignature.d.ts +16 -4
  82. package/dist/types/src/primitives/TransactionSignature.d.ts.map +1 -1
  83. package/dist/types/src/primitives/utils.d.ts +1 -0
  84. package/dist/types/src/primitives/utils.d.ts.map +1 -1
  85. package/dist/types/src/remittance/CommsLayer.d.ts +50 -0
  86. package/dist/types/src/remittance/CommsLayer.d.ts.map +1 -0
  87. package/dist/types/src/remittance/IdentityLayer.d.ts +35 -0
  88. package/dist/types/src/remittance/IdentityLayer.d.ts.map +1 -0
  89. package/dist/types/src/remittance/RemittanceManager.d.ts +452 -0
  90. package/dist/types/src/remittance/RemittanceManager.d.ts.map +1 -0
  91. package/dist/types/src/remittance/RemittanceModule.d.ts +106 -0
  92. package/dist/types/src/remittance/RemittanceModule.d.ts.map +1 -0
  93. package/dist/types/src/remittance/index.d.ts +7 -0
  94. package/dist/types/src/remittance/index.d.ts.map +1 -0
  95. package/dist/types/src/remittance/modules/BasicBRC29.d.ts +133 -0
  96. package/dist/types/src/remittance/modules/BasicBRC29.d.ts.map +1 -0
  97. package/dist/types/src/remittance/modules/index.d.ts +2 -0
  98. package/dist/types/src/remittance/modules/index.d.ts.map +1 -0
  99. package/dist/types/src/remittance/types.d.ts +238 -0
  100. package/dist/types/src/remittance/types.d.ts.map +1 -0
  101. package/dist/types/src/script/OP.d.ts +5 -3
  102. package/dist/types/src/script/OP.d.ts.map +1 -1
  103. package/dist/types/src/script/Script.d.ts.map +1 -1
  104. package/dist/types/src/script/Spend.d.ts +7 -0
  105. package/dist/types/src/script/Spend.d.ts.map +1 -1
  106. package/dist/types/src/transaction/BeefTx.d.ts +2 -2
  107. package/dist/types/src/transaction/Transaction.d.ts +14 -0
  108. package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
  109. package/dist/types/src/wallet/Wallet.interfaces.d.ts +5 -5
  110. package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -1
  111. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  112. package/dist/umd/bundle.js +13 -13
  113. package/dist/umd/bundle.js.map +1 -1
  114. package/docs/index.md +2 -14
  115. package/docs/reference/auth.md +6 -12
  116. package/docs/reference/primitives.md +20 -78
  117. package/docs/reference/remittance.md +2166 -0
  118. package/docs/reference/script.md +11 -3
  119. package/docs/reference/transaction.md +27 -1
  120. package/docs/reference/wallet.md +6 -5
  121. package/docs/remittance-getting-started.md +138 -0
  122. package/mod.ts +1 -0
  123. package/package.json +12 -3
  124. package/src/auth/Peer.ts +18 -29
  125. package/src/auth/__tests/Peer.test.ts +253 -1
  126. package/src/identity/IdentityClient.ts +29 -153
  127. package/src/identity/__tests/IdentityClient.test.ts +1 -289
  128. package/src/overlay-tools/__tests/SHIPBroadcaster.test.ts +7 -9
  129. package/src/primitives/TransactionSignature.ts +129 -10
  130. package/src/primitives/__tests/utils.test.ts +30 -7
  131. package/src/primitives/utils.ts +13 -129
  132. package/src/remittance/CommsLayer.ts +41 -0
  133. package/src/remittance/IdentityLayer.ts +32 -0
  134. package/src/remittance/RemittanceManager.ts +1672 -0
  135. package/src/remittance/RemittanceModule.ts +92 -0
  136. package/src/remittance/__tests/BasicBRC29.test.ts +188 -0
  137. package/src/remittance/__tests/RemittanceManager.test.ts +493 -0
  138. package/src/remittance/__tests/examples.ts +130 -0
  139. package/src/remittance/index.ts +6 -0
  140. package/src/remittance/modules/BasicBRC29.ts +361 -0
  141. package/src/remittance/modules/index.ts +1 -0
  142. package/src/remittance/types.ts +284 -0
  143. package/src/script/OP.ts +15 -13
  144. package/src/script/Script.ts +3 -1
  145. package/src/script/Spend.ts +128 -52
  146. package/src/script/__tests/Chronicle.test.ts +186 -0
  147. package/src/script/__tests/Spend.test.ts +1 -1
  148. package/src/script/__tests/SpendValildVectors.test.ts +63 -0
  149. package/src/script/__tests/lrshiftnum.test.ts +185 -0
  150. package/src/script/__tests/sighashTestData.ts +1031 -0
  151. package/src/script/__tests/spend.valid.vectors.ts +9 -16
  152. package/src/transaction/BeefTx.ts +3 -3
  153. package/src/transaction/Transaction.ts +186 -0
  154. package/src/transaction/__tests/Beef.test.ts +2 -0
  155. package/src/transaction/__tests/Transaction.test.ts +641 -3
  156. package/src/wallet/Wallet.interfaces.ts +5 -5
@@ -0,0 +1,92 @@
1
+ import { PubKeyHex } from '../wallet/index.js'
2
+ import { Invoice, ModuleContext, RemittanceOptionId, ThreadId, Termination, Settlement } from './types.js'
3
+
4
+ /**
5
+ * A remittance module implements a specific settlement system.
6
+ *
7
+ * The RemittanceManager core uses module ids as the only “capability mechanism”:
8
+ * if an invoice contains an option with module id X, a payer can only satisfy it
9
+ * if they are configured with module X.
10
+ */
11
+ export interface RemittanceModule<
12
+ TOptionTerms = unknown,
13
+ TSettlementArtifact = unknown,
14
+ TReceiptData = unknown
15
+ > {
16
+ /** Unique id used as the invoice.options key and as settlement.moduleId. */
17
+ id: RemittanceOptionId
18
+ /** Human-readable name for UIs. */
19
+ name: string
20
+
21
+ /**
22
+ * Whether this module allows unsolicited settlements (i.e. settlement without an invoice).
23
+ *
24
+ * If true, the payer can build a settlement without an invoice being provided by the payee.
25
+ * In this case, the option terms provided to `buildSettlement` may be used in lieu of an invoice.
26
+ *
27
+ * If false, an invoice must always be provided to `buildSettlement`.
28
+ */
29
+ allowUnsolicitedSettlements: boolean
30
+
31
+ /**
32
+ * Creates module-defined option terms that will be embedded into the invoice.
33
+ *
34
+ * In UTXO-ish offers, these option terms may include a partially-signed transaction template.
35
+ *
36
+ * Optional because some modules may not require any option data, or may only support unsolicited settlements.
37
+ *
38
+ * However, a module MAY still create option terms/invoices even if it can sometimes support unsolicited settlements.
39
+ */
40
+ createOption?: (args: { threadId: ThreadId, invoice: Invoice }, ctx: ModuleContext) => Promise<TOptionTerms>
41
+
42
+ /**
43
+ * Builds the settlement artifact for a chosen option.
44
+ *
45
+ * For UTXO settlement systems, this is usually a transaction (or partially-signed tx) to be broadcast.
46
+ *
47
+ * For unsolicited settlements, an invoice may not always be provided and the option terms may be used in lieu of an invoice to settle against.
48
+ *
49
+ * For example, the option terms may include a tx template with outputs to fulfill the settlement.
50
+ *
51
+ * When `allowUnsolicitedSettlements` is false, an invoice will always be provided.
52
+ *
53
+ * Termination can be returned to abort the protocol with a reason.
54
+ */
55
+ buildSettlement: (
56
+ args: { threadId: ThreadId, invoice?: Invoice, option: TOptionTerms, note?: string },
57
+ ctx: ModuleContext
58
+ ) => Promise<{ action: 'settle', artifact: TSettlementArtifact } | { action: 'terminate', termination: Termination }>
59
+
60
+ /**
61
+ * Accepts a settlement artifact on the payee side.
62
+ *
63
+ * The module should validate and internalize/store whatever it needs.
64
+ * The manager will wrap the returned value as receipt.receiptData.
65
+ *
66
+ * If the settlement is invalid, the module should return either a termination or receiptData (possibly with a refund or indicating the failure), depending how the module chooses to handle it.
67
+ */
68
+ acceptSettlement: (
69
+ args: { threadId: ThreadId, invoice?: Invoice, settlement: TSettlementArtifact, sender: PubKeyHex },
70
+ ctx: ModuleContext
71
+ ) => Promise<{ action: 'accept', receiptData?: TReceiptData } | { action: 'terminate', termination: Termination }>
72
+
73
+ /**
74
+ * Processes a receipt on the payer side.
75
+ *
76
+ * This is where a module can automatically internalize a refund, mark a local order fulfilled, receive goods and services, etc.
77
+ */
78
+ processReceipt?: (
79
+ args: { threadId: ThreadId, invoice?: Invoice, receiptData: TReceiptData, sender: PubKeyHex },
80
+ ctx: ModuleContext
81
+ ) => Promise<void>
82
+
83
+ /**
84
+ * Processes a termination on either side.
85
+ *
86
+ * This is where a module can clean up any internal state, reverse provisional actions, take refunds, etc.
87
+ */
88
+ processTermination?: (
89
+ args: { threadId: ThreadId, invoice?: Invoice, settlement?: Settlement, termination: Termination, sender: PubKeyHex },
90
+ ctx: ModuleContext
91
+ ) => Promise<void>
92
+ }
@@ -0,0 +1,188 @@
1
+ import type { ModuleContext } from '../types.js'
2
+ import type { WalletInterface } from '../../wallet/Wallet.interfaces.js'
3
+ import { Brc29RemittanceModule } from '../modules/BasicBRC29.js'
4
+
5
+ const makeContext = (wallet: WalletInterface): ModuleContext => ({
6
+ wallet,
7
+ originator: 'example.com',
8
+ now: () => 123
9
+ })
10
+
11
+ describe('Brc29RemittanceModule', () => {
12
+ // Prevent console.log output during tests
13
+ const consoleErrorSpy = jest.spyOn(console, 'log').mockImplementation(() => { })
14
+
15
+ describe('unsolicited settlements (no invoice)', () => {
16
+ it('builds a settlement artifact for unsolicited payment', async () => {
17
+ const wallet = {
18
+ getPublicKey: jest.fn(async () => ({ publicKey: '02deadbeef' })),
19
+ createAction: jest.fn(async () => ({ tx: [1, 2, 3] }))
20
+ } as unknown as WalletInterface
21
+
22
+ const module = new Brc29RemittanceModule({
23
+ protocolID: [2, 'test-protocol'],
24
+ labels: ['label-1'],
25
+ description: 'Test payment',
26
+ outputDescription: 'Test output',
27
+ nonceProvider: {
28
+ createNonce: jest.fn()
29
+ .mockResolvedValueOnce('prefix')
30
+ .mockResolvedValueOnce('suffix')
31
+ },
32
+ lockingScriptProvider: {
33
+ pubKeyToP2PKHLockingScript: jest.fn(async () => '76a914deadbeef88ac')
34
+ }
35
+ })
36
+
37
+ const option = { amountSatoshis: 1000, payee: 'payee-key' }
38
+ const result = await module.buildSettlement({ threadId: 'thread-1', option, note: 'unsolicited payment' }, makeContext(wallet))
39
+ expect(result.action).toBe('settle')
40
+ if (result.action !== 'settle') return
41
+
42
+ expect(result.artifact.customInstructions).toEqual({ derivationPrefix: 'prefix', derivationSuffix: 'suffix' })
43
+ expect(result.artifact.amountSatoshis).toBe(1000)
44
+ expect(result.artifact.outputIndex).toBe(0)
45
+ expect(result.artifact.transaction).toEqual([1, 2, 3])
46
+
47
+ expect(wallet.getPublicKey).toHaveBeenCalledWith(
48
+ {
49
+ protocolID: [2, 'test-protocol'],
50
+ keyID: 'prefix suffix',
51
+ counterparty: option.payee
52
+ },
53
+ 'example.com'
54
+ )
55
+
56
+ const createArgs = (wallet.createAction as jest.Mock).mock.calls[0][0]
57
+ const customInstructions = JSON.parse(createArgs.outputs[0].customInstructions as string)
58
+ expect(customInstructions).toEqual({
59
+ derivationPrefix: 'prefix',
60
+ derivationSuffix: 'suffix',
61
+ payee: option.payee,
62
+ threadId: 'thread-1',
63
+ note: 'unsolicited payment'
64
+ })
65
+ expect(createArgs.outputs[0].outputDescription).toBe('Test output')
66
+ })
67
+
68
+ it('terminates on invalid amounts for unsolicited settlements', async () => {
69
+ const wallet = {
70
+ getPublicKey: jest.fn(async () => ({ publicKey: '02deadbeef' })),
71
+ createAction: jest.fn(async () => ({ tx: [1, 2, 3] }))
72
+ } as unknown as WalletInterface
73
+
74
+ const module = new Brc29RemittanceModule()
75
+ const option = { amountSatoshis: 0, payee: 'payee-key' }
76
+ const result = await module.buildSettlement({ threadId: 'thread-1', option }, makeContext(wallet))
77
+ expect(result.action).toBe('terminate')
78
+ })
79
+
80
+ it('terminates on invalid option data for unsolicited settlements', async () => {
81
+ const wallet = {
82
+ getPublicKey: jest.fn(async () => ({ publicKey: '02deadbeef' })),
83
+ createAction: jest.fn(async () => ({ tx: [1, 2, 3] }))
84
+ } as unknown as WalletInterface
85
+
86
+ const module = new Brc29RemittanceModule()
87
+ const option = { amountSatoshis: -5, payee: 'payee-key', outputIndex: -1 }
88
+ const result = await module.buildSettlement({ threadId: 'thread-1', option }, makeContext(wallet))
89
+ expect(result.action).toBe('terminate')
90
+ if (result.action === 'terminate') {
91
+ expect(result.termination.code).toBe('brc29.invalid_option')
92
+ }
93
+ })
94
+ })
95
+
96
+ describe('settlement building edge cases', () => {
97
+ it('terminates when wallet fails to create transaction', async () => {
98
+ const wallet = {
99
+ getPublicKey: jest.fn(async () => ({ publicKey: '02deadbeef' })),
100
+ createAction: jest.fn(async () => ({}))
101
+ } as unknown as WalletInterface
102
+
103
+ const module = new Brc29RemittanceModule({
104
+ nonceProvider: {
105
+ createNonce: jest.fn()
106
+ .mockResolvedValueOnce('prefix')
107
+ .mockResolvedValueOnce('suffix')
108
+ },
109
+ lockingScriptProvider: {
110
+ pubKeyToP2PKHLockingScript: jest.fn(async () => '76a914deadbeef88ac')
111
+ }
112
+ })
113
+ const option = { amountSatoshis: 1000, payee: 'payee-key' }
114
+ const result = await module.buildSettlement({ threadId: 'thread-1', option }, makeContext(wallet))
115
+ expect(result.action).toBe('terminate')
116
+ if (result.action === 'terminate') {
117
+ expect(result.termination.code).toBe('brc29.missing_tx')
118
+ }
119
+ })
120
+ })
121
+
122
+ describe('settlement acceptance', () => {
123
+ it('accepts settlements by internalizing the payment', async () => {
124
+ const wallet = {
125
+ internalizeAction: jest.fn(async () => ({ ok: true }))
126
+ } as unknown as WalletInterface
127
+
128
+ const module = new Brc29RemittanceModule()
129
+ const settlement = {
130
+ customInstructions: { derivationPrefix: 'p', derivationSuffix: 's' },
131
+ transaction: [9, 9, 9],
132
+ amountSatoshis: 1000,
133
+ outputIndex: 1
134
+ }
135
+ const result = await module.acceptSettlement(
136
+ { threadId: 'thread-1', settlement, sender: 'payer-key' },
137
+ makeContext(wallet)
138
+ )
139
+ expect(result.action).toBe('accept')
140
+ if (result.action === 'accept') {
141
+ expect(result.receiptData?.internalizeResult).toEqual({ ok: true })
142
+ }
143
+
144
+ expect(wallet.internalizeAction).toHaveBeenCalledWith(
145
+ {
146
+ tx: settlement.transaction,
147
+ outputs: [
148
+ {
149
+ paymentRemittance: {
150
+ derivationPrefix: 'p',
151
+ derivationSuffix: 's',
152
+ senderIdentityKey: 'payer-key'
153
+ },
154
+ outputIndex: 1,
155
+ protocol: 'wallet payment'
156
+ }
157
+ ],
158
+ labels: ['brc29'],
159
+ description: 'BRC-29 payment received'
160
+ },
161
+ 'example.com'
162
+ )
163
+ })
164
+
165
+ it('terminates when internalization fails', async () => {
166
+ const wallet = {
167
+ internalizeAction: jest.fn(async () => {
168
+ throw new Error('fail')
169
+ })
170
+ } as unknown as WalletInterface
171
+
172
+ const module = new Brc29RemittanceModule()
173
+ const settlement = {
174
+ customInstructions: { derivationPrefix: 'p', derivationSuffix: 's' },
175
+ transaction: [9, 9, 9],
176
+ amountSatoshis: 1000
177
+ }
178
+ const result = await module.acceptSettlement(
179
+ { threadId: 'thread-1', settlement, sender: 'payer-key' },
180
+ makeContext(wallet)
181
+ )
182
+ expect(result.action).toBe('terminate')
183
+ if (result.action === 'terminate') {
184
+ expect(result.termination.code).toBe('brc29.internalize_failed')
185
+ }
186
+ })
187
+ })
188
+ })