@antseed/node 0.1.0 → 0.1.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.
Files changed (140) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +7 -5
  3. package/dist/discovery/http-metadata-resolver.d.ts +6 -0
  4. package/dist/discovery/http-metadata-resolver.d.ts.map +1 -1
  5. package/dist/discovery/http-metadata-resolver.js +32 -4
  6. package/dist/discovery/http-metadata-resolver.js.map +1 -1
  7. package/dist/discovery/peer-lookup.d.ts +1 -0
  8. package/dist/discovery/peer-lookup.d.ts.map +1 -1
  9. package/dist/discovery/peer-lookup.js +10 -25
  10. package/dist/discovery/peer-lookup.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/interfaces/seller-provider.d.ts +13 -1
  16. package/dist/interfaces/seller-provider.d.ts.map +1 -1
  17. package/dist/node.d.ts +13 -3
  18. package/dist/node.d.ts.map +1 -1
  19. package/dist/node.js +146 -21
  20. package/dist/node.js.map +1 -1
  21. package/dist/proxy/proxy-mux.d.ts +3 -1
  22. package/dist/proxy/proxy-mux.d.ts.map +1 -1
  23. package/dist/proxy/proxy-mux.js +9 -5
  24. package/dist/proxy/proxy-mux.js.map +1 -1
  25. package/dist/types/http.d.ts +1 -0
  26. package/dist/types/http.d.ts.map +1 -1
  27. package/dist/types/http.js +1 -1
  28. package/dist/types/http.js.map +1 -1
  29. package/package.json +14 -10
  30. package/contracts/AntseedEscrow.sol +0 -310
  31. package/contracts/MockUSDC.sol +0 -64
  32. package/contracts/README.md +0 -102
  33. package/src/config/encryption.test.ts +0 -49
  34. package/src/config/encryption.ts +0 -53
  35. package/src/config/plugin-config-manager.test.ts +0 -92
  36. package/src/config/plugin-config-manager.ts +0 -153
  37. package/src/config/plugin-loader.ts +0 -90
  38. package/src/discovery/announcer.ts +0 -169
  39. package/src/discovery/bootstrap.ts +0 -57
  40. package/src/discovery/default-metadata-resolver.ts +0 -18
  41. package/src/discovery/dht-health.ts +0 -136
  42. package/src/discovery/dht-node.ts +0 -191
  43. package/src/discovery/http-metadata-resolver.ts +0 -47
  44. package/src/discovery/index.ts +0 -15
  45. package/src/discovery/metadata-codec.ts +0 -453
  46. package/src/discovery/metadata-resolver.ts +0 -7
  47. package/src/discovery/metadata-server.ts +0 -73
  48. package/src/discovery/metadata-validator.ts +0 -172
  49. package/src/discovery/peer-lookup.ts +0 -122
  50. package/src/discovery/peer-metadata.ts +0 -34
  51. package/src/discovery/peer-selector.ts +0 -134
  52. package/src/discovery/profile-manager.ts +0 -131
  53. package/src/discovery/profile-search.ts +0 -100
  54. package/src/discovery/reputation-verifier.ts +0 -54
  55. package/src/index.ts +0 -61
  56. package/src/interfaces/buyer-router.ts +0 -21
  57. package/src/interfaces/plugin.ts +0 -36
  58. package/src/interfaces/seller-provider.ts +0 -81
  59. package/src/metering/index.ts +0 -6
  60. package/src/metering/receipt-generator.ts +0 -105
  61. package/src/metering/receipt-verifier.ts +0 -102
  62. package/src/metering/session-tracker.ts +0 -145
  63. package/src/metering/storage.ts +0 -600
  64. package/src/metering/token-counter.ts +0 -127
  65. package/src/metering/usage-aggregator.ts +0 -236
  66. package/src/node.ts +0 -1698
  67. package/src/p2p/connection-auth.ts +0 -152
  68. package/src/p2p/connection-manager.ts +0 -916
  69. package/src/p2p/handshake.ts +0 -162
  70. package/src/p2p/ice-config.ts +0 -59
  71. package/src/p2p/identity.ts +0 -110
  72. package/src/p2p/index.ts +0 -11
  73. package/src/p2p/keepalive.ts +0 -118
  74. package/src/p2p/message-protocol.ts +0 -171
  75. package/src/p2p/nat-traversal.ts +0 -169
  76. package/src/p2p/payment-codec.ts +0 -165
  77. package/src/p2p/payment-mux.ts +0 -153
  78. package/src/p2p/reconnect.ts +0 -117
  79. package/src/payments/balance-manager.ts +0 -77
  80. package/src/payments/buyer-payment-manager.ts +0 -414
  81. package/src/payments/disputes.ts +0 -72
  82. package/src/payments/evm/escrow-client.ts +0 -263
  83. package/src/payments/evm/keypair.ts +0 -31
  84. package/src/payments/evm/signatures.ts +0 -103
  85. package/src/payments/evm/wallet.ts +0 -42
  86. package/src/payments/index.ts +0 -50
  87. package/src/payments/settlement.ts +0 -40
  88. package/src/payments/types.ts +0 -79
  89. package/src/proxy/index.ts +0 -3
  90. package/src/proxy/provider-detection.ts +0 -78
  91. package/src/proxy/proxy-mux.ts +0 -173
  92. package/src/proxy/request-codec.ts +0 -294
  93. package/src/reputation/index.ts +0 -6
  94. package/src/reputation/rating-manager.ts +0 -118
  95. package/src/reputation/report-manager.ts +0 -91
  96. package/src/reputation/trust-engine.ts +0 -120
  97. package/src/reputation/trust-score.ts +0 -74
  98. package/src/reputation/uptime-tracker.ts +0 -155
  99. package/src/routing/default-router.ts +0 -75
  100. package/src/types/bittorrent-dht.d.ts +0 -19
  101. package/src/types/buyer.ts +0 -37
  102. package/src/types/capability.ts +0 -34
  103. package/src/types/connection.ts +0 -29
  104. package/src/types/http.ts +0 -20
  105. package/src/types/index.ts +0 -14
  106. package/src/types/metering.ts +0 -175
  107. package/src/types/nat-api.d.ts +0 -29
  108. package/src/types/peer-profile.ts +0 -25
  109. package/src/types/peer.ts +0 -62
  110. package/src/types/plugin-config.ts +0 -31
  111. package/src/types/protocol.ts +0 -162
  112. package/src/types/provider.ts +0 -40
  113. package/src/types/rating.ts +0 -23
  114. package/src/types/report.ts +0 -30
  115. package/src/types/seller.ts +0 -38
  116. package/src/types/staking.ts +0 -23
  117. package/src/utils/debug.ts +0 -30
  118. package/src/utils/hex.ts +0 -14
  119. package/tests/balance-manager.test.ts +0 -156
  120. package/tests/bootstrap.test.ts +0 -108
  121. package/tests/buyer-payment-manager.test.ts +0 -358
  122. package/tests/connection-auth.test.ts +0 -87
  123. package/tests/default-router.test.ts +0 -148
  124. package/tests/evm-keypair.test.ts +0 -173
  125. package/tests/identity.test.ts +0 -133
  126. package/tests/message-protocol.test.ts +0 -212
  127. package/tests/metadata-codec.test.ts +0 -165
  128. package/tests/metadata-validator.test.ts +0 -261
  129. package/tests/metering-storage.test.ts +0 -244
  130. package/tests/payment-codec.test.ts +0 -95
  131. package/tests/payment-mux.test.ts +0 -191
  132. package/tests/peer-selector.test.ts +0 -184
  133. package/tests/provider-detection.test.ts +0 -107
  134. package/tests/proxy-mux-security.test.ts +0 -38
  135. package/tests/receipt.test.ts +0 -215
  136. package/tests/reputation-integration.test.ts +0 -195
  137. package/tests/request-codec.test.ts +0 -144
  138. package/tests/token-counter.test.ts +0 -122
  139. package/tsconfig.json +0 -9
  140. package/vitest.config.ts +0 -7
@@ -1,310 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.24;
3
-
4
- interface IERC20 {
5
- function transferFrom(address from, address to, uint256 value) external returns (bool);
6
- function transfer(address to, uint256 value) external returns (bool);
7
- }
8
-
9
- /**
10
- * @title AntseedEscrow
11
- * @notice Session-scoped USDC escrow used by Antseed payment channels.
12
- * @dev State mapping matches node/src/payments/crypto/escrow.ts STATE_MAP:
13
- * 0=open, 1=active, 2=disputed, 3=settled, 4=closed.
14
- */
15
- contract AntseedEscrow {
16
- enum ChannelState {
17
- Open,
18
- Active,
19
- Disputed,
20
- Settled,
21
- Closed
22
- }
23
-
24
- struct Channel {
25
- address buyer;
26
- address seller;
27
- uint256 amount;
28
- ChannelState state;
29
- uint64 createdAt;
30
- uint64 disputedAt;
31
- }
32
-
33
- IERC20 public immutable usdc;
34
- address public owner;
35
- address public arbiter;
36
- address public feeCollector;
37
- uint64 public disputeTimeout;
38
-
39
- mapping(bytes32 => Channel) private channels;
40
-
41
- bool private locked;
42
-
43
- event ChannelDeposited(bytes32 indexed sessionId, address indexed buyer, address indexed seller, uint256 amount);
44
- event ChannelReleased(bytes32 indexed sessionId, address indexed seller, uint256 amount, address caller);
45
- event ChannelSettled(
46
- bytes32 indexed sessionId,
47
- address indexed seller,
48
- uint256 sellerAmount,
49
- address indexed feeCollector,
50
- uint256 platformAmount,
51
- address buyer,
52
- uint256 buyerRefund,
53
- address caller
54
- );
55
- event ChannelRefunded(bytes32 indexed sessionId, address indexed buyer, uint256 amount, address caller);
56
- event ChannelDisputed(bytes32 indexed sessionId, address indexed caller);
57
- event ArbiterUpdated(address indexed previousArbiter, address indexed newArbiter);
58
- event FeeCollectorUpdated(address indexed previousFeeCollector, address indexed newFeeCollector);
59
- event DisputeTimeoutUpdated(uint64 previousTimeout, uint64 newTimeout);
60
- event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
61
-
62
- error InvalidAddress();
63
- error InvalidSession();
64
- error InvalidAmount();
65
- error SessionExists();
66
- error InvalidState();
67
- error NotAuthorized();
68
- error NotOwner();
69
- error NotArbiter();
70
- error InvalidSplit();
71
- error DisputeTimeoutNotReached();
72
- error Reentrancy();
73
- error TransferFailed();
74
-
75
- modifier nonReentrant() {
76
- if (locked) revert Reentrancy();
77
- locked = true;
78
- _;
79
- locked = false;
80
- }
81
-
82
- modifier onlyOwner() {
83
- if (msg.sender != owner) revert NotOwner();
84
- _;
85
- }
86
-
87
- constructor(address usdcToken, address initialArbiter) {
88
- if (usdcToken == address(0)) revert InvalidAddress();
89
- usdc = IERC20(usdcToken);
90
- owner = msg.sender;
91
- arbiter = initialArbiter == address(0) ? msg.sender : initialArbiter;
92
- feeCollector = msg.sender;
93
- disputeTimeout = 72 hours;
94
- }
95
-
96
- function setArbiter(address newArbiter) external onlyOwner {
97
- if (newArbiter == address(0)) revert InvalidAddress();
98
- emit ArbiterUpdated(arbiter, newArbiter);
99
- arbiter = newArbiter;
100
- }
101
-
102
- function transferOwnership(address newOwner) external onlyOwner {
103
- if (newOwner == address(0)) revert InvalidAddress();
104
- emit OwnershipTransferred(owner, newOwner);
105
- owner = newOwner;
106
- }
107
-
108
- function setFeeCollector(address newFeeCollector) external onlyOwner {
109
- if (newFeeCollector == address(0)) revert InvalidAddress();
110
- emit FeeCollectorUpdated(feeCollector, newFeeCollector);
111
- feeCollector = newFeeCollector;
112
- }
113
-
114
- function setDisputeTimeout(uint64 newTimeout) external onlyOwner {
115
- if (newTimeout == 0) revert InvalidAmount();
116
- emit DisputeTimeoutUpdated(disputeTimeout, newTimeout);
117
- disputeTimeout = newTimeout;
118
- }
119
-
120
- /**
121
- * @notice Lock buyer funds for a session.
122
- * @param sessionId keccak256(sessionIdString) from ethers.id(sessionId)
123
- * @param seller seller wallet address
124
- * @param amount USDC amount in token base units (6 decimals)
125
- */
126
- function deposit(bytes32 sessionId, address seller, uint256 amount) external nonReentrant {
127
- if (sessionId == bytes32(0)) revert InvalidSession();
128
- if (seller == address(0)) revert InvalidAddress();
129
- if (amount == 0) revert InvalidAmount();
130
-
131
- Channel storage channel = channels[sessionId];
132
- if (channel.buyer != address(0)) revert SessionExists();
133
-
134
- channel.buyer = msg.sender;
135
- channel.seller = seller;
136
- channel.amount = amount;
137
- channel.state = ChannelState.Active;
138
- channel.createdAt = uint64(block.timestamp);
139
- channel.disputedAt = 0;
140
-
141
- _safeTransferFrom(msg.sender, address(this), amount);
142
- emit ChannelDeposited(sessionId, msg.sender, seller, amount);
143
- }
144
-
145
- /**
146
- * @notice Release escrow to seller.
147
- * @dev Active channel: buyer/seller/arbiter can release.
148
- * Disputed channel: only arbiter can release.
149
- */
150
- function release(bytes32 sessionId) external nonReentrant {
151
- Channel storage channel = channels[sessionId];
152
- if (channel.state != ChannelState.Active && channel.state != ChannelState.Disputed) {
153
- revert InvalidState();
154
- }
155
- _authorizeForSettlement(channel);
156
-
157
- uint256 amount = channel.amount;
158
- channel.amount = 0;
159
- channel.state = ChannelState.Settled;
160
- channel.disputedAt = 0;
161
-
162
- _safeTransfer(channel.seller, amount);
163
- emit ChannelReleased(sessionId, channel.seller, amount, msg.sender);
164
- }
165
-
166
- /**
167
- * @notice Settle escrow by splitting funds between seller, platform fee collector, and buyer refund.
168
- * @dev Active channel: buyer/seller/arbiter can settle.
169
- * Disputed channel: only arbiter can settle.
170
- */
171
- function settle(bytes32 sessionId, uint256 sellerAmount, uint256 platformAmount) external nonReentrant {
172
- Channel storage channel = channels[sessionId];
173
- if (channel.state != ChannelState.Active && channel.state != ChannelState.Disputed) {
174
- revert InvalidState();
175
- }
176
- _authorizeForSettlement(channel);
177
-
178
- uint256 amount = channel.amount;
179
- if (sellerAmount > amount || platformAmount > amount - sellerAmount) {
180
- revert InvalidSplit();
181
- }
182
- uint256 buyerRefund = amount - sellerAmount - platformAmount;
183
-
184
- channel.amount = 0;
185
- channel.state = ChannelState.Settled;
186
- channel.disputedAt = 0;
187
-
188
- if (sellerAmount > 0) {
189
- _safeTransfer(channel.seller, sellerAmount);
190
- }
191
- if (platformAmount > 0) {
192
- _safeTransfer(feeCollector, platformAmount);
193
- }
194
- if (buyerRefund > 0) {
195
- _safeTransfer(channel.buyer, buyerRefund);
196
- }
197
-
198
- emit ChannelSettled(
199
- sessionId,
200
- channel.seller,
201
- sellerAmount,
202
- feeCollector,
203
- platformAmount,
204
- channel.buyer,
205
- buyerRefund,
206
- msg.sender
207
- );
208
- }
209
-
210
- /**
211
- * @notice Mark an active channel as disputed.
212
- */
213
- function dispute(bytes32 sessionId) external {
214
- Channel storage channel = channels[sessionId];
215
- if (channel.state != ChannelState.Active) revert InvalidState();
216
- if (msg.sender != channel.buyer && msg.sender != channel.seller && msg.sender != arbiter) {
217
- revert NotAuthorized();
218
- }
219
-
220
- channel.state = ChannelState.Disputed;
221
- channel.disputedAt = uint64(block.timestamp);
222
- emit ChannelDisputed(sessionId, msg.sender);
223
- }
224
-
225
- /**
226
- * @notice Refund escrow to buyer.
227
- * @dev Active channel: buyer/arbiter can refund.
228
- * Disputed channel: only arbiter can refund.
229
- */
230
- function refund(bytes32 sessionId) external nonReentrant {
231
- Channel storage channel = channels[sessionId];
232
- if (channel.state != ChannelState.Active && channel.state != ChannelState.Disputed) {
233
- revert InvalidState();
234
- }
235
-
236
- if (channel.state == ChannelState.Active) {
237
- if (msg.sender != channel.buyer && msg.sender != arbiter) {
238
- revert NotAuthorized();
239
- }
240
- } else if (msg.sender != arbiter) {
241
- revert NotArbiter();
242
- }
243
-
244
- uint256 amount = channel.amount;
245
- channel.amount = 0;
246
- channel.state = ChannelState.Closed;
247
- channel.disputedAt = 0;
248
-
249
- _safeTransfer(channel.buyer, amount);
250
- emit ChannelRefunded(sessionId, channel.buyer, amount, msg.sender);
251
- }
252
-
253
- /**
254
- * @notice Resolve stale disputes by refunding the buyer after the dispute timeout.
255
- */
256
- function resolveDisputeTimeout(bytes32 sessionId) external nonReentrant {
257
- Channel storage channel = channels[sessionId];
258
- if (channel.state != ChannelState.Disputed) revert InvalidState();
259
- if (uint64(block.timestamp) < channel.disputedAt + disputeTimeout) {
260
- revert DisputeTimeoutNotReached();
261
- }
262
-
263
- uint256 amount = channel.amount;
264
- channel.amount = 0;
265
- channel.state = ChannelState.Closed;
266
- channel.disputedAt = 0;
267
-
268
- _safeTransfer(channel.buyer, amount);
269
- emit ChannelRefunded(sessionId, channel.buyer, amount, msg.sender);
270
- }
271
-
272
- function getChannel(bytes32 sessionId)
273
- external
274
- view
275
- returns (address buyer, address seller, uint256 amount, uint8 state)
276
- {
277
- Channel storage channel = channels[sessionId];
278
- return (channel.buyer, channel.seller, channel.amount, uint8(channel.state));
279
- }
280
-
281
- function _safeTransferFrom(address from, address to, uint256 value) private {
282
- (bool ok, bytes memory ret) = address(usdc).call(
283
- abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value)
284
- );
285
- if (!ok || (ret.length > 0 && !abi.decode(ret, (bool)))) {
286
- revert TransferFailed();
287
- }
288
- }
289
-
290
- function _safeTransfer(address to, uint256 value) private {
291
- (bool ok, bytes memory ret) = address(usdc).call(
292
- abi.encodeWithSelector(IERC20.transfer.selector, to, value)
293
- );
294
- if (!ok || (ret.length > 0 && !abi.decode(ret, (bool)))) {
295
- revert TransferFailed();
296
- }
297
- }
298
-
299
- function _authorizeForSettlement(Channel storage channel) private view {
300
- if (channel.state == ChannelState.Active) {
301
- if (msg.sender != channel.buyer && msg.sender != channel.seller && msg.sender != arbiter) {
302
- revert NotAuthorized();
303
- }
304
- return;
305
- }
306
- if (msg.sender != arbiter) {
307
- revert NotArbiter();
308
- }
309
- }
310
- }
@@ -1,64 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.24;
3
-
4
- /**
5
- * @title MockUSDC
6
- * @notice Minimal ERC20 used for local escrow integration tests and examples.
7
- */
8
- contract MockUSDC {
9
- string public constant name = "Mock USD Coin";
10
- string public constant symbol = "USDC";
11
- uint8 public constant decimals = 6;
12
-
13
- uint256 public totalSupply;
14
-
15
- mapping(address => uint256) public balanceOf;
16
- mapping(address => mapping(address => uint256)) public allowance;
17
-
18
- event Transfer(address indexed from, address indexed to, uint256 value);
19
- event Approval(address indexed owner, address indexed spender, uint256 value);
20
-
21
- error InsufficientBalance();
22
- error InsufficientAllowance();
23
- error InvalidAddress();
24
-
25
- function mint(address to, uint256 amount) external {
26
- if (to == address(0)) revert InvalidAddress();
27
- totalSupply += amount;
28
- balanceOf[to] += amount;
29
- emit Transfer(address(0), to, amount);
30
- }
31
-
32
- function approve(address spender, uint256 amount) external returns (bool) {
33
- allowance[msg.sender][spender] = amount;
34
- emit Approval(msg.sender, spender, amount);
35
- return true;
36
- }
37
-
38
- function transfer(address to, uint256 amount) external returns (bool) {
39
- _transfer(msg.sender, to, amount);
40
- return true;
41
- }
42
-
43
- function transferFrom(address from, address to, uint256 amount) external returns (bool) {
44
- uint256 allowed = allowance[from][msg.sender];
45
- if (allowed < amount) revert InsufficientAllowance();
46
-
47
- if (allowed != type(uint256).max) {
48
- allowance[from][msg.sender] = allowed - amount;
49
- emit Approval(from, msg.sender, allowance[from][msg.sender]);
50
- }
51
-
52
- _transfer(from, to, amount);
53
- return true;
54
- }
55
-
56
- function _transfer(address from, address to, uint256 amount) private {
57
- if (to == address(0)) revert InvalidAddress();
58
- if (balanceOf[from] < amount) revert InsufficientBalance();
59
-
60
- balanceOf[from] -= amount;
61
- balanceOf[to] += amount;
62
- emit Transfer(from, to, amount);
63
- }
64
- }
@@ -1,102 +0,0 @@
1
- # Antseed Escrow Contract
2
-
3
- `AntseedEscrow.sol` is the on-chain escrow contract used by the payment channel flow.
4
-
5
- ## Contract Paths
6
-
7
- - `node/contracts/AntseedEscrow.sol` - production escrow contract
8
- - `node/contracts/MockUSDC.sol` - test-only ERC20 used for local integration flows
9
-
10
- ## ABI Compatibility
11
-
12
- The contract exposes the runtime methods expected by `BaseEscrowClient`:
13
-
14
- - `deposit(bytes32 sessionId, address seller, uint256 amount)`
15
- - `release(bytes32 sessionId)`
16
- - `settle(bytes32 sessionId, uint256 sellerAmount, uint256 platformAmount)`
17
- - `dispute(bytes32 sessionId)`
18
- - `refund(bytes32 sessionId)`
19
- - `resolveDisputeTimeout(bytes32 sessionId)`
20
- - `getChannel(bytes32 sessionId) returns (address buyer, address seller, uint256 amount, uint8 state)`
21
-
22
- Owner/admin methods:
23
-
24
- - `setArbiter(address)`
25
- - `setFeeCollector(address)`
26
- - `setDisputeTimeout(uint64 seconds)`
27
-
28
- Deployment uses the constructor signature:
29
-
30
- - `constructor(address usdcToken, address initialArbiter)`
31
-
32
- Channel states are encoded as:
33
-
34
- - `0 = open`
35
- - `1 = active`
36
- - `2 = disputed`
37
- - `3 = settled`
38
- - `4 = closed`
39
-
40
- ## Compile
41
-
42
- Example using Foundry (`forge`):
43
-
44
- ```bash
45
- cd node
46
- forge build --root . --contracts contracts --out contracts/out
47
- ```
48
-
49
- Example using `solc`:
50
-
51
- ```bash
52
- solc --optimize --bin --abi node/contracts/AntseedEscrow.sol -o node/contracts/out
53
- ```
54
-
55
- ## Deploy (TypeScript Helper)
56
-
57
- Deploy the compiled contract using ethers.js or your preferred toolchain. The constructor expects `(address usdcToken, address initialArbiter)`.
58
-
59
- For programmatic deployment, use `BaseEscrowClient` from `@antseed/node`:
60
-
61
- ```ts
62
- import { BaseEscrowClient } from '@antseed/node';
63
-
64
- const client = new BaseEscrowClient({
65
- rpcUrl: process.env.RPC_URL!,
66
- contractAddress: deployedAddress,
67
- usdcAddress: process.env.USDC_ADDRESS!,
68
- });
69
- ```
70
-
71
- ## End-to-End Integration Test
72
-
73
- A full on-chain test lives in:
74
-
75
- - `node/tests/escrow-contract.integration.test.ts`
76
-
77
- It compiles `AntseedEscrow.sol` + `MockUSDC.sol`, starts a local Anvil chain, deploys the contract, and exercises:
78
-
79
- - `deposit -> release`
80
- - `deposit -> dispute -> arbiter refund`
81
- - `deposit -> settle(seller/platform/refund split)`
82
- - `deposit -> dispute -> resolveDisputeTimeout`
83
-
84
- Run only this suite:
85
-
86
- ```bash
87
- cd node
88
- npm test -- escrow-contract.integration.test.ts
89
- ```
90
-
91
- The test auto-skips when `anvil` or `forge` is unavailable.
92
-
93
- ## Operational Notes
94
-
95
- - `deposit` sets `buyer = msg.sender`; it expects an approved USDC `transferFrom`.
96
- - `release` while active can be called by buyer/seller/arbiter.
97
- - `release` while disputed requires arbiter.
98
- - `settle` while active can be called by buyer/seller/arbiter.
99
- - `settle` while disputed requires arbiter and supports explicit seller/platform payouts with automatic buyer refund remainder.
100
- - `refund` while active can be called by buyer/arbiter.
101
- - `refund` while disputed requires arbiter.
102
- - `resolveDisputeTimeout` allows anyone to refund a stale disputed channel after `disputeTimeout`.
@@ -1,49 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { encryptValue, decryptValue, deriveMachineKey, generateSalt } from './encryption.js'
3
-
4
- describe('encryption', () => {
5
- it('should round-trip encrypt and decrypt', () => {
6
- const salt = generateSalt()
7
- const key = deriveMachineKey(salt)
8
- const plaintext = 'sk-ant-api03-secret-key-value'
9
- const encrypted = encryptValue(plaintext, key)
10
- expect(encrypted).not.toBe(plaintext)
11
- const decrypted = decryptValue(encrypted, key)
12
- expect(decrypted).toBe(plaintext)
13
- })
14
-
15
- it('should produce different ciphertexts for same input (random IV)', () => {
16
- const salt = generateSalt()
17
- const key = deriveMachineKey(salt)
18
- const plaintext = 'test-secret'
19
- const a = encryptValue(plaintext, key)
20
- const b = encryptValue(plaintext, key)
21
- expect(a).not.toBe(b)
22
- })
23
-
24
- it('should fail to decrypt with wrong key', () => {
25
- const salt1 = generateSalt()
26
- const salt2 = generateSalt()
27
- const key1 = deriveMachineKey(salt1)
28
- const key2 = deriveMachineKey(salt2)
29
- const encrypted = encryptValue('secret', key1)
30
- expect(() => decryptValue(encrypted, key2)).toThrow()
31
- })
32
-
33
- it('should handle empty string', () => {
34
- const salt = generateSalt()
35
- const key = deriveMachineKey(salt)
36
- const encrypted = encryptValue('', key)
37
- const decrypted = decryptValue(encrypted, key)
38
- expect(decrypted).toBe('')
39
- })
40
-
41
- it('should handle unicode', () => {
42
- const salt = generateSalt()
43
- const key = deriveMachineKey(salt)
44
- const plaintext = 'héllo wörld 🔑'
45
- const encrypted = encryptValue(plaintext, key)
46
- const decrypted = decryptValue(encrypted, key)
47
- expect(decrypted).toBe(plaintext)
48
- })
49
- })
@@ -1,53 +0,0 @@
1
- import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto'
2
- import { hostname, homedir } from 'node:os'
3
-
4
- const ALGORITHM = 'aes-256-gcm'
5
- const SALT_LENGTH = 32
6
- const IV_LENGTH = 16
7
- const TAG_LENGTH = 16
8
- const KEY_LENGTH = 32
9
-
10
- /**
11
- * Derive an encryption key from a machine-specific seed.
12
- */
13
- export function deriveMachineKey(salt: Buffer): Buffer {
14
- const seed = [
15
- process.env['USER'] ?? process.env['USERNAME'] ?? '',
16
- hostname(),
17
- homedir(),
18
- ].join(':')
19
- return scryptSync(seed, salt, KEY_LENGTH)
20
- }
21
-
22
- /**
23
- * Encrypt a string value. Returns base64-encoded ciphertext with IV and auth tag prepended.
24
- */
25
- export function encryptValue(plaintext: string, key: Buffer): string {
26
- const iv = randomBytes(IV_LENGTH)
27
- const cipher = createCipheriv(ALGORITHM, key, iv)
28
- const encrypted = Buffer.concat([cipher.update(plaintext, 'utf-8'), cipher.final()])
29
- const tag = cipher.getAuthTag()
30
- const combined = Buffer.concat([iv, tag, encrypted])
31
- return combined.toString('base64')
32
- }
33
-
34
- /**
35
- * Decrypt a base64-encoded value produced by encryptValue.
36
- */
37
- export function decryptValue(encoded: string, key: Buffer): string {
38
- const combined = Buffer.from(encoded, 'base64')
39
- const iv = combined.subarray(0, IV_LENGTH)
40
- const tag = combined.subarray(IV_LENGTH, IV_LENGTH + TAG_LENGTH)
41
- const ciphertext = combined.subarray(IV_LENGTH + TAG_LENGTH)
42
- const decipher = createDecipheriv(ALGORITHM, key, iv)
43
- decipher.setAuthTag(tag)
44
- const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()])
45
- return decrypted.toString('utf-8')
46
- }
47
-
48
- /**
49
- * Generate a fresh random salt for key derivation.
50
- */
51
- export function generateSalt(): Buffer {
52
- return randomBytes(SALT_LENGTH)
53
- }
@@ -1,92 +0,0 @@
1
- import { describe, it, expect, beforeEach } from 'vitest'
2
- import { mkdtemp, rm } from 'node:fs/promises'
3
- import { tmpdir } from 'node:os'
4
- import { join } from 'node:path'
5
- import { addInstance, removeInstance, getInstance, getInstances, updateInstanceConfig, loadPluginConfig } from './plugin-config-manager.js'
6
- import type { ConfigField } from '../interfaces/plugin.js'
7
-
8
- const schema: ConfigField[] = [
9
- { key: 'API_KEY', label: 'API Key', type: 'secret', required: true },
10
- { key: 'BASE_URL', label: 'Base URL', type: 'string', required: false },
11
- ]
12
-
13
- describe('plugin-config-manager', () => {
14
- let tmpDir: string
15
- let configPath: string
16
-
17
- beforeEach(async () => {
18
- tmpDir = await mkdtemp(join(tmpdir(), 'antseed-test-'))
19
- configPath = join(tmpDir, 'config.json')
20
- })
21
-
22
- it('should add and retrieve an instance', async () => {
23
- await addInstance(configPath, {
24
- id: 'test-provider',
25
- package: '@antseed/provider-test',
26
- type: 'provider',
27
- config: { API_KEY: 'sk-secret-123', BASE_URL: 'https://api.test.com' },
28
- }, schema)
29
-
30
- const instance = await getInstance(configPath, 'test-provider')
31
- expect(instance).not.toBeNull()
32
- expect(instance!.id).toBe('test-provider')
33
- expect(instance!.config['API_KEY']).toBe('sk-secret-123')
34
- expect(instance!.config['BASE_URL']).toBe('https://api.test.com')
35
- })
36
-
37
- it('should encrypt secrets in the file', async () => {
38
- await addInstance(configPath, {
39
- id: 'test',
40
- package: '@antseed/provider-test',
41
- type: 'provider',
42
- config: { API_KEY: 'sk-secret', BASE_URL: 'https://api.test.com' },
43
- }, schema)
44
-
45
- const raw = await loadPluginConfig(configPath)
46
- const stored = raw.instances[0]!.config
47
- // Secret should be encrypted (prefixed with enc:)
48
- expect(typeof stored['API_KEY']).toBe('string')
49
- expect((stored['API_KEY'] as string).startsWith('enc:')).toBe(true)
50
- // Non-secret should be plain
51
- expect(stored['BASE_URL']).toBe('https://api.test.com')
52
- })
53
-
54
- it('should remove an instance', async () => {
55
- await addInstance(configPath, {
56
- id: 'to-remove',
57
- package: '@antseed/provider-test',
58
- type: 'provider',
59
- config: {},
60
- })
61
- await removeInstance(configPath, 'to-remove')
62
- const instance = await getInstance(configPath, 'to-remove')
63
- expect(instance).toBeNull()
64
- })
65
-
66
- it('should list all instances', async () => {
67
- await addInstance(configPath, { id: 'a', package: 'pkg-a', type: 'provider', config: {} })
68
- await addInstance(configPath, { id: 'b', package: 'pkg-b', type: 'router', config: {} })
69
- const all = await getInstances(configPath)
70
- expect(all).toHaveLength(2)
71
- expect(all.map(i => i.id)).toEqual(['a', 'b'])
72
- })
73
-
74
- it('should update instance config', async () => {
75
- await addInstance(configPath, {
76
- id: 'updatable',
77
- package: 'pkg',
78
- type: 'provider',
79
- config: { API_KEY: 'old-key' },
80
- }, schema)
81
-
82
- await updateInstanceConfig(configPath, 'updatable', { API_KEY: 'new-key' }, schema)
83
- const updated = await getInstance(configPath, 'updatable')
84
- expect(updated!.config['API_KEY']).toBe('new-key')
85
- })
86
-
87
- it('should reject duplicate instance IDs', async () => {
88
- await addInstance(configPath, { id: 'dup', package: 'pkg', type: 'provider', config: {} })
89
- await expect(addInstance(configPath, { id: 'dup', package: 'pkg', type: 'provider', config: {} }))
90
- .rejects.toThrow('already exists')
91
- })
92
- })