openclaw-overlay-plugin 0.8.14 → 0.8.16

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 (190) hide show
  1. package/dist/index.js +6705 -326
  2. package/dist/index.js.map +7 -0
  3. package/dist/src/cli.js +7498 -11
  4. package/dist/src/cli.js.map +7 -0
  5. package/index.ts +1 -1
  6. package/openclaw.plugin.json +1 -1
  7. package/package.json +8 -8
  8. package/src/scripts/messaging/handlers.ts +1 -1
  9. package/src/scripts/overlay/advertisement.ts +1 -1
  10. package/src/scripts/overlay/registration.ts +1 -1
  11. package/src/scripts/overlay/services.ts +1 -1
  12. package/src/scripts/overlay/transaction.ts +1 -1
  13. package/src/scripts/payment/build.ts +1 -1
  14. package/src/scripts/payment/commands.ts +1 -1
  15. package/src/scripts/wallet/balance.ts +1 -1
  16. package/src/scripts/wallet/setup.ts +1 -1
  17. package/src/test/identity-consistency.test.ts +1 -1
  18. package/src/test/wallet.test.ts +1 -2
  19. package/dist/index.d.ts +0 -9
  20. package/dist/src/cli-main.d.ts +0 -7
  21. package/dist/src/cli-main.js +0 -202
  22. package/dist/src/cli.d.ts +0 -8
  23. package/dist/src/compatibility.test.d.ts +0 -4
  24. package/dist/src/compatibility.test.js +0 -41
  25. package/dist/src/core/config.d.ts +0 -11
  26. package/dist/src/core/config.js +0 -15
  27. package/dist/src/core/index.d.ts +0 -25
  28. package/dist/src/core/index.js +0 -26
  29. package/dist/src/core/payment.d.ts +0 -16
  30. package/dist/src/core/payment.js +0 -94
  31. package/dist/src/core/types.d.ts +0 -94
  32. package/dist/src/core/types.js +0 -4
  33. package/dist/src/core/verify.d.ts +0 -28
  34. package/dist/src/core/verify.js +0 -104
  35. package/dist/src/core/wallet.d.ts +0 -105
  36. package/dist/src/core/wallet.js +0 -256
  37. package/dist/src/scripts/baemail/commands.d.ts +0 -35
  38. package/dist/src/scripts/baemail/commands.js +0 -282
  39. package/dist/src/scripts/baemail/handler.d.ts +0 -36
  40. package/dist/src/scripts/baemail/handler.js +0 -284
  41. package/dist/src/scripts/baemail/index.d.ts +0 -5
  42. package/dist/src/scripts/baemail/index.js +0 -5
  43. package/dist/src/scripts/config.d.ts +0 -52
  44. package/dist/src/scripts/config.js +0 -75
  45. package/dist/src/scripts/index.d.ts +0 -7
  46. package/dist/src/scripts/index.js +0 -7
  47. package/dist/src/scripts/messaging/connect.d.ts +0 -8
  48. package/dist/src/scripts/messaging/connect.js +0 -168
  49. package/dist/src/scripts/messaging/handlers.d.ts +0 -21
  50. package/dist/src/scripts/messaging/handlers.js +0 -334
  51. package/dist/src/scripts/messaging/inbox.d.ts +0 -11
  52. package/dist/src/scripts/messaging/inbox.js +0 -51
  53. package/dist/src/scripts/messaging/index.d.ts +0 -8
  54. package/dist/src/scripts/messaging/index.js +0 -8
  55. package/dist/src/scripts/messaging/poll.d.ts +0 -7
  56. package/dist/src/scripts/messaging/poll.js +0 -52
  57. package/dist/src/scripts/messaging/send.d.ts +0 -7
  58. package/dist/src/scripts/messaging/send.js +0 -43
  59. package/dist/src/scripts/output.d.ts +0 -13
  60. package/dist/src/scripts/output.js +0 -28
  61. package/dist/src/scripts/overlay/advertisement.d.ts +0 -16
  62. package/dist/src/scripts/overlay/advertisement.js +0 -122
  63. package/dist/src/scripts/overlay/discover.d.ts +0 -7
  64. package/dist/src/scripts/overlay/discover.js +0 -74
  65. package/dist/src/scripts/overlay/index.d.ts +0 -7
  66. package/dist/src/scripts/overlay/index.js +0 -7
  67. package/dist/src/scripts/overlay/registration.d.ts +0 -19
  68. package/dist/src/scripts/overlay/registration.js +0 -176
  69. package/dist/src/scripts/overlay/services.d.ts +0 -29
  70. package/dist/src/scripts/overlay/services.js +0 -167
  71. package/dist/src/scripts/overlay/transaction.d.ts +0 -42
  72. package/dist/src/scripts/overlay/transaction.js +0 -103
  73. package/dist/src/scripts/payment/build.d.ts +0 -24
  74. package/dist/src/scripts/payment/build.js +0 -54
  75. package/dist/src/scripts/payment/commands.d.ts +0 -15
  76. package/dist/src/scripts/payment/commands.js +0 -73
  77. package/dist/src/scripts/payment/index.d.ts +0 -6
  78. package/dist/src/scripts/payment/index.js +0 -6
  79. package/dist/src/scripts/payment/types.d.ts +0 -56
  80. package/dist/src/scripts/payment/types.js +0 -4
  81. package/dist/src/scripts/services/index.d.ts +0 -6
  82. package/dist/src/scripts/services/index.js +0 -6
  83. package/dist/src/scripts/services/queue.d.ts +0 -11
  84. package/dist/src/scripts/services/queue.js +0 -28
  85. package/dist/src/scripts/services/request.d.ts +0 -7
  86. package/dist/src/scripts/services/request.js +0 -82
  87. package/dist/src/scripts/services/respond.d.ts +0 -11
  88. package/dist/src/scripts/services/respond.js +0 -132
  89. package/dist/src/scripts/types.d.ts +0 -107
  90. package/dist/src/scripts/types.js +0 -4
  91. package/dist/src/scripts/utils/index.d.ts +0 -6
  92. package/dist/src/scripts/utils/index.js +0 -6
  93. package/dist/src/scripts/utils/merkle.d.ts +0 -12
  94. package/dist/src/scripts/utils/merkle.js +0 -47
  95. package/dist/src/scripts/utils/storage.d.ts +0 -66
  96. package/dist/src/scripts/utils/storage.js +0 -211
  97. package/dist/src/scripts/utils/woc.d.ts +0 -26
  98. package/dist/src/scripts/utils/woc.js +0 -91
  99. package/dist/src/scripts/wallet/balance.d.ts +0 -22
  100. package/dist/src/scripts/wallet/balance.js +0 -240
  101. package/dist/src/scripts/wallet/identity.d.ts +0 -71
  102. package/dist/src/scripts/wallet/identity.js +0 -152
  103. package/dist/src/scripts/wallet/index.d.ts +0 -6
  104. package/dist/src/scripts/wallet/index.js +0 -6
  105. package/dist/src/scripts/wallet/setup.d.ts +0 -19
  106. package/dist/src/scripts/wallet/setup.js +0 -119
  107. package/dist/src/scripts/x-verification/commands.d.ts +0 -27
  108. package/dist/src/scripts/x-verification/commands.js +0 -222
  109. package/dist/src/scripts/x-verification/index.d.ts +0 -4
  110. package/dist/src/scripts/x-verification/index.js +0 -4
  111. package/dist/src/services/built-in/api-proxy/index.d.ts +0 -6
  112. package/dist/src/services/built-in/api-proxy/index.js +0 -23
  113. package/dist/src/services/built-in/code-develop/index.d.ts +0 -6
  114. package/dist/src/services/built-in/code-develop/index.js +0 -23
  115. package/dist/src/services/built-in/code-review/index.d.ts +0 -10
  116. package/dist/src/services/built-in/code-review/index.js +0 -51
  117. package/dist/src/services/built-in/image-analysis/index.d.ts +0 -6
  118. package/dist/src/services/built-in/image-analysis/index.js +0 -33
  119. package/dist/src/services/built-in/memory-store/index.d.ts +0 -6
  120. package/dist/src/services/built-in/memory-store/index.js +0 -22
  121. package/dist/src/services/built-in/roulette/index.d.ts +0 -6
  122. package/dist/src/services/built-in/roulette/index.js +0 -27
  123. package/dist/src/services/built-in/summarize/index.d.ts +0 -6
  124. package/dist/src/services/built-in/summarize/index.js +0 -21
  125. package/dist/src/services/built-in/tell-joke/handler.d.ts +0 -7
  126. package/dist/src/services/built-in/tell-joke/handler.js +0 -122
  127. package/dist/src/services/built-in/tell-joke/index.d.ts +0 -9
  128. package/dist/src/services/built-in/tell-joke/index.js +0 -31
  129. package/dist/src/services/built-in/translate/index.d.ts +0 -6
  130. package/dist/src/services/built-in/translate/index.js +0 -21
  131. package/dist/src/services/built-in/web-research/index.d.ts +0 -9
  132. package/dist/src/services/built-in/web-research/index.js +0 -51
  133. package/dist/src/services/index.d.ts +0 -13
  134. package/dist/src/services/index.js +0 -14
  135. package/dist/src/services/loader.d.ts +0 -77
  136. package/dist/src/services/loader.js +0 -292
  137. package/dist/src/services/manager.d.ts +0 -86
  138. package/dist/src/services/manager.js +0 -255
  139. package/dist/src/services/registry.d.ts +0 -98
  140. package/dist/src/services/registry.js +0 -204
  141. package/dist/src/services/types.d.ts +0 -230
  142. package/dist/src/services/types.js +0 -30
  143. package/dist/src/test/cli.test.d.ts +0 -7
  144. package/dist/src/test/cli.test.js +0 -330
  145. package/dist/src/test/comprehensive-overlay.test.d.ts +0 -13
  146. package/dist/src/test/comprehensive-overlay.test.js +0 -593
  147. package/dist/src/test/identity-consistency.test.d.ts +0 -6
  148. package/dist/src/test/identity-consistency.test.js +0 -60
  149. package/dist/src/test/key-derivation.test.d.ts +0 -12
  150. package/dist/src/test/key-derivation.test.js +0 -86
  151. package/dist/src/test/network-address.test.d.ts +0 -9
  152. package/dist/src/test/network-address.test.js +0 -37
  153. package/dist/src/test/overlay-submit.test.d.ts +0 -10
  154. package/dist/src/test/overlay-submit.test.js +0 -460
  155. package/dist/src/test/request-response-flow.test.d.ts +0 -5
  156. package/dist/src/test/request-response-flow.test.js +0 -210
  157. package/dist/src/test/service-system.test.d.ts +0 -5
  158. package/dist/src/test/service-system.test.js +0 -190
  159. package/dist/src/test/taskflow.test.d.ts +0 -7
  160. package/dist/src/test/taskflow.test.js +0 -82
  161. package/dist/src/test/utils/server-logic.d.ts +0 -98
  162. package/dist/src/test/utils/server-logic.js +0 -286
  163. package/dist/src/test/wallet.test.d.ts +0 -7
  164. package/dist/src/test/wallet.test.js +0 -146
  165. package/src/core/README.md +0 -246
  166. package/src/core/config.d.ts +0 -12
  167. package/src/core/config.d.ts.map +0 -1
  168. package/src/core/config.js +0 -14
  169. package/src/core/config.js.map +0 -1
  170. package/src/core/config.ts +0 -22
  171. package/src/core/index.ts +0 -42
  172. package/src/core/payment.d.ts +0 -17
  173. package/src/core/payment.d.ts.map +0 -1
  174. package/src/core/payment.js +0 -95
  175. package/src/core/payment.js.map +0 -1
  176. package/src/core/payment.ts +0 -111
  177. package/src/core/types.d.ts +0 -95
  178. package/src/core/types.d.ts.map +0 -1
  179. package/src/core/types.js +0 -5
  180. package/src/core/types.js.map +0 -1
  181. package/src/core/types.ts +0 -102
  182. package/src/core/verify.d.ts +0 -29
  183. package/src/core/verify.d.ts.map +0 -1
  184. package/src/core/verify.js +0 -105
  185. package/src/core/verify.js.map +0 -1
  186. package/src/core/verify.ts +0 -119
  187. package/src/core/wallet.d.ts +0 -100
  188. package/src/core/wallet.d.ts.map +0 -1
  189. package/src/core/wallet.js.map +0 -1
  190. package/src/core/wallet.ts +0 -323
@@ -1,86 +0,0 @@
1
- /**
2
- * Unit tests for key derivation consistency.
3
- *
4
- * CRITICAL: These tests ensure that transaction signing uses the correct
5
- * child private key that matches the derived address.
6
- *
7
- * Bug history: Initially, code was deriving a child address using BRC-29
8
- * but signing with the root private key, causing OP_EQUALVERIFY failures.
9
- *
10
- * Run: node dist/test/key-derivation.test.js
11
- */
12
- import { PrivateKey, Transaction, P2PKH, CachedKeyDeriver, Utils } from '@bsv/sdk';
13
- import { brc29ProtocolID } from '@bsv/wallet-toolbox';
14
- async function assert(condition, message) {
15
- if (!condition) {
16
- throw new Error(`Assertion failed: ${message}`);
17
- }
18
- }
19
- async function runTests() {
20
- console.log('🧪 Running Key Derivation Tests...\n');
21
- // Test setup
22
- const rootPrivKey = PrivateKey.fromRandom();
23
- const keyDeriver = new CachedKeyDeriver(rootPrivKey);
24
- const derivationPrefix = Utils.toBase64(Array.from(Utils.toArray('import', 'utf8')));
25
- const derivationSuffix = Utils.toBase64(Array.from(Utils.toArray('now', 'utf8')));
26
- const keyString = `${derivationPrefix} ${derivationSuffix}`;
27
- const childPrivKey = keyDeriver.derivePrivateKey(brc29ProtocolID, keyString, 'self');
28
- const pubKey = keyDeriver.derivePublicKey(brc29ProtocolID, keyString, 'self', true);
29
- const derivedAddress = pubKey.toAddress();
30
- const hashResult = pubKey.toHash();
31
- const derivedHash160 = typeof hashResult === 'string'
32
- ? new Uint8Array(hashResult.match(/.{2}/g).map(h => parseInt(h, 16)))
33
- : new Uint8Array(hashResult);
34
- // Test 1: Consistency
35
- console.log('✓ Test 1: Derived keys are consistent');
36
- const keyDeriver2 = new CachedKeyDeriver(rootPrivKey);
37
- const childPrivKey2 = keyDeriver2.derivePrivateKey(brc29ProtocolID, keyString, 'self');
38
- await assert(childPrivKey.toHex() === childPrivKey2.toHex(), 'Child keys should be identical');
39
- // Test 2: Child key matches derived address
40
- console.log('✓ Test 2: Child private key matches derived address');
41
- const childPubKey = childPrivKey.toPublicKey();
42
- const childAddress = childPubKey.toAddress();
43
- await assert(childAddress === derivedAddress, 'Child key address should match derived address');
44
- // Test 3: Root key does NOT match (critical!)
45
- console.log('✓ Test 3: CRITICAL - Root key does NOT match derived address');
46
- const rootAddress = rootPrivKey.toPublicKey().toAddress();
47
- await assert(rootAddress !== derivedAddress, 'Root address must differ from derived address');
48
- // Test 4: Transaction with child key succeeds
49
- console.log('✓ Test 4: CRITICAL - Transaction signed with child key validates');
50
- const fundingTx = new Transaction();
51
- fundingTx.addOutput({
52
- lockingScript: new P2PKH().lock(Array.from(derivedHash160)),
53
- satoshis: 1000,
54
- });
55
- const spendingTx = new Transaction();
56
- spendingTx.addInput({
57
- sourceTransaction: fundingTx,
58
- sourceOutputIndex: 0,
59
- unlockingScriptTemplate: new P2PKH().unlock(childPrivKey),
60
- });
61
- spendingTx.addOutput({
62
- lockingScript: new P2PKH().lock(Array.from(derivedHash160)),
63
- satoshis: 900,
64
- });
65
- await spendingTx.sign();
66
- const inputScript = spendingTx.inputs[0].unlockingScript;
67
- await assert(!!inputScript, 'Unlocking script should be present');
68
- await assert(Array.from(inputScript.toBinary()).length > 0, 'Script should have content');
69
- // Test 5: Different paths produce different addresses
70
- console.log('✓ Test 5: Different derivation paths produce different addresses');
71
- const path1 = Utils.toBase64(Array.from(Utils.toArray('import', 'utf8'))) + ' ' + Utils.toBase64(Array.from(Utils.toArray('now', 'utf8')));
72
- const path2 = Utils.toBase64(Array.from(Utils.toArray('import', 'utf8'))) + ' ' + Utils.toBase64(Array.from(Utils.toArray('later', 'utf8')));
73
- const pubKey1 = keyDeriver.derivePublicKey(brc29ProtocolID, path1, 'self', true);
74
- const pubKey2 = keyDeriver.derivePublicKey(brc29ProtocolID, path2, 'self', true);
75
- await assert(pubKey1.toAddress() !== pubKey2.toAddress(), 'Different paths should produce different addresses');
76
- console.log('\n✅ All tests passed!\n');
77
- console.log('Key derivation is working correctly:');
78
- console.log(` Root address: ${rootAddress}`);
79
- console.log(` Derived address: ${derivedAddress}`);
80
- console.log(` Child key works: YES`);
81
- console.log(` Root key works: NO (correctly rejected)\n`);
82
- }
83
- runTests().catch((err) => {
84
- console.error('\n❌ Tests failed:', err.message);
85
- process.exit(1);
86
- });
@@ -1,9 +0,0 @@
1
- /**
2
- * Unit tests for network-specific address generation.
3
- *
4
- * These tests verify that address generation correctly uses the specified
5
- * network prefix (mainnet vs testnet).
6
- *
7
- * Run: npx tsx src/test/network-address.test.ts
8
- */
9
- export {};
@@ -1,37 +0,0 @@
1
- /**
2
- * Unit tests for network-specific address generation.
3
- *
4
- * These tests verify that address generation correctly uses the specified
5
- * network prefix (mainnet vs testnet).
6
- *
7
- * Run: npx tsx src/test/network-address.test.ts
8
- */
9
- import { PrivateKey } from '@bsv/sdk';
10
- import { deriveWalletAddress } from '../scripts/wallet/identity.js';
11
- async function assert(condition, message) {
12
- if (!condition) {
13
- throw new Error(`Assertion failed: ${message}`);
14
- }
15
- }
16
- async function runTests() {
17
- console.log('🧪 Running Network Address Generation Tests...\n');
18
- const privKey = PrivateKey.fromRandom();
19
- // Test 1: Mainnet Address Generation
20
- console.log('✓ Test 1: Mainnet address starts with 1');
21
- const mainnet = await deriveWalletAddress(privKey, 'mainnet');
22
- console.log(` Mainnet: ${mainnet.address}`);
23
- await assert(mainnet.address.startsWith('1'), 'Mainnet address should start with 1');
24
- // Test 2: Testnet Address Generation
25
- console.log('✓ Test 2: Testnet address starts with m or n');
26
- const testnet = await deriveWalletAddress(privKey, 'testnet');
27
- console.log(` Testnet: ${testnet.address}`);
28
- await assert(testnet.address.startsWith('m') || testnet.address.startsWith('n'), 'Testnet address should start with m or n');
29
- // Test 3: Addresses are different
30
- console.log('✓ Test 3: Mainnet and testnet addresses for same key are different');
31
- await assert(mainnet.address !== testnet.address, 'Addresses should be different across networks');
32
- console.log('\n✅ All network address tests passed!\n');
33
- }
34
- runTests().catch((err) => {
35
- console.error('\n❌ Tests failed:', err.message);
36
- process.exit(1);
37
- });
@@ -1,10 +0,0 @@
1
- /**
2
- * Unit tests for overlay /submit endpoint compatibility.
3
- *
4
- * These tests validate that the client constructs BEEF and payloads
5
- * in the exact format expected by the openclaw-overlay server's
6
- * topic managers using PushDrop tokens.
7
- *
8
- * Run with: npx tsx src/test/overlay-submit.test.ts
9
- */
10
- export {};
@@ -1,460 +0,0 @@
1
- /**
2
- * Unit tests for overlay /submit endpoint compatibility.
3
- *
4
- * These tests validate that the client constructs BEEF and payloads
5
- * in the exact format expected by the openclaw-overlay server's
6
- * topic managers using PushDrop tokens.
7
- *
8
- * Run with: npx tsx src/test/overlay-submit.test.ts
9
- */
10
- import { Beef, Transaction, PrivateKey, P2PKH, LockingScript, OP, PushDrop } from '@bsv/sdk';
11
- const PROTOCOL_ID = 'openclaw-overlay-v1';
12
- /**
13
- * Extract data fields from a PushDrop script using the SDK's decode method.
14
- */
15
- function extractPushDropFields(script) {
16
- try {
17
- const decoded = PushDrop.decode(script);
18
- return decoded.fields;
19
- }
20
- catch {
21
- return null;
22
- }
23
- }
24
- /**
25
- * Parse identity output using PushDrop decode and server's validation logic.
26
- */
27
- function parseIdentityOutput(script) {
28
- const fields = extractPushDropFields(script);
29
- if (!fields || fields.length < 1)
30
- return null;
31
- try {
32
- const payload = JSON.parse(new TextDecoder().decode(new Uint8Array(fields[0])));
33
- // Server validation rules
34
- if (payload.protocol !== PROTOCOL_ID)
35
- return null;
36
- if (payload.type !== 'identity')
37
- return null;
38
- if (typeof payload.identityKey !== 'string' || !/^[0-9a-fA-F]{66}$/.test(payload.identityKey))
39
- return null;
40
- if (typeof payload.name !== 'string' || payload.name.length === 0)
41
- return null;
42
- if (!Array.isArray(payload.capabilities))
43
- return null;
44
- if (typeof payload.timestamp !== 'string')
45
- return null;
46
- return payload;
47
- }
48
- catch {
49
- return null;
50
- }
51
- }
52
- /**
53
- * Parse service output using PushDrop decode and server's validation logic.
54
- */
55
- function parseServiceOutput(script) {
56
- const fields = extractPushDropFields(script);
57
- if (!fields || fields.length < 1)
58
- return null;
59
- try {
60
- const payload = JSON.parse(new TextDecoder().decode(new Uint8Array(fields[0])));
61
- // Server validation rules
62
- if (payload.protocol !== PROTOCOL_ID)
63
- return null;
64
- if (payload.type !== 'service')
65
- return null;
66
- if (typeof payload.identityKey !== 'string' || !/^[0-9a-fA-F]{66}$/.test(payload.identityKey))
67
- return null;
68
- if (typeof payload.serviceId !== 'string' || payload.serviceId.length === 0)
69
- return null;
70
- if (typeof payload.name !== 'string' || payload.name.length === 0)
71
- return null;
72
- if (!payload.pricing || typeof payload.pricing.amountSats !== 'number')
73
- return null;
74
- if (typeof payload.timestamp !== 'string')
75
- return null;
76
- return payload;
77
- }
78
- catch {
79
- return null;
80
- }
81
- }
82
- /**
83
- * Create a minimally encoded push chunk for script building.
84
- */
85
- function createPushChunk(data) {
86
- if (data.length === 0) {
87
- return { op: 0 };
88
- }
89
- if (data.length === 1 && data[0] === 0) {
90
- return { op: 0 };
91
- }
92
- if (data.length === 1 && data[0] > 0 && data[0] <= 16) {
93
- return { op: 0x50 + data[0] };
94
- }
95
- if (data.length <= 75) {
96
- return { op: data.length, data };
97
- }
98
- if (data.length <= 255) {
99
- return { op: 0x4c, data };
100
- }
101
- if (data.length <= 65535) {
102
- return { op: 0x4d, data };
103
- }
104
- return { op: 0x4e, data };
105
- }
106
- /**
107
- * Build a PushDrop-style locking script with JSON payload.
108
- * Format: <pubkey> OP_CHECKSIG <jsonBytes> OP_DROP
109
- */
110
- function buildPushDropScript(privKey, payload) {
111
- const pubKey = privKey.toPublicKey();
112
- const pubKeyBytes = pubKey.toDER();
113
- const jsonBytes = Array.from(new TextEncoder().encode(JSON.stringify(payload)));
114
- const chunks = [];
115
- // P2PK lock: <pubkey> OP_CHECKSIG
116
- chunks.push({ op: pubKeyBytes.length, data: pubKeyBytes });
117
- chunks.push({ op: OP.OP_CHECKSIG });
118
- // Data field: <jsonBytes>
119
- chunks.push(createPushChunk(jsonBytes));
120
- // OP_DROP to clean stack
121
- chunks.push({ op: OP.OP_DROP });
122
- return new LockingScript(chunks);
123
- }
124
- /**
125
- * Simulate the server's identifyAdmissibleOutputs logic.
126
- */
127
- function identifyAdmissibleOutputs(beef, type) {
128
- // Parse BEEF and get the newest (subject) transaction
129
- const parsedBeef = Beef.fromBinary(beef);
130
- const subjectTx = parsedBeef.txs[0]._tx;
131
- if (!subjectTx) {
132
- return { outputsToAdmit: [], coinsToRetain: [] };
133
- }
134
- const outputsToAdmit = [];
135
- for (let i = 0; i < subjectTx.outputs.length; i++) {
136
- const output = subjectTx.outputs[i];
137
- if (output.lockingScript) {
138
- const parsed = type === 'identity'
139
- ? parseIdentityOutput(output.lockingScript)
140
- : parseServiceOutput(output.lockingScript);
141
- if (parsed !== null) {
142
- outputsToAdmit.push(i);
143
- }
144
- }
145
- }
146
- return { outputsToAdmit, coinsToRetain: [] };
147
- }
148
- // ============================================================================
149
- // Test utilities
150
- // ============================================================================
151
- let testsPassed = 0;
152
- let testsFailed = 0;
153
- function assert(condition, message) {
154
- if (!condition) {
155
- console.error(`❌ FAIL: ${message}`);
156
- testsFailed++;
157
- throw new Error(message);
158
- }
159
- console.log(`✅ PASS: ${message}`);
160
- testsPassed++;
161
- }
162
- function assertThrows(fn, message) {
163
- try {
164
- fn();
165
- console.error(`❌ FAIL: ${message} (expected to throw)`);
166
- testsFailed++;
167
- }
168
- catch {
169
- console.log(`✅ PASS: ${message}`);
170
- testsPassed++;
171
- }
172
- }
173
- // ============================================================================
174
- // Test: BEEF format validation
175
- // ============================================================================
176
- async function testBeefFormat() {
177
- console.log('\n=== Test: BEEF Format Validation ===');
178
- // Create a minimal transaction chain
179
- const privKey = PrivateKey.fromRandom();
180
- const pubKeyHash = privKey.toPublicKey().toHash();
181
- // Source transaction (simulating a mined tx with merkle proof)
182
- const sourceTx = new Transaction();
183
- sourceTx.addOutput({
184
- lockingScript: new P2PKH().lock(pubKeyHash),
185
- satoshis: 10000,
186
- });
187
- // Spending transaction with PushDrop output
188
- const tx = new Transaction();
189
- tx.addInput({
190
- sourceTransaction: sourceTx,
191
- sourceOutputIndex: 0,
192
- unlockingScriptTemplate: new P2PKH().unlock(privKey),
193
- });
194
- tx.addOutput({
195
- lockingScript: buildPushDropScript(privKey, { protocol: PROTOCOL_ID, type: 'identity', test: true }),
196
- satoshis: 1,
197
- });
198
- await tx.sign();
199
- // Build BEEF
200
- const beef = new Beef();
201
- beef.mergeTransaction(tx);
202
- const binary = beef.toBinary();
203
- // Validate BEEF magic bytes
204
- const magic = binary.slice(0, 4);
205
- const magicHex = magic.map(b => b.toString(16).padStart(2, '0')).join('');
206
- assert(magicHex === '0100beef' || magicHex === '0200beef', `BEEF magic bytes should be 0100beef or 0200beef, got ${magicHex}`);
207
- // Validate BEEF can be parsed
208
- const parsed = Beef.fromBinary(binary);
209
- assert(parsed.txs.length >= 1, `BEEF should contain at least 1 transaction, got ${parsed.txs.length}`);
210
- // Validate the newest transaction can be found in BEEF
211
- const beefTx = parsed.txs[0];
212
- const newestTxid = beefTx.txid || beefTx._tx?.id('hex');
213
- assert(newestTxid === tx.id('hex'), `Newest transaction in BEEF should match original, got ${newestTxid?.slice(0, 16)}`);
214
- }
215
- // ============================================================================
216
- // Test: Identity payload validation
217
- // ============================================================================
218
- async function testIdentityPayload() {
219
- console.log('\n=== Test: Identity Payload Validation ===');
220
- const privKey = PrivateKey.fromRandom();
221
- const identityKey = privKey.toPublicKey().toString();
222
- // Valid identity payload
223
- const validPayload = {
224
- protocol: PROTOCOL_ID,
225
- type: 'identity',
226
- identityKey,
227
- name: 'test-agent',
228
- description: 'A test agent',
229
- channels: { overlay: 'https://example.com' },
230
- capabilities: ['test'],
231
- timestamp: new Date().toISOString(),
232
- };
233
- const script = buildPushDropScript(privKey, validPayload);
234
- const parsed = parseIdentityOutput(script);
235
- assert(parsed !== null, 'Valid identity payload should be parsed');
236
- assert(parsed.identityKey === identityKey, 'Identity key should match');
237
- assert(parsed.name === 'test-agent', 'Name should match');
238
- assert(parsed.type === 'identity', 'Type should be identity');
239
- // Invalid: wrong protocol
240
- const wrongProtocol = { ...validPayload, protocol: 'wrong-protocol' };
241
- const script2 = buildPushDropScript(privKey, wrongProtocol);
242
- assert(parseIdentityOutput(script2) === null, 'Wrong protocol should be rejected');
243
- // Invalid: wrong type
244
- const wrongType = { ...validPayload, type: 'service' };
245
- const script3 = buildPushDropScript(privKey, wrongType);
246
- assert(parseIdentityOutput(script3) === null, 'Wrong type should be rejected');
247
- // Invalid: bad identity key
248
- const badKey = { ...validPayload, identityKey: 'not-a-valid-key' };
249
- const script4 = buildPushDropScript(privKey, badKey);
250
- assert(parseIdentityOutput(script4) === null, 'Invalid identity key should be rejected');
251
- // Invalid: empty name
252
- const emptyName = { ...validPayload, name: '' };
253
- const script5 = buildPushDropScript(privKey, emptyName);
254
- assert(parseIdentityOutput(script5) === null, 'Empty name should be rejected');
255
- // Invalid: capabilities not array
256
- const badCaps = { ...validPayload, capabilities: 'not-array' };
257
- const script6 = buildPushDropScript(privKey, badCaps);
258
- assert(parseIdentityOutput(script6) === null, 'Non-array capabilities should be rejected');
259
- }
260
- // ============================================================================
261
- // Test: Service payload validation
262
- // ============================================================================
263
- async function testServicePayload() {
264
- console.log('\n=== Test: Service Payload Validation ===');
265
- const privKey = PrivateKey.fromRandom();
266
- const identityKey = privKey.toPublicKey().toString();
267
- // Valid service payload
268
- const validPayload = {
269
- protocol: PROTOCOL_ID,
270
- type: 'service',
271
- identityKey,
272
- serviceId: 'test-service',
273
- name: 'Test Service',
274
- description: 'A test service',
275
- pricing: { model: 'per-task', amountSats: 100 },
276
- timestamp: new Date().toISOString(),
277
- };
278
- const script = buildPushDropScript(privKey, validPayload);
279
- const parsed = parseServiceOutput(script);
280
- assert(parsed !== null, 'Valid service payload should be parsed');
281
- assert(parsed.serviceId === 'test-service', 'Service ID should match');
282
- assert(parsed.pricing.amountSats === 100, 'Price should match');
283
- // Invalid: missing pricing
284
- const noPricing = { ...validPayload, pricing: undefined };
285
- const script2 = buildPushDropScript(privKey, noPricing);
286
- assert(parseServiceOutput(script2) === null, 'Missing pricing should be rejected');
287
- // Invalid: empty serviceId
288
- const emptyId = { ...validPayload, serviceId: '' };
289
- const script3 = buildPushDropScript(privKey, emptyId);
290
- assert(parseServiceOutput(script3) === null, 'Empty serviceId should be rejected');
291
- }
292
- // ============================================================================
293
- // Test: Full BEEF submission simulation
294
- // ============================================================================
295
- async function testBeefSubmission() {
296
- console.log('\n=== Test: BEEF Submission Simulation ===');
297
- const privKey = PrivateKey.fromRandom();
298
- const pubKeyHash = privKey.toPublicKey().toHash();
299
- const identityKey = privKey.toPublicKey().toString();
300
- // Create source transaction (simulating confirmed tx)
301
- const sourceTx = new Transaction();
302
- sourceTx.addOutput({
303
- lockingScript: new P2PKH().lock(pubKeyHash),
304
- satoshis: 10000,
305
- });
306
- // Valid identity registration
307
- const identityPayload = {
308
- protocol: PROTOCOL_ID,
309
- type: 'identity',
310
- identityKey,
311
- name: 'test-agent',
312
- description: 'Test agent for unit tests',
313
- channels: { overlay: 'https://clawoverlay.com' },
314
- capabilities: ['testing'],
315
- timestamp: new Date().toISOString(),
316
- };
317
- const tx = new Transaction();
318
- tx.addInput({
319
- sourceTransaction: sourceTx,
320
- sourceOutputIndex: 0,
321
- unlockingScriptTemplate: new P2PKH().unlock(privKey),
322
- });
323
- tx.addOutput({
324
- lockingScript: buildPushDropScript(privKey, identityPayload),
325
- satoshis: 1,
326
- });
327
- tx.addOutput({
328
- lockingScript: new P2PKH().lock(pubKeyHash),
329
- satoshis: 9900,
330
- });
331
- await tx.sign();
332
- // Build BEEF with ancestry
333
- const beef = new Beef();
334
- beef.mergeTransaction(tx);
335
- const beefBinary = beef.toBinary();
336
- // Simulate server's topic manager
337
- const result = identifyAdmissibleOutputs(beefBinary, 'identity');
338
- assert(result.outputsToAdmit.length === 1, `Should admit 1 output, got ${result.outputsToAdmit.length}`);
339
- assert(result.outputsToAdmit[0] === 0, 'Should admit output index 0 (PushDrop)');
340
- }
341
- // ============================================================================
342
- // Test: Chained transactions (stored BEEF)
343
- // ============================================================================
344
- async function testChainedBeef() {
345
- console.log('\n=== Test: Chained BEEF (multiple unconfirmed txs) ===');
346
- const privKey = PrivateKey.fromRandom();
347
- const pubKeyHash = privKey.toPublicKey().toHash();
348
- const identityKey = privKey.toPublicKey().toString();
349
- // Grandparent tx (simulating mined tx - would have merkle proof)
350
- const grandparentTx = new Transaction();
351
- grandparentTx.addOutput({
352
- lockingScript: new P2PKH().lock(pubKeyHash),
353
- satoshis: 100000,
354
- });
355
- // Parent tx (first overlay submission - unconfirmed)
356
- const parentTx = new Transaction();
357
- parentTx.addInput({
358
- sourceTransaction: grandparentTx,
359
- sourceOutputIndex: 0,
360
- unlockingScriptTemplate: new P2PKH().unlock(privKey),
361
- });
362
- parentTx.addOutput({
363
- lockingScript: buildPushDropScript(privKey, {
364
- protocol: PROTOCOL_ID,
365
- type: 'identity',
366
- identityKey,
367
- name: 'parent-tx',
368
- description: 'First registration',
369
- channels: {},
370
- capabilities: [],
371
- timestamp: new Date().toISOString(),
372
- }),
373
- satoshis: 1,
374
- });
375
- parentTx.addOutput({
376
- lockingScript: new P2PKH().lock(pubKeyHash),
377
- satoshis: 99900,
378
- });
379
- await parentTx.sign();
380
- // Child tx (second overlay submission - spending parent's change)
381
- const childTx = new Transaction();
382
- childTx.addInput({
383
- sourceTransaction: parentTx,
384
- sourceOutputIndex: 1, // Spend the change output
385
- unlockingScriptTemplate: new P2PKH().unlock(privKey),
386
- });
387
- childTx.addOutput({
388
- lockingScript: buildPushDropScript(privKey, {
389
- protocol: PROTOCOL_ID,
390
- type: 'service',
391
- identityKey,
392
- serviceId: 'test-svc',
393
- name: 'Test Service',
394
- description: 'Service from child tx',
395
- pricing: { model: 'per-task', amountSats: 50 },
396
- timestamp: new Date().toISOString(),
397
- }),
398
- satoshis: 1,
399
- });
400
- childTx.addOutput({
401
- lockingScript: new P2PKH().lock(pubKeyHash),
402
- satoshis: 99800,
403
- });
404
- await childTx.sign();
405
- // Build BEEF - should include full chain
406
- const beef = new Beef();
407
- beef.mergeTransaction(childTx);
408
- const beefBinary = beef.toBinary();
409
- // Verify BEEF contains all transactions
410
- const parsedBeef = Beef.fromBinary(beefBinary);
411
- assert(parsedBeef.txs.length >= 2, `BEEF should contain at least 2 txs for chain, got ${parsedBeef.txs.length}`);
412
- // Verify child tx is the newest in BEEF
413
- const beefTx = parsedBeef.txs[0];
414
- const newestTxid = beefTx.txid || beefTx._tx?.id('hex');
415
- assert(newestTxid === childTx.id('hex'), 'Newest tx in BEEF should be the child transaction');
416
- // Simulate server validation
417
- const result = identifyAdmissibleOutputs(beefBinary, 'service');
418
- assert(result.outputsToAdmit.length === 1, 'Should admit the service output');
419
- }
420
- // ============================================================================
421
- // Test: Invalid BEEF handling
422
- // ============================================================================
423
- async function testInvalidBeef() {
424
- console.log('\n=== Test: Invalid BEEF Handling ===');
425
- // Empty BEEF
426
- const emptyBeef = new Beef();
427
- const emptyBinary = emptyBeef.toBinary();
428
- assertThrows(() => Transaction.fromBEEF(emptyBinary), 'Empty BEEF should throw when extracting transaction');
429
- // Malformed BEEF (random bytes)
430
- const garbage = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
431
- assertThrows(() => Beef.fromBinary(Array.from(garbage)), 'Garbage bytes should throw when parsing BEEF');
432
- // BEEF with wrong magic
433
- const wrongMagic = new Uint8Array([0xDE, 0xAD, 0xBE, 0xEF, 0, 0]);
434
- assertThrows(() => Beef.fromBinary(Array.from(wrongMagic)), 'Wrong magic bytes should throw when parsing BEEF');
435
- }
436
- // ============================================================================
437
- // Main test runner
438
- // ============================================================================
439
- async function runTests() {
440
- console.log('Starting overlay submit tests (PushDrop format)...\n');
441
- try {
442
- await testBeefFormat();
443
- await testIdentityPayload();
444
- await testServicePayload();
445
- await testBeefSubmission();
446
- await testChainedBeef();
447
- await testInvalidBeef();
448
- console.log(`\n========================================`);
449
- console.log(`Tests completed: ${testsPassed} passed, ${testsFailed} failed`);
450
- console.log(`========================================`);
451
- if (testsFailed > 0) {
452
- process.exit(1);
453
- }
454
- }
455
- catch (e) {
456
- console.error('\nTest suite failed:', e);
457
- process.exit(1);
458
- }
459
- }
460
- runTests();
@@ -1,5 +0,0 @@
1
- /**
2
- * Tests for request/response flow and duplicate prevention.
3
- */
4
- declare function run(): Promise<void>;
5
- export { run };