@agirails/sdk 2.0.1-beta → 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.
Files changed (405) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +116 -108
  3. package/bin/actp +10 -0
  4. package/dist/ACTPClient.d.ts +456 -33
  5. package/dist/ACTPClient.d.ts.map +1 -1
  6. package/dist/ACTPClient.js +477 -93
  7. package/dist/ACTPClient.js.map +1 -1
  8. package/dist/abi/AgentRegistry.json +782 -0
  9. package/dist/abi/EscrowVault.json +106 -38
  10. package/dist/abi/IdentityRegistry.json +316 -0
  11. package/dist/adapters/BaseAdapter.d.ts +231 -0
  12. package/dist/adapters/BaseAdapter.d.ts.map +1 -0
  13. package/dist/adapters/BaseAdapter.js +393 -0
  14. package/dist/adapters/BaseAdapter.js.map +1 -0
  15. package/dist/adapters/BeginnerAdapter.d.ts +152 -0
  16. package/dist/adapters/BeginnerAdapter.d.ts.map +1 -0
  17. package/dist/adapters/BeginnerAdapter.js +168 -0
  18. package/dist/adapters/BeginnerAdapter.js.map +1 -0
  19. package/dist/adapters/IntermediateAdapter.d.ts +211 -0
  20. package/dist/adapters/IntermediateAdapter.d.ts.map +1 -0
  21. package/dist/adapters/IntermediateAdapter.js +260 -0
  22. package/dist/adapters/IntermediateAdapter.js.map +1 -0
  23. package/dist/adapters/index.d.ts +15 -0
  24. package/dist/adapters/index.d.ts.map +1 -0
  25. package/dist/adapters/index.js +26 -0
  26. package/dist/adapters/index.js.map +1 -0
  27. package/dist/builders/DeliveryProofBuilder.d.ts +60 -1
  28. package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
  29. package/dist/builders/DeliveryProofBuilder.js +81 -5
  30. package/dist/builders/DeliveryProofBuilder.js.map +1 -1
  31. package/dist/builders/QuoteBuilder.d.ts +101 -0
  32. package/dist/builders/QuoteBuilder.d.ts.map +1 -1
  33. package/dist/builders/QuoteBuilder.js +120 -3
  34. package/dist/builders/QuoteBuilder.js.map +1 -1
  35. package/dist/builders/index.d.ts +4 -0
  36. package/dist/builders/index.d.ts.map +1 -1
  37. package/dist/builders/index.js +4 -0
  38. package/dist/builders/index.js.map +1 -1
  39. package/dist/cli/commands/balance.d.ts +13 -0
  40. package/dist/cli/commands/balance.d.ts.map +1 -0
  41. package/dist/cli/commands/balance.js +89 -0
  42. package/dist/cli/commands/balance.js.map +1 -0
  43. package/dist/cli/commands/batch.d.ts +24 -0
  44. package/dist/cli/commands/batch.d.ts.map +1 -0
  45. package/dist/cli/commands/batch.js +424 -0
  46. package/dist/cli/commands/batch.js.map +1 -0
  47. package/dist/cli/commands/config.d.ts +13 -0
  48. package/dist/cli/commands/config.d.ts.map +1 -0
  49. package/dist/cli/commands/config.js +192 -0
  50. package/dist/cli/commands/config.js.map +1 -0
  51. package/dist/cli/commands/init.d.ts +19 -0
  52. package/dist/cli/commands/init.d.ts.map +1 -0
  53. package/dist/cli/commands/init.js +143 -0
  54. package/dist/cli/commands/init.js.map +1 -0
  55. package/dist/cli/commands/mint.d.ts +13 -0
  56. package/dist/cli/commands/mint.d.ts.map +1 -0
  57. package/dist/cli/commands/mint.js +91 -0
  58. package/dist/cli/commands/mint.js.map +1 -0
  59. package/dist/cli/commands/pay.d.ts +18 -0
  60. package/dist/cli/commands/pay.d.ts.map +1 -0
  61. package/dist/cli/commands/pay.js +87 -0
  62. package/dist/cli/commands/pay.js.map +1 -0
  63. package/dist/cli/commands/simulate.d.ts +32 -0
  64. package/dist/cli/commands/simulate.d.ts.map +1 -0
  65. package/dist/cli/commands/simulate.js +290 -0
  66. package/dist/cli/commands/simulate.js.map +1 -0
  67. package/dist/cli/commands/time.d.ts +29 -0
  68. package/dist/cli/commands/time.d.ts.map +1 -0
  69. package/dist/cli/commands/time.js +252 -0
  70. package/dist/cli/commands/time.js.map +1 -0
  71. package/dist/cli/commands/tx.d.ts +16 -0
  72. package/dist/cli/commands/tx.d.ts.map +1 -0
  73. package/dist/cli/commands/tx.js +379 -0
  74. package/dist/cli/commands/tx.js.map +1 -0
  75. package/dist/cli/commands/watch.d.ts +20 -0
  76. package/dist/cli/commands/watch.d.ts.map +1 -0
  77. package/dist/cli/commands/watch.js +160 -0
  78. package/dist/cli/commands/watch.js.map +1 -0
  79. package/dist/cli/index.d.ts +17 -0
  80. package/dist/cli/index.d.ts.map +1 -0
  81. package/dist/cli/index.js +104 -0
  82. package/dist/cli/index.js.map +1 -0
  83. package/dist/cli/utils/client.d.ts +70 -0
  84. package/dist/cli/utils/client.d.ts.map +1 -0
  85. package/dist/cli/utils/client.js +240 -0
  86. package/dist/cli/utils/client.js.map +1 -0
  87. package/dist/cli/utils/config.d.ts +91 -0
  88. package/dist/cli/utils/config.d.ts.map +1 -0
  89. package/dist/cli/utils/config.js +240 -0
  90. package/dist/cli/utils/config.js.map +1 -0
  91. package/dist/cli/utils/output.d.ts +174 -0
  92. package/dist/cli/utils/output.d.ts.map +1 -0
  93. package/dist/cli/utils/output.js +380 -0
  94. package/dist/cli/utils/output.js.map +1 -0
  95. package/dist/config/networks.d.ts +28 -0
  96. package/dist/config/networks.d.ts.map +1 -1
  97. package/dist/config/networks.js +60 -12
  98. package/dist/config/networks.js.map +1 -1
  99. package/dist/errors/index.d.ts +165 -2
  100. package/dist/errors/index.d.ts.map +1 -1
  101. package/dist/errors/index.js +260 -2
  102. package/dist/errors/index.js.map +1 -1
  103. package/dist/index.d.ts +61 -13
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +141 -36
  106. package/dist/index.js.map +1 -1
  107. package/dist/level0/Provider.d.ts +106 -0
  108. package/dist/level0/Provider.d.ts.map +1 -0
  109. package/dist/level0/Provider.js +10 -0
  110. package/dist/level0/Provider.js.map +1 -0
  111. package/dist/level0/ServiceDirectory.d.ts +74 -0
  112. package/dist/level0/ServiceDirectory.d.ts.map +1 -0
  113. package/dist/level0/ServiceDirectory.js +122 -0
  114. package/dist/level0/ServiceDirectory.js.map +1 -0
  115. package/dist/level0/index.d.ts +10 -0
  116. package/dist/level0/index.d.ts.map +1 -0
  117. package/dist/level0/index.js +15 -0
  118. package/dist/level0/index.js.map +1 -0
  119. package/dist/level0/provide.d.ts +51 -0
  120. package/dist/level0/provide.d.ts.map +1 -0
  121. package/dist/level0/provide.js +113 -0
  122. package/dist/level0/provide.js.map +1 -0
  123. package/dist/level0/request.d.ts +53 -0
  124. package/dist/level0/request.d.ts.map +1 -0
  125. package/dist/level0/request.js +462 -0
  126. package/dist/level0/request.js.map +1 -0
  127. package/dist/level1/Agent.d.ts +472 -0
  128. package/dist/level1/Agent.d.ts.map +1 -0
  129. package/dist/level1/Agent.js +1091 -0
  130. package/dist/level1/Agent.js.map +1 -0
  131. package/dist/level1/index.d.ts +10 -0
  132. package/dist/level1/index.d.ts.map +1 -0
  133. package/dist/level1/index.js +30 -0
  134. package/dist/level1/index.js.map +1 -0
  135. package/dist/level1/pricing/PriceCalculator.d.ts +62 -0
  136. package/dist/level1/pricing/PriceCalculator.d.ts.map +1 -0
  137. package/dist/level1/pricing/PriceCalculator.js +237 -0
  138. package/dist/level1/pricing/PriceCalculator.js.map +1 -0
  139. package/dist/level1/pricing/PricingStrategy.d.ts +179 -0
  140. package/dist/level1/pricing/PricingStrategy.d.ts.map +1 -0
  141. package/dist/level1/pricing/PricingStrategy.js +11 -0
  142. package/dist/level1/pricing/PricingStrategy.js.map +1 -0
  143. package/dist/level1/types/Job.d.ts +166 -0
  144. package/dist/level1/types/Job.d.ts.map +1 -0
  145. package/dist/level1/types/Job.js +11 -0
  146. package/dist/level1/types/Job.js.map +1 -0
  147. package/dist/level1/types/Options.d.ts +258 -0
  148. package/dist/level1/types/Options.d.ts.map +1 -0
  149. package/dist/level1/types/Options.js +8 -0
  150. package/dist/level1/types/Options.js.map +1 -0
  151. package/dist/level1/types/index.d.ts +8 -0
  152. package/dist/level1/types/index.d.ts.map +1 -0
  153. package/dist/level1/types/index.js +8 -0
  154. package/dist/level1/types/index.js.map +1 -0
  155. package/dist/protocol/ACTPKernel.d.ts +229 -2
  156. package/dist/protocol/ACTPKernel.d.ts.map +1 -1
  157. package/dist/protocol/ACTPKernel.js +367 -33
  158. package/dist/protocol/ACTPKernel.js.map +1 -1
  159. package/dist/protocol/AgentRegistry.d.ts +177 -0
  160. package/dist/protocol/AgentRegistry.d.ts.map +1 -0
  161. package/dist/protocol/AgentRegistry.js +449 -0
  162. package/dist/protocol/AgentRegistry.js.map +1 -0
  163. package/dist/protocol/DIDManager.d.ts +289 -0
  164. package/dist/protocol/DIDManager.d.ts.map +1 -0
  165. package/dist/protocol/DIDManager.js +481 -0
  166. package/dist/protocol/DIDManager.js.map +1 -0
  167. package/dist/protocol/DIDResolver.d.ts +236 -0
  168. package/dist/protocol/DIDResolver.d.ts.map +1 -0
  169. package/dist/protocol/DIDResolver.js +495 -0
  170. package/dist/protocol/DIDResolver.js.map +1 -0
  171. package/dist/protocol/EASHelper.d.ts +57 -2
  172. package/dist/protocol/EASHelper.d.ts.map +1 -1
  173. package/dist/protocol/EASHelper.js +230 -37
  174. package/dist/protocol/EASHelper.js.map +1 -1
  175. package/dist/protocol/EscrowVault.d.ts +93 -2
  176. package/dist/protocol/EscrowVault.d.ts.map +1 -1
  177. package/dist/protocol/EscrowVault.js +122 -33
  178. package/dist/protocol/EscrowVault.js.map +1 -1
  179. package/dist/protocol/EventMonitor.d.ts +45 -1
  180. package/dist/protocol/EventMonitor.d.ts.map +1 -1
  181. package/dist/protocol/EventMonitor.js +64 -8
  182. package/dist/protocol/EventMonitor.js.map +1 -1
  183. package/dist/protocol/MessageSigner.d.ts +116 -2
  184. package/dist/protocol/MessageSigner.d.ts.map +1 -1
  185. package/dist/protocol/MessageSigner.js +215 -9
  186. package/dist/protocol/MessageSigner.js.map +1 -1
  187. package/dist/protocol/ProofGenerator.d.ts +93 -0
  188. package/dist/protocol/ProofGenerator.d.ts.map +1 -1
  189. package/dist/protocol/ProofGenerator.js +194 -9
  190. package/dist/protocol/ProofGenerator.js.map +1 -1
  191. package/dist/protocol/QuoteBuilder.d.ts +8 -0
  192. package/dist/protocol/QuoteBuilder.d.ts.map +1 -1
  193. package/dist/protocol/QuoteBuilder.js +8 -0
  194. package/dist/protocol/QuoteBuilder.js.map +1 -1
  195. package/dist/runtime/BlockchainRuntime.d.ts +360 -0
  196. package/dist/runtime/BlockchainRuntime.d.ts.map +1 -0
  197. package/dist/runtime/BlockchainRuntime.js +767 -0
  198. package/dist/runtime/BlockchainRuntime.js.map +1 -0
  199. package/dist/runtime/IACTPRuntime.d.ts +271 -0
  200. package/dist/runtime/IACTPRuntime.d.ts.map +1 -0
  201. package/dist/runtime/IACTPRuntime.js +15 -0
  202. package/dist/runtime/IACTPRuntime.js.map +1 -0
  203. package/dist/runtime/MockRuntime.d.ts +445 -0
  204. package/dist/runtime/MockRuntime.d.ts.map +1 -0
  205. package/dist/runtime/MockRuntime.js +1065 -0
  206. package/dist/runtime/MockRuntime.js.map +1 -0
  207. package/dist/runtime/MockStateManager.d.ts +233 -0
  208. package/dist/runtime/MockStateManager.d.ts.map +1 -0
  209. package/dist/runtime/MockStateManager.js +533 -0
  210. package/dist/runtime/MockStateManager.js.map +1 -0
  211. package/dist/runtime/index.d.ts +14 -0
  212. package/dist/runtime/index.d.ts.map +1 -0
  213. package/dist/runtime/index.js +42 -0
  214. package/dist/runtime/index.js.map +1 -0
  215. package/dist/runtime/types/MockState.d.ts +167 -0
  216. package/dist/runtime/types/MockState.d.ts.map +1 -0
  217. package/dist/runtime/types/MockState.js +43 -0
  218. package/dist/runtime/types/MockState.js.map +1 -0
  219. package/dist/types/agent.d.ts +76 -0
  220. package/dist/types/agent.d.ts.map +1 -0
  221. package/dist/types/agent.js +8 -0
  222. package/dist/types/agent.js.map +1 -0
  223. package/dist/types/did.d.ts +192 -0
  224. package/dist/types/did.d.ts.map +1 -0
  225. package/dist/types/did.js +38 -0
  226. package/dist/types/did.js.map +1 -0
  227. package/dist/types/eip712.d.ts +34 -0
  228. package/dist/types/eip712.d.ts.map +1 -1
  229. package/dist/types/eip712.js +31 -5
  230. package/dist/types/eip712.js.map +1 -1
  231. package/dist/types/escrow.d.ts +17 -10
  232. package/dist/types/escrow.d.ts.map +1 -1
  233. package/dist/types/index.d.ts +5 -0
  234. package/dist/types/index.d.ts.map +1 -1
  235. package/dist/types/index.js +8 -0
  236. package/dist/types/index.js.map +1 -1
  237. package/dist/types/message.d.ts +32 -0
  238. package/dist/types/message.d.ts.map +1 -1
  239. package/dist/types/message.js +4 -0
  240. package/dist/types/message.js.map +1 -1
  241. package/dist/types/state.d.ts +28 -0
  242. package/dist/types/state.d.ts.map +1 -1
  243. package/dist/types/state.js +37 -6
  244. package/dist/types/state.js.map +1 -1
  245. package/dist/types/transaction.d.ts +17 -0
  246. package/dist/types/transaction.d.ts.map +1 -1
  247. package/dist/utils/ErrorRecoveryGuide.d.ts +125 -0
  248. package/dist/utils/ErrorRecoveryGuide.d.ts.map +1 -0
  249. package/dist/utils/ErrorRecoveryGuide.js +579 -0
  250. package/dist/utils/ErrorRecoveryGuide.js.map +1 -0
  251. package/dist/utils/Helpers.d.ts +453 -0
  252. package/dist/utils/Helpers.d.ts.map +1 -0
  253. package/dist/utils/Helpers.js +623 -0
  254. package/dist/utils/Helpers.js.map +1 -0
  255. package/dist/utils/IPFSClient.d.ts +113 -0
  256. package/dist/utils/IPFSClient.d.ts.map +1 -1
  257. package/dist/utils/IPFSClient.js +128 -7
  258. package/dist/utils/IPFSClient.js.map +1 -1
  259. package/dist/utils/Logger.d.ts +195 -0
  260. package/dist/utils/Logger.d.ts.map +1 -0
  261. package/dist/utils/Logger.js +382 -0
  262. package/dist/utils/Logger.js.map +1 -0
  263. package/dist/utils/NonceManager.d.ts +234 -1
  264. package/dist/utils/NonceManager.d.ts.map +1 -1
  265. package/dist/utils/NonceManager.js +372 -7
  266. package/dist/utils/NonceManager.js.map +1 -1
  267. package/dist/utils/RateLimiter.d.ts +253 -0
  268. package/dist/utils/RateLimiter.d.ts.map +1 -0
  269. package/dist/utils/RateLimiter.js +424 -0
  270. package/dist/utils/RateLimiter.js.map +1 -0
  271. package/dist/utils/ReceivedNonceTracker.d.ts +175 -0
  272. package/dist/utils/ReceivedNonceTracker.d.ts.map +1 -1
  273. package/dist/utils/ReceivedNonceTracker.js +261 -5
  274. package/dist/utils/ReceivedNonceTracker.js.map +1 -1
  275. package/dist/utils/SDKLifecycle.d.ts +156 -0
  276. package/dist/utils/SDKLifecycle.d.ts.map +1 -0
  277. package/dist/utils/SDKLifecycle.js +347 -0
  278. package/dist/utils/SDKLifecycle.js.map +1 -0
  279. package/dist/utils/SecureNonce.d.ts +57 -0
  280. package/dist/utils/SecureNonce.d.ts.map +1 -0
  281. package/dist/utils/SecureNonce.js +80 -0
  282. package/dist/utils/SecureNonce.js.map +1 -0
  283. package/dist/utils/Semaphore.d.ts +123 -0
  284. package/dist/utils/Semaphore.d.ts.map +1 -0
  285. package/dist/utils/Semaphore.js +247 -0
  286. package/dist/utils/Semaphore.js.map +1 -0
  287. package/dist/utils/UsedAttestationTracker.d.ts +167 -0
  288. package/dist/utils/UsedAttestationTracker.d.ts.map +1 -0
  289. package/dist/utils/UsedAttestationTracker.js +309 -0
  290. package/dist/utils/UsedAttestationTracker.js.map +1 -0
  291. package/dist/utils/canonicalJson.d.ts +22 -0
  292. package/dist/utils/canonicalJson.d.ts.map +1 -1
  293. package/dist/utils/canonicalJson.js +26 -3
  294. package/dist/utils/canonicalJson.js.map +1 -1
  295. package/dist/utils/computeTypeHash.d.ts +14 -0
  296. package/dist/utils/computeTypeHash.d.ts.map +1 -1
  297. package/dist/utils/computeTypeHash.js +19 -2
  298. package/dist/utils/computeTypeHash.js.map +1 -1
  299. package/dist/utils/fsSafe.d.ts +14 -0
  300. package/dist/utils/fsSafe.d.ts.map +1 -0
  301. package/dist/utils/fsSafe.js +89 -0
  302. package/dist/utils/fsSafe.js.map +1 -0
  303. package/dist/utils/index.d.ts +15 -0
  304. package/dist/utils/index.d.ts.map +1 -0
  305. package/dist/utils/index.js +51 -0
  306. package/dist/utils/index.js.map +1 -0
  307. package/dist/utils/security.d.ts +147 -0
  308. package/dist/utils/security.d.ts.map +1 -0
  309. package/dist/utils/security.js +391 -0
  310. package/dist/utils/security.js.map +1 -0
  311. package/dist/utils/validation.d.ts +40 -0
  312. package/dist/utils/validation.d.ts.map +1 -1
  313. package/dist/utils/validation.js +184 -7
  314. package/dist/utils/validation.js.map +1 -1
  315. package/package.json +54 -37
  316. package/src/ACTPClient.ts +692 -178
  317. package/src/abi/AgentRegistry.json +782 -0
  318. package/src/abi/EscrowVault.json +106 -38
  319. package/src/abi/IdentityRegistry.json +316 -0
  320. package/src/adapters/BaseAdapter.ts +473 -0
  321. package/src/adapters/BeginnerAdapter.ts +232 -0
  322. package/src/adapters/IntermediateAdapter.ts +316 -0
  323. package/src/adapters/index.ts +25 -0
  324. package/src/builders/DeliveryProofBuilder.ts +3 -2
  325. package/src/cli/commands/balance.ts +110 -0
  326. package/src/cli/commands/batch.ts +487 -0
  327. package/src/cli/commands/config.ts +231 -0
  328. package/src/cli/commands/init.ts +161 -0
  329. package/src/cli/commands/mint.ts +116 -0
  330. package/src/cli/commands/pay.ts +113 -0
  331. package/src/cli/commands/simulate.ts +345 -0
  332. package/src/cli/commands/time.ts +303 -0
  333. package/src/cli/commands/tx.ts +448 -0
  334. package/src/cli/commands/watch.ts +211 -0
  335. package/src/cli/index.ts +116 -0
  336. package/src/cli/utils/client.ts +249 -0
  337. package/src/cli/utils/config.ts +282 -0
  338. package/src/cli/utils/output.ts +465 -0
  339. package/src/config/networks.ts +32 -9
  340. package/src/errors/index.ts +298 -1
  341. package/src/index.ts +207 -71
  342. package/src/level0/Provider.ts +117 -0
  343. package/src/level0/ServiceDirectory.ts +131 -0
  344. package/src/level0/index.ts +10 -0
  345. package/src/level0/provide.ts +131 -0
  346. package/src/level0/request.ts +494 -0
  347. package/src/level1/Agent.ts +1432 -0
  348. package/src/level1/index.ts +10 -0
  349. package/src/level1/pricing/PriceCalculator.ts +255 -0
  350. package/src/level1/pricing/PricingStrategy.ts +198 -0
  351. package/src/level1/types/Job.ts +179 -0
  352. package/src/level1/types/Options.ts +291 -0
  353. package/src/level1/types/index.ts +8 -0
  354. package/src/protocol/ACTPKernel.ts +175 -23
  355. package/src/protocol/AgentRegistry.ts +559 -0
  356. package/src/protocol/DIDManager.ts +629 -0
  357. package/src/protocol/DIDResolver.ts +554 -0
  358. package/src/protocol/EASHelper.ts +230 -46
  359. package/src/protocol/EscrowVault.ts +68 -50
  360. package/src/protocol/EventMonitor.ts +44 -15
  361. package/src/protocol/MessageSigner.ts +193 -13
  362. package/src/protocol/ProofGenerator.ts +223 -4
  363. package/src/runtime/BlockchainRuntime.ts +993 -0
  364. package/src/runtime/IACTPRuntime.ts +284 -0
  365. package/src/runtime/MockRuntime.ts +1244 -0
  366. package/src/runtime/MockStateManager.ts +576 -0
  367. package/src/runtime/index.ts +25 -0
  368. package/src/runtime/types/MockState.ts +227 -0
  369. package/src/types/agent.ts +79 -0
  370. package/src/types/did.ts +223 -0
  371. package/src/types/escrow.ts +12 -11
  372. package/src/types/index.ts +5 -1
  373. package/src/types/state.ts +12 -3
  374. package/src/types/transaction.ts +4 -1
  375. package/src/utils/ErrorRecoveryGuide.ts +675 -0
  376. package/src/utils/Helpers.ts +688 -0
  377. package/src/utils/IPFSClient.ts +122 -5
  378. package/src/utils/Logger.ts +484 -0
  379. package/src/utils/NonceManager.ts +305 -8
  380. package/src/utils/RateLimiter.ts +534 -0
  381. package/src/utils/ReceivedNonceTracker.ts +170 -0
  382. package/src/utils/SDKLifecycle.ts +416 -0
  383. package/src/utils/SecureNonce.ts +78 -0
  384. package/src/utils/Semaphore.ts +276 -0
  385. package/src/utils/UsedAttestationTracker.ts +387 -0
  386. package/src/utils/fsSafe.ts +75 -0
  387. package/src/utils/index.ts +80 -0
  388. package/src/utils/security.ts +418 -0
  389. package/src/utils/validation.ts +164 -0
  390. package/src/__tests__/ProofGenerator.test.ts +0 -124
  391. package/src/__tests__/QuoteBuilder.test.ts +0 -516
  392. package/src/__tests__/StateMachine.test.ts +0 -82
  393. package/src/__tests__/builders/DeliveryProofBuilder.test.ts +0 -581
  394. package/src/__tests__/integration/ACTPClient.test.ts +0 -263
  395. package/src/__tests__/integration.test.ts +0 -289
  396. package/src/__tests__/protocol/EASHelper.test.ts +0 -472
  397. package/src/__tests__/protocol/EventMonitor.test.ts +0 -382
  398. package/src/__tests__/security/ACTPKernel.security.test.ts +0 -1167
  399. package/src/__tests__/security/EscrowVault.security.test.ts +0 -570
  400. package/src/__tests__/security/MessageSigner.security.test.ts +0 -286
  401. package/src/__tests__/security/NonceReplay.security.test.ts +0 -501
  402. package/src/__tests__/security/validation.security.test.ts +0 -376
  403. package/src/__tests__/utils/IPFSClient.test.ts +0 -262
  404. package/src/__tests__/utils/NonceManager.test.ts +0 -205
  405. package/src/__tests__/utils/canonicalJson.test.ts +0 -153
@@ -0,0 +1,1091 @@
1
+ "use strict";
2
+ /**
3
+ * Agent - Standard API for AI agents
4
+ *
5
+ * Provides agent-level abstractions: lifecycle, service provision,
6
+ * job handling, events, and statistics.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ var desc = Object.getOwnPropertyDescriptor(m, k);
13
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
+ desc = { enumerable: true, get: function() { return m[k]; } };
15
+ }
16
+ Object.defineProperty(o, k2, desc);
17
+ }) : (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ o[k2] = m[k];
20
+ }));
21
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
23
+ }) : function(o, v) {
24
+ o["default"] = v;
25
+ });
26
+ var __importStar = (this && this.__importStar) || function (mod) {
27
+ if (mod && mod.__esModule) return mod;
28
+ var result = {};
29
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
30
+ __setModuleDefault(result, mod);
31
+ return result;
32
+ };
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.Agent = void 0;
35
+ const events_1 = require("events");
36
+ const path = __importStar(require("path"));
37
+ const os = __importStar(require("os"));
38
+ const fs = __importStar(require("fs"));
39
+ const ethers_1 = require("ethers");
40
+ const ACTPClient_1 = require("../ACTPClient");
41
+ const errors_1 = require("../errors");
42
+ const security_1 = require("../utils/security");
43
+ const Logger_1 = require("../utils/Logger");
44
+ const Helpers_1 = require("../utils/Helpers");
45
+ const Semaphore_1 = require("../utils/Semaphore");
46
+ const ProofGenerator_1 = require("../protocol/ProofGenerator");
47
+ /**
48
+ * Agent class - Standard API
49
+ *
50
+ * Represents an autonomous AI agent that can provide services,
51
+ * request services from other agents, and manage its lifecycle.
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * const agent = new Agent({ name: 'Translator', network: 'mock' });
56
+ *
57
+ * agent.provide('translation', async (job, ctx) => {
58
+ * ctx.progress(50, 'Translating...');
59
+ * return { translated: translate(job.input.text) };
60
+ * });
61
+ *
62
+ * agent.on('payment:received', (amount) => {
63
+ * console.log(`Earned ${amount} USDC!`);
64
+ * });
65
+ *
66
+ * await agent.start();
67
+ * ```
68
+ */
69
+ class Agent extends events_1.EventEmitter {
70
+ /**
71
+ * Creates a new Agent instance
72
+ *
73
+ * @param config - Agent configuration
74
+ */
75
+ constructor(config) {
76
+ super();
77
+ /**
78
+ * Current agent status
79
+ */
80
+ this._status = 'idle';
81
+ /**
82
+ * Registered services
83
+ */
84
+ this.services = new Map();
85
+ /**
86
+ * Active jobs
87
+ *
88
+ * SECURITY FIX (C-2): Changed from Map to LRUCache to prevent unbounded growth
89
+ * Maximum 1000 active jobs with LRU eviction
90
+ */
91
+ this.activeJobs = new security_1.LRUCache(1000);
92
+ /**
93
+ * Processed job IDs (for deduplication)
94
+ *
95
+ * SECURITY FIX (C-1): Track jobs we've attempted to process
96
+ * This prevents race conditions where the same job is processed multiple times
97
+ * before the state transition completes
98
+ */
99
+ this.processedJobs = new security_1.LRUCache(10000);
100
+ /**
101
+ * Processing locks (for atomic locking)
102
+ *
103
+ * SECURITY FIX (C-1): Mutex for job processing.
104
+ * When we see a job, we IMMEDIATELY add to this set (atomic in single-threaded JS).
105
+ * This prevents race conditions where two poll cycles both pass the processedJobs.has()
106
+ * check before either calls processedJobs.set().
107
+ */
108
+ this.processingLocks = new Set();
109
+ /**
110
+ * Statistics
111
+ */
112
+ this._stats = {
113
+ jobsReceived: 0,
114
+ jobsCompleted: 0,
115
+ jobsFailed: 0,
116
+ totalEarned: 0,
117
+ totalSpent: 0,
118
+ averageJobTime: 0,
119
+ successRate: 0,
120
+ };
121
+ /**
122
+ * Cached balance (updated periodically during polling)
123
+ */
124
+ this._balance = {
125
+ eth: '0',
126
+ usdc: '0',
127
+ locked: '0',
128
+ pending: '0',
129
+ };
130
+ if (!config.name) {
131
+ throw new errors_1.ServiceConfigError('name', 'Agent name is required');
132
+ }
133
+ // SECURITY FIX (H-6): Use dedicated AGIRAILS directory as base
134
+ // This prevents writes anywhere in the project directory
135
+ const AGIRAILS_BASE = path.join(os.homedir(), '.agirails');
136
+ // Ensure base directory exists
137
+ if (!fs.existsSync(AGIRAILS_BASE)) {
138
+ fs.mkdirSync(AGIRAILS_BASE, { recursive: true });
139
+ }
140
+ // Validate state directory path if provided
141
+ if (config.stateDirectory) {
142
+ try {
143
+ // Validate the path is safe (no traversal, within AGIRAILS_BASE)
144
+ config.stateDirectory = (0, security_1.validatePath)(config.stateDirectory, AGIRAILS_BASE);
145
+ }
146
+ catch (error) {
147
+ throw new errors_1.ServiceConfigError('stateDirectory', `Invalid state directory: ${error instanceof Error ? error.message : String(error)}`);
148
+ }
149
+ }
150
+ this.name = config.name;
151
+ this.description = config.description;
152
+ this.network = config.network || 'mock';
153
+ this.config = config;
154
+ this.logger = new Logger_1.Logger({
155
+ source: `Agent:${config.name}`,
156
+ minLevel: config.logging?.level || 'info',
157
+ });
158
+ // SECURITY FIX (MEDIUM-4): Initialize concurrency semaphore
159
+ // Default to 10 concurrent jobs if not specified
160
+ const maxConcurrency = config.behavior?.concurrency || 10;
161
+ this.concurrencySemaphore = new Semaphore_1.Semaphore(maxConcurrency);
162
+ this.logger.debug('Initialized concurrency semaphore', { maxConcurrency });
163
+ }
164
+ // =========================================================================
165
+ // Lifecycle Methods
166
+ // =========================================================================
167
+ /**
168
+ * Start the agent
169
+ *
170
+ * Initializes ACTP client and begins polling for jobs.
171
+ *
172
+ * @throws {AgentLifecycleError} If agent is not in idle or stopped state
173
+ */
174
+ async start() {
175
+ if (this._status !== 'idle' && this._status !== 'stopped') {
176
+ throw new errors_1.AgentLifecycleError(this._status, 'start');
177
+ }
178
+ this._status = 'starting';
179
+ this.emit('starting');
180
+ try {
181
+ // SECURITY FIX (RPCURL): Use rpcUrl from config or fallback to network default
182
+ // This allows Agent to work with testnet/mainnet without requiring explicit rpcUrl
183
+ // if user is okay with public RPC endpoints.
184
+ let rpcUrl = this.config.rpcUrl;
185
+ if (!rpcUrl && (this.network === 'testnet' || this.network === 'mainnet')) {
186
+ // Import getNetwork to get default rpcUrl from network config
187
+ const { getNetwork } = await Promise.resolve().then(() => __importStar(require('../config/networks')));
188
+ const networkName = this.network === 'testnet' ? 'base-sepolia' : 'base-mainnet';
189
+ const networkConfig = getNetwork(networkName);
190
+ rpcUrl = networkConfig.rpcUrl;
191
+ this.logger.info(`Using default RPC URL for ${networkName}: ${rpcUrl}`);
192
+ }
193
+ // Initialize ACTP client
194
+ this._client = await ACTPClient_1.ACTPClient.create({
195
+ mode: this.network === 'testnet' ? 'testnet' : this.network === 'mainnet' ? 'mainnet' : 'mock',
196
+ requesterAddress: this.address || this.generateAddress(),
197
+ stateDirectory: this.config.stateDirectory,
198
+ privateKey: this.getPrivateKey(),
199
+ rpcUrl,
200
+ });
201
+ // Start polling for jobs
202
+ this.startPolling();
203
+ this._status = 'running';
204
+ this.emit('started');
205
+ }
206
+ catch (error) {
207
+ this._status = 'stopped';
208
+ this.emit('error', error);
209
+ throw error;
210
+ }
211
+ }
212
+ /**
213
+ * Stop the agent
214
+ *
215
+ * Stops polling and waits for active jobs to complete.
216
+ */
217
+ async stop() {
218
+ if (this._status === 'stopped' || this._status === 'stopping') {
219
+ return;
220
+ }
221
+ this._status = 'stopping';
222
+ this.emit('stopping');
223
+ // Stop polling
224
+ this.stopPolling();
225
+ // Wait for active jobs to complete (with timeout)
226
+ await this.waitForActiveJobs(30000); // 30s timeout
227
+ this._status = 'stopped';
228
+ this.emit('stopped');
229
+ }
230
+ /**
231
+ * Pause the agent
232
+ *
233
+ * Stops accepting new jobs but keeps active jobs running.
234
+ */
235
+ pause() {
236
+ if (this._status !== 'running') {
237
+ throw new errors_1.AgentLifecycleError(this._status, 'pause');
238
+ }
239
+ this.stopPolling();
240
+ this._status = 'paused';
241
+ this.emit('paused');
242
+ }
243
+ /**
244
+ * Resume the agent
245
+ *
246
+ * Resumes accepting new jobs after being paused.
247
+ */
248
+ resume() {
249
+ if (this._status !== 'paused') {
250
+ throw new errors_1.AgentLifecycleError(this._status, 'resume');
251
+ }
252
+ this.startPolling();
253
+ this._status = 'running';
254
+ this.emit('resumed');
255
+ }
256
+ /**
257
+ * Restart the agent
258
+ */
259
+ async restart() {
260
+ await this.stop();
261
+ await this.start();
262
+ }
263
+ // =========================================================================
264
+ // Service Registration
265
+ // =========================================================================
266
+ /**
267
+ * Register a service handler
268
+ *
269
+ * @param serviceOrConfig - Service name or full configuration
270
+ * @param handler - Job handler function
271
+ * @param options - Optional pricing/filter configuration
272
+ *
273
+ * @example
274
+ * ```typescript
275
+ * // Simple
276
+ * agent.provide('echo', async (job) => job.input);
277
+ *
278
+ * // With pricing
279
+ * agent.provide({
280
+ * name: 'translation',
281
+ * pricing: {
282
+ * cost: { base: 0.5, perUnit: { unit: 'word', rate: 0.005 } },
283
+ * margin: 0.40
284
+ * }
285
+ * }, async (job, ctx) => {
286
+ * // ... translation logic
287
+ * });
288
+ * ```
289
+ */
290
+ provide(serviceOrConfig, handler, options) {
291
+ const config = typeof serviceOrConfig === 'string'
292
+ ? { name: serviceOrConfig, ...options }
293
+ : serviceOrConfig;
294
+ if (!config.name) {
295
+ throw new errors_1.ServiceConfigError('name', 'Service name is required');
296
+ }
297
+ // SECURITY FIX (H-2): Validate service name to prevent injection
298
+ try {
299
+ config.name = (0, security_1.validateServiceName)(config.name);
300
+ }
301
+ catch (error) {
302
+ throw new errors_1.ServiceConfigError('name', `Invalid service name: ${error instanceof Error ? error.message : String(error)}`);
303
+ }
304
+ if (this.services.has(config.name)) {
305
+ throw new errors_1.ServiceConfigError('name', `Service "${config.name}" already registered`);
306
+ }
307
+ this.services.set(config.name, { config, handler });
308
+ this.emit('service:registered', config.name);
309
+ this.logger.info('Service registered', { service: config.name });
310
+ return this;
311
+ }
312
+ /**
313
+ * Request a service from another agent
314
+ *
315
+ * @param service - Service name
316
+ * @param options - Request options
317
+ * @returns Promise resolving to result
318
+ */
319
+ async request(service, options) {
320
+ if (!this._client) {
321
+ throw new errors_1.AgentLifecycleError(this._status, 'request (agent not started)');
322
+ }
323
+ // Import Basic API request function
324
+ const { request: basicRequest } = await Promise.resolve().then(() => __importStar(require('../level0/request')));
325
+ // Call Basic API request with agent's network
326
+ const result = await basicRequest(service, {
327
+ ...options,
328
+ network: this.network,
329
+ });
330
+ // Update stats
331
+ this._stats.totalSpent += options.budget;
332
+ return result;
333
+ }
334
+ // =========================================================================
335
+ // Properties
336
+ // =========================================================================
337
+ /**
338
+ * Current agent status
339
+ */
340
+ get status() {
341
+ return this._status;
342
+ }
343
+ /**
344
+ * Agent's Ethereum address
345
+ */
346
+ get address() {
347
+ return this._client?.getAddress() || '';
348
+ }
349
+ /**
350
+ * Registered service names
351
+ */
352
+ get serviceNames() {
353
+ return Array.from(this.services.keys());
354
+ }
355
+ /**
356
+ * Active jobs
357
+ *
358
+ * SECURITY FIX (N-2): Now uses LRUCache.values() iterator.
359
+ * Returns a snapshot of currently active jobs.
360
+ */
361
+ get jobs() {
362
+ return this.activeJobs.values();
363
+ }
364
+ /**
365
+ * Statistics
366
+ */
367
+ get stats() {
368
+ return { ...this._stats };
369
+ }
370
+ /**
371
+ * Get agent balance
372
+ *
373
+ * Returns current USDC balance plus locked/pending amounts from active transactions.
374
+ * Note: This is an async operation wrapped in a sync getter for convenience.
375
+ * For real-time balance, use getBalanceAsync() instead.
376
+ */
377
+ get balance() {
378
+ // Return cached balance (updated periodically during polling)
379
+ return { ...this._balance };
380
+ }
381
+ /**
382
+ * Get agent balance asynchronously (real-time)
383
+ *
384
+ * @returns Promise resolving to current balance
385
+ */
386
+ async getBalanceAsync() {
387
+ if (!this._client?.runtime) {
388
+ return {
389
+ eth: '0',
390
+ usdc: '0',
391
+ locked: '0',
392
+ pending: '0',
393
+ };
394
+ }
395
+ try {
396
+ // Get USDC balance (if runtime supports it)
397
+ let usdc = '0';
398
+ if ('getBalance' in this._client.runtime) {
399
+ usdc = await this._client.runtime.getBalance(this.address);
400
+ }
401
+ // Get transactions where this agent is provider
402
+ let locked = BigInt(0);
403
+ let pending = BigInt(0);
404
+ if ('getTransactionsByProvider' in this._client.runtime) {
405
+ // Get all active transactions for this provider
406
+ const allTx = await this._client.runtime.getTransactionsByProvider(this.address, undefined, // all states
407
+ 1000);
408
+ for (const tx of allTx) {
409
+ const amount = BigInt(tx.amount || '0');
410
+ // Locked: funds in escrow for active work (COMMITTED, IN_PROGRESS, DELIVERED)
411
+ if (tx.state === 'COMMITTED' || tx.state === 'IN_PROGRESS' || tx.state === 'DELIVERED') {
412
+ locked += amount;
413
+ }
414
+ // Pending: potential earnings waiting to be accepted (INITIATED, QUOTED)
415
+ if (tx.state === 'INITIATED' || tx.state === 'QUOTED') {
416
+ pending += amount;
417
+ }
418
+ }
419
+ }
420
+ this._balance = {
421
+ eth: '0', // ETH balance not tracked in USDC-only system
422
+ usdc: usdc,
423
+ locked: locked.toString(),
424
+ pending: pending.toString(),
425
+ };
426
+ return { ...this._balance };
427
+ }
428
+ catch (error) {
429
+ this.logger.warn('Failed to fetch balance', { error });
430
+ return { ...this._balance };
431
+ }
432
+ }
433
+ /**
434
+ * ACTP Client reference (for advanced usage)
435
+ */
436
+ get client() {
437
+ return this._client;
438
+ }
439
+ // =========================================================================
440
+ // Private Methods
441
+ // =========================================================================
442
+ /**
443
+ * Start polling for new jobs
444
+ */
445
+ startPolling() {
446
+ if (this.pollingIntervalId) {
447
+ return; // Already polling
448
+ }
449
+ const pollingInterval = 5000; // 5 seconds
450
+ this.pollingIntervalId = setInterval(() => {
451
+ this.pollForJobs().catch((error) => {
452
+ this.emit('error', error);
453
+ });
454
+ }, pollingInterval);
455
+ }
456
+ /**
457
+ * Stop polling
458
+ */
459
+ stopPolling() {
460
+ if (this.pollingIntervalId) {
461
+ clearInterval(this.pollingIntervalId);
462
+ this.pollingIntervalId = undefined;
463
+ }
464
+ }
465
+ /**
466
+ * Poll for new jobs
467
+ *
468
+ * SECURITY FIXES:
469
+ * - C-1: Race condition prevention using processedJobs deduplication
470
+ * - C-2: Memory leak prevention using LRUCache
471
+ * - H-1: DoS prevention by filtering transactions before loading all
472
+ * - H-4: Authorization checks for state transitions
473
+ *
474
+ * Queries runtime for transactions where this agent is the provider
475
+ * and the transaction is in INITIATED state (awaiting acceptance).
476
+ * For each pending transaction, creates a Job object and invokes
477
+ * the appropriate service handler.
478
+ */
479
+ async pollForJobs() {
480
+ if (!this._client) {
481
+ return; // Agent not started yet
482
+ }
483
+ try {
484
+ // SECURITY FIX (H-1): Use filtered query instead of getAllTransactions
485
+ // This prevents DoS via memory exhaustion by only fetching relevant transactions
486
+ let pendingJobs = [];
487
+ // Check if runtime has the filtered query method
488
+ if ('getTransactionsByProvider' in this._client.runtime) {
489
+ // Use optimized filtered query (max 100 jobs per poll)
490
+ pendingJobs = await this._client.runtime.getTransactionsByProvider(this.address, 'INITIATED', 100);
491
+ }
492
+ else {
493
+ // Fallback to getAllTransactions (for older runtime versions)
494
+ const allTransactions = await this._client.runtime.getAllTransactions();
495
+ pendingJobs = allTransactions.filter((tx) => tx.provider === this.address && tx.state === 'INITIATED');
496
+ }
497
+ this.logger.debug('Polling for jobs', {
498
+ pendingJobs: pendingJobs.length,
499
+ });
500
+ // Process each pending job
501
+ for (const tx of pendingJobs) {
502
+ try {
503
+ // SECURITY FIX (C-1): Check processingLocks first (atomic check)
504
+ // This prevents race conditions where two poll cycles both try to process
505
+ // the same job before either transitions the state
506
+ if (this.processingLocks.has(tx.id) || this.processedJobs.has(tx.id)) {
507
+ continue;
508
+ }
509
+ // IMMEDIATELY acquire lock (atomic in single-threaded JS)
510
+ this.processingLocks.add(tx.id);
511
+ // SECURITY FIX (C-2): Check if already in active jobs (LRUCache handles size limit)
512
+ if (this.activeJobs.has(tx.id)) {
513
+ this.processingLocks.delete(tx.id);
514
+ continue;
515
+ }
516
+ // SECURITY FIX (H-4): Verify this agent is authorized to accept this transaction
517
+ // Check that tx.provider matches our address (prevents unauthorized state transitions)
518
+ if (tx.provider !== this.address) {
519
+ this.logger.warn('Unauthorized transaction detected', {
520
+ txId: tx.id,
521
+ expectedProvider: this.address,
522
+ actualProvider: tx.provider,
523
+ });
524
+ this.processingLocks.delete(tx.id);
525
+ continue;
526
+ }
527
+ // Find matching service handler
528
+ const serviceHandler = this.findServiceHandler(tx);
529
+ if (!serviceHandler) {
530
+ // No handler registered for this service type
531
+ this.logger.debug('No handler for transaction', { txId: tx.id });
532
+ this.processingLocks.delete(tx.id);
533
+ continue;
534
+ }
535
+ // Check auto-accept behavior
536
+ const shouldAccept = await this.shouldAutoAccept(tx);
537
+ if (!shouldAccept) {
538
+ this.logger.debug('Auto-accept declined', { txId: tx.id });
539
+ this.processingLocks.delete(tx.id);
540
+ continue;
541
+ }
542
+ // Create Job object from transaction
543
+ const job = this.createJobFromTransaction(tx);
544
+ // SECURITY FIX (C-2): Add to active jobs (LRUCache prevents unbounded growth)
545
+ this.activeJobs.set(job.id, job);
546
+ // Link escrow immediately to transition out of INITIATED state
547
+ // This prevents polling from picking up this job again
548
+ try {
549
+ if (this._client && tx.state === 'INITIATED') {
550
+ await this._client.runtime.linkEscrow(tx.id, tx.amount);
551
+ }
552
+ // Successfully processed - mark as processed and release lock
553
+ this.processedJobs.set(job.id, true);
554
+ }
555
+ catch (escrowError) {
556
+ // If linking escrow fails, remove from active jobs and release lock (allow retry)
557
+ this.activeJobs.delete(job.id);
558
+ this.logger.error('Failed to link escrow', { txId: tx.id }, escrowError);
559
+ this.processingLocks.delete(tx.id);
560
+ continue;
561
+ }
562
+ finally {
563
+ // Always release the lock
564
+ this.processingLocks.delete(tx.id);
565
+ }
566
+ this._stats.jobsReceived++;
567
+ this.emit('job:received', job);
568
+ this.logger.info('Job accepted', { jobId: job.id, service: job.service });
569
+ // Process the job asynchronously (don't await here to continue polling)
570
+ this.processJob(job, serviceHandler.handler).catch((error) => {
571
+ this.logger.error('Job processing failed', { jobId: job.id }, error);
572
+ this.emit('error', error);
573
+ });
574
+ }
575
+ catch (error) {
576
+ // Log error but continue processing other jobs
577
+ this.logger.error('Error processing pending job', { txId: tx.id }, error);
578
+ this.emit('error', error);
579
+ }
580
+ }
581
+ // Update cached balance (non-blocking, don't await)
582
+ this.getBalanceAsync().catch(() => {
583
+ // Silently ignore balance update errors during polling
584
+ });
585
+ }
586
+ catch (error) {
587
+ // Polling error - will retry on next interval
588
+ this.logger.error('Polling error', {}, error);
589
+ this.emit('error', error);
590
+ }
591
+ }
592
+ /**
593
+ * Find service handler for a transaction
594
+ *
595
+ * SECURITY FIX (MEDIUM): Use exact field matching instead of substring search
596
+ * to prevent service routing spoofing attacks.
597
+ *
598
+ * Supports multiple formats (in priority order):
599
+ * 1. JSON: {"service":"name","input":...} - new structured format
600
+ * 2. Legacy: "service:name;input:..." - backward compatibility
601
+ * 3. Plain string exact match - simple service name
602
+ * 4. bytes32 hash - on-chain only (requires off-chain lookup)
603
+ */
604
+ findServiceHandler(tx) {
605
+ const serviceDesc = tx.serviceDescription;
606
+ if (!serviceDesc) {
607
+ return undefined;
608
+ }
609
+ let parsedService;
610
+ // 1. Try JSON format first (new structured format from request())
611
+ try {
612
+ const jsonMetadata = JSON.parse(serviceDesc);
613
+ if (jsonMetadata && typeof jsonMetadata.service === 'string') {
614
+ parsedService = jsonMetadata.service;
615
+ }
616
+ }
617
+ catch {
618
+ // Not JSON, try other formats
619
+ }
620
+ // 2. Try legacy "service:NAME;input:JSON" format
621
+ if (!parsedService) {
622
+ const legacyMetadata = Helpers_1.ServiceHash.fromLegacy(serviceDesc);
623
+ if (legacyMetadata) {
624
+ parsedService = legacyMetadata.service;
625
+ }
626
+ }
627
+ // 3. If we parsed a service name, do EXACT match
628
+ if (parsedService) {
629
+ const handler = this.services.get(parsedService);
630
+ if (handler) {
631
+ return handler;
632
+ }
633
+ }
634
+ // 4. Check if it's a bytes32 hash (from on-chain BlockchainRuntime)
635
+ // NOTE: For hashed metadata, the original data must be retrieved from
636
+ // event logs or off-chain storage. This is a fallback for hash-only matching.
637
+ if (Helpers_1.ServiceHash.isValidHash(serviceDesc)) {
638
+ this.logger.debug('Service description is a hash - cannot extract service name', {
639
+ hash: serviceDesc.slice(0, 18) + '...',
640
+ });
641
+ // Cannot match hashes without original data
642
+ // In production, use event indexing to get original metadata
643
+ return undefined;
644
+ }
645
+ // 5. Fallback: Plain string exact match (service name directly)
646
+ for (const [serviceName, handler] of this.services.entries()) {
647
+ // EXACT match only - prevent substring spoofing
648
+ if (serviceDesc === serviceName) {
649
+ return handler;
650
+ }
651
+ }
652
+ return undefined;
653
+ }
654
+ /**
655
+ * Check if job should be auto-accepted
656
+ *
657
+ * SECURITY FIX (MVP): Added pricing strategy evaluation
658
+ * - Checks service-level filters (budget constraints)
659
+ * - Evaluates pricing strategy if configured
660
+ * - Only accepts jobs that meet pricing requirements
661
+ */
662
+ async shouldAutoAccept(tx) {
663
+ // Get the service config for this transaction
664
+ const serviceHandler = this.findServiceHandler(tx);
665
+ // Check service-level filters first (budget constraints)
666
+ if (serviceHandler?.config.filter) {
667
+ const filter = serviceHandler.config.filter;
668
+ const budget = this.convertAmountToNumber(tx.amount);
669
+ // If filter is a ServiceFilter object, check budget constraints
670
+ if (typeof filter === 'object' && !Array.isArray(filter)) {
671
+ // Check minBudget
672
+ if (filter.minBudget !== undefined && budget < filter.minBudget) {
673
+ this.logger.debug('Job rejected: budget below minimum', {
674
+ txId: tx.id,
675
+ budget,
676
+ minBudget: filter.minBudget,
677
+ });
678
+ return false;
679
+ }
680
+ // Check maxBudget
681
+ if (filter.maxBudget !== undefined && budget > filter.maxBudget) {
682
+ this.logger.debug('Job rejected: budget above maximum', {
683
+ txId: tx.id,
684
+ budget,
685
+ maxBudget: filter.maxBudget,
686
+ });
687
+ return false;
688
+ }
689
+ // Check custom filter function
690
+ if (filter.custom && typeof filter.custom === 'function') {
691
+ const job = this.createJobFromTransaction(tx);
692
+ const customResult = filter.custom(job);
693
+ if (!customResult) {
694
+ this.logger.debug('Job rejected: custom filter declined', { txId: tx.id });
695
+ return false;
696
+ }
697
+ }
698
+ }
699
+ // If filter is a function (legacy support)
700
+ else if (typeof filter === 'function') {
701
+ const job = this.createJobFromTransaction(tx);
702
+ const filterResult = filter(job);
703
+ if (!filterResult) {
704
+ this.logger.debug('Job rejected: filter function declined', { txId: tx.id });
705
+ return false;
706
+ }
707
+ }
708
+ }
709
+ // MVP: Check pricing strategy if configured
710
+ if (serviceHandler?.config.pricing) {
711
+ const { calculatePrice } = await Promise.resolve().then(() => __importStar(require('./pricing/PriceCalculator')));
712
+ const job = this.createJobFromTransaction(tx);
713
+ try {
714
+ const calculation = calculatePrice(serviceHandler.config.pricing, job);
715
+ this.logger.debug('Pricing calculation', {
716
+ txId: tx.id,
717
+ cost: calculation.cost,
718
+ price: calculation.price,
719
+ profit: calculation.profit,
720
+ margin: calculation.marginPercent,
721
+ decision: calculation.decision,
722
+ reason: calculation.reason,
723
+ });
724
+ // Only accept if pricing decision is 'accept'
725
+ if (calculation.decision === 'reject') {
726
+ this.logger.info('Job rejected by pricing strategy', {
727
+ txId: tx.id,
728
+ reason: calculation.reason,
729
+ });
730
+ return false;
731
+ }
732
+ // If decision is 'counter-offer', we could implement QUOTED state here
733
+ // For MVP, we treat 'counter-offer' as reject (no automatic negotiation)
734
+ if (calculation.decision === 'counter-offer') {
735
+ this.logger.info('Job requires counter-offer (not implemented in MVP)', {
736
+ txId: tx.id,
737
+ reason: calculation.reason,
738
+ });
739
+ return false;
740
+ }
741
+ }
742
+ catch (error) {
743
+ // If pricing calculation fails, reject the job for safety
744
+ this.logger.error('Pricing calculation failed, rejecting job', { txId: tx.id }, error);
745
+ return false;
746
+ }
747
+ }
748
+ // Check agent-level autoAccept behavior
749
+ const autoAccept = this.config.behavior?.autoAccept;
750
+ if (autoAccept === undefined || autoAccept === true) {
751
+ return true;
752
+ }
753
+ if (autoAccept === false) {
754
+ return false;
755
+ }
756
+ // It's a function - evaluate it
757
+ if (typeof autoAccept === 'function') {
758
+ const job = this.createJobFromTransaction(tx);
759
+ return await autoAccept(job);
760
+ }
761
+ return false;
762
+ }
763
+ /**
764
+ * Create Job object from MockTransaction
765
+ */
766
+ createJobFromTransaction(tx) {
767
+ return {
768
+ id: tx.id,
769
+ service: this.extractServiceName(tx),
770
+ input: this.extractJobInput(tx),
771
+ budget: this.convertAmountToNumber(tx.amount),
772
+ deadline: new Date(tx.deadline * 1000), // Convert unix timestamp to Date
773
+ requester: tx.requester,
774
+ metadata: this.extractMetadata(tx),
775
+ };
776
+ }
777
+ /**
778
+ * Extract service name from transaction
779
+ *
780
+ * Supports multiple formats:
781
+ * 1. JSON: {"service":"name","input":...}
782
+ * 2. Legacy: "service:name;input:..."
783
+ * 3. Plain string (service name directly)
784
+ */
785
+ extractServiceName(tx) {
786
+ if (!tx.serviceDescription) {
787
+ return 'unknown';
788
+ }
789
+ // Try JSON format first (new structured format)
790
+ try {
791
+ const parsed = JSON.parse(tx.serviceDescription);
792
+ if (parsed && typeof parsed.service === 'string') {
793
+ return parsed.service;
794
+ }
795
+ }
796
+ catch {
797
+ // Not JSON, try other formats
798
+ }
799
+ // Try legacy format: "service:serviceName;input:..."
800
+ const legacyMatch = tx.serviceDescription.match(/^service:([^;]+)/);
801
+ if (legacyMatch) {
802
+ return legacyMatch[1];
803
+ }
804
+ // Plain string - might be just the service name
805
+ if (typeof tx.serviceDescription === 'string' && tx.serviceDescription.length < 64) {
806
+ return tx.serviceDescription;
807
+ }
808
+ return 'unknown';
809
+ }
810
+ /**
811
+ * Extract job input from transaction
812
+ *
813
+ * Supports multiple formats:
814
+ * 1. JSON: {"service":"name","input":{...}}
815
+ * 2. Legacy: "service:name;input:JSON"
816
+ */
817
+ extractJobInput(tx) {
818
+ if (!tx.serviceDescription) {
819
+ return {};
820
+ }
821
+ // Try JSON format first (new structured format)
822
+ try {
823
+ const parsed = JSON.parse(tx.serviceDescription);
824
+ if (parsed && parsed.input !== undefined) {
825
+ return parsed.input;
826
+ }
827
+ }
828
+ catch {
829
+ // Not JSON, try other formats
830
+ }
831
+ // Try legacy format: "service:serviceName;input:JSON"
832
+ const legacyMatch = tx.serviceDescription.match(/;input:(.+)$/);
833
+ if (legacyMatch) {
834
+ try {
835
+ return JSON.parse(legacyMatch[1]);
836
+ }
837
+ catch {
838
+ return legacyMatch[1]; // Return as string if not valid JSON
839
+ }
840
+ }
841
+ return {};
842
+ }
843
+ /**
844
+ * Extract metadata from transaction
845
+ */
846
+ extractMetadata(tx) {
847
+ return {
848
+ transactionId: tx.id,
849
+ createdAt: tx.createdAt,
850
+ disputeWindow: tx.disputeWindow,
851
+ };
852
+ }
853
+ /**
854
+ * Convert amount string to number (USDC has 6 decimals)
855
+ */
856
+ convertAmountToNumber(amount) {
857
+ const amountBigInt = BigInt(amount);
858
+ return Number(amountBigInt) / 1000000; // Convert from USDC wei to USDC
859
+ }
860
+ /**
861
+ * Process a job by invoking the handler
862
+ *
863
+ * SECURITY FIX (C-2): Always cleanup activeJobs on completion/failure
864
+ * SECURITY FIX (MEDIUM-4): Uses semaphore to limit concurrent execution
865
+ */
866
+ async processJob(job, handler) {
867
+ const startTime = Date.now();
868
+ // SECURITY FIX (MEDIUM-4): Check concurrency limit before processing
869
+ // If semaphore is full, wait up to 30 seconds for a slot
870
+ const CONCURRENCY_TIMEOUT_MS = 30000;
871
+ try {
872
+ // Try to acquire semaphore permit (wait if at limit)
873
+ await this.concurrencySemaphore.acquire(CONCURRENCY_TIMEOUT_MS);
874
+ }
875
+ catch (acquireError) {
876
+ // Timeout waiting for concurrency slot
877
+ this.logger.warn('Job rejected due to concurrency limit', {
878
+ jobId: job.id,
879
+ activeJobs: this.concurrencySemaphore.limit - this.concurrencySemaphore.availablePermits,
880
+ maxConcurrency: this.concurrencySemaphore.limit,
881
+ queueLength: this.concurrencySemaphore.queueLength,
882
+ });
883
+ // Remove from active jobs since we couldn't process it
884
+ this.activeJobs.delete(job.id);
885
+ this.processedJobs.delete(job.id);
886
+ this.emit('job:rejected', job, 'concurrency_limit');
887
+ throw new Error(`Job ${job.id} rejected: concurrency limit reached (${this.concurrencySemaphore.limit} concurrent jobs max). ` +
888
+ `Try again later or increase behavior.concurrency.`);
889
+ }
890
+ try {
891
+ // Create job context
892
+ const context = this.createJobContext(job);
893
+ // Invoke handler
894
+ const result = await handler(job, context);
895
+ // SECURITY FIX (CRITICAL-2): Use ProofGenerator to create authenticated delivery proof
896
+ // This ensures the proof has proper structure with txId, contentHash, and timestamp
897
+ const proofGenerator = new ProofGenerator_1.ProofGenerator();
898
+ const deliverable = typeof result === 'string' ? result : JSON.stringify(result);
899
+ const deliveryProof = proofGenerator.generateDeliveryProof({
900
+ txId: job.id,
901
+ deliverable,
902
+ metadata: {
903
+ service: job.service,
904
+ completedAt: Date.now(),
905
+ },
906
+ });
907
+ // Encode proof with content hash for verification
908
+ const deliveryProofJson = JSON.stringify({
909
+ ...deliveryProof,
910
+ result, // Include original result for convenience
911
+ });
912
+ // Transition transaction to DELIVERED state
913
+ if (this._client) {
914
+ // Store delivery proof by directly accessing MockRuntime's state
915
+ // This is a workaround - in production, we'd use a proper method
916
+ const runtime = this._client.runtime;
917
+ if (runtime.stateManager) {
918
+ await runtime.stateManager.withLock(async (state) => {
919
+ const tx = state.transactions[job.id];
920
+ if (tx) {
921
+ tx.deliveryProof = deliveryProofJson;
922
+ }
923
+ });
924
+ }
925
+ // Transition to DELIVERED (escrow was already linked in pollForJobs)
926
+ await this._client.runtime.transitionState(job.id, 'DELIVERED');
927
+ }
928
+ // SECURITY FIX (C-2): Remove from active jobs on SUCCESS
929
+ this.activeJobs.delete(job.id);
930
+ // Update stats
931
+ this._stats.jobsCompleted++;
932
+ const duration = Date.now() - startTime;
933
+ this._stats.averageJobTime =
934
+ (this._stats.averageJobTime * (this._stats.jobsCompleted - 1) + duration) /
935
+ this._stats.jobsCompleted;
936
+ this._stats.successRate =
937
+ this._stats.jobsCompleted / (this._stats.jobsCompleted + this._stats.jobsFailed);
938
+ this._stats.totalEarned += job.budget;
939
+ // Emit events
940
+ this.logger.info('Job completed', {
941
+ jobId: job.id,
942
+ duration,
943
+ earned: job.budget,
944
+ });
945
+ this.emit('job:completed', job, result);
946
+ this.emit('payment:received', job.budget);
947
+ }
948
+ catch (error) {
949
+ // SECURITY FIX (C-2): Remove from active jobs on FAILURE
950
+ this.activeJobs.delete(job.id);
951
+ this._stats.jobsFailed++;
952
+ this._stats.successRate =
953
+ this._stats.jobsCompleted / (this._stats.jobsCompleted + this._stats.jobsFailed);
954
+ this.logger.error('Job failed', { jobId: job.id }, error);
955
+ this.emit('job:failed', job, error);
956
+ }
957
+ finally {
958
+ // SECURITY FIX (MEDIUM-4): Always release semaphore permit
959
+ this.concurrencySemaphore.release();
960
+ }
961
+ }
962
+ /**
963
+ * Create JobContext for handler execution
964
+ */
965
+ createJobContext(job) {
966
+ const state = new Map();
967
+ let cancelled = false;
968
+ const cancelHandlers = [];
969
+ const agent = this; // Capture 'this' for use in closures
970
+ return {
971
+ agent: agent,
972
+ progress(percent, message) {
973
+ // Emit progress event
974
+ agent.emit('job:progress', job.id, percent, message);
975
+ },
976
+ log: {
977
+ debug: (message, meta) => {
978
+ if (agent.config.logging?.level === 'debug') {
979
+ console.debug(`[${job.id}] ${message}`, meta);
980
+ }
981
+ },
982
+ info: (message, meta) => {
983
+ if (['debug', 'info'].includes(agent.config.logging?.level || 'info')) {
984
+ console.info(`[${job.id}] ${message}`, meta);
985
+ }
986
+ },
987
+ warn: (message, meta) => {
988
+ if (['debug', 'info', 'warn'].includes(agent.config.logging?.level || 'info')) {
989
+ console.warn(`[${job.id}] ${message}`, meta);
990
+ }
991
+ },
992
+ error: (message, meta) => {
993
+ console.error(`[${job.id}] ${message}`, meta);
994
+ },
995
+ },
996
+ state: {
997
+ get(key) {
998
+ return state.get(key);
999
+ },
1000
+ set(key, value) {
1001
+ state.set(key, value);
1002
+ },
1003
+ },
1004
+ get cancelled() {
1005
+ return cancelled;
1006
+ },
1007
+ onCancel(handler) {
1008
+ cancelHandlers.push(handler);
1009
+ },
1010
+ };
1011
+ }
1012
+ /**
1013
+ * Wait for active jobs to complete
1014
+ */
1015
+ async waitForActiveJobs(timeoutMs) {
1016
+ const startTime = Date.now();
1017
+ while (this.activeJobs.size > 0) {
1018
+ if (Date.now() - startTime > timeoutMs) {
1019
+ this.logger.warn('Active jobs still running after timeout', {
1020
+ activeJobs: this.activeJobs.size,
1021
+ });
1022
+ break;
1023
+ }
1024
+ await new Promise((resolve) => setTimeout(resolve, 100));
1025
+ }
1026
+ }
1027
+ /**
1028
+ * Generate address based on wallet configuration
1029
+ *
1030
+ * SECURITY FIX (HIGH): For testnet/mainnet, MUST derive from private key.
1031
+ * For mock mode, can use deterministic address for convenience.
1032
+ */
1033
+ generateAddress() {
1034
+ // If wallet has private key, ALWAYS derive address from it
1035
+ const privateKey = this.getPrivateKey();
1036
+ if (privateKey) {
1037
+ try {
1038
+ const wallet = new ethers_1.ethers.Wallet(privateKey);
1039
+ return wallet.address.toLowerCase();
1040
+ }
1041
+ catch (error) {
1042
+ throw new errors_1.ValidationError('wallet', 'Invalid private key format');
1043
+ }
1044
+ }
1045
+ // For non-mock networks, require a valid private key or address
1046
+ if (this.network === 'testnet' || this.network === 'mainnet') {
1047
+ throw new errors_1.ValidationError('wallet', `${this.network} mode requires a valid private key or address in wallet configuration`);
1048
+ }
1049
+ // For mock mode only: generate deterministic address from agent name
1050
+ // This is safe because mock mode doesn't involve real funds
1051
+ return `0x${Buffer.from(this.name).toString('hex').padEnd(40, '0').slice(0, 40)}`;
1052
+ }
1053
+ /**
1054
+ * Get private key from configuration
1055
+ *
1056
+ * SECURITY FIX (HIGH): Validate private key format before use
1057
+ */
1058
+ getPrivateKey() {
1059
+ if (!this.config.wallet || this.config.wallet === 'auto' || this.config.wallet === 'connect') {
1060
+ return undefined;
1061
+ }
1062
+ if (typeof this.config.wallet === 'string') {
1063
+ // Check if it looks like a private key (0x + 64 hex chars)
1064
+ if (/^0x[0-9a-fA-F]{64}$/.test(this.config.wallet)) {
1065
+ // Validate by trying to create a wallet
1066
+ try {
1067
+ new ethers_1.ethers.Wallet(this.config.wallet);
1068
+ return this.config.wallet;
1069
+ }
1070
+ catch {
1071
+ throw new errors_1.ValidationError('wallet', 'Invalid private key format');
1072
+ }
1073
+ }
1074
+ // It's an address, not a private key
1075
+ return undefined;
1076
+ }
1077
+ // Validate private key format
1078
+ if (this.config.wallet.privateKey) {
1079
+ try {
1080
+ new ethers_1.ethers.Wallet(this.config.wallet.privateKey);
1081
+ return this.config.wallet.privateKey;
1082
+ }
1083
+ catch {
1084
+ throw new errors_1.ValidationError('wallet.privateKey', 'Invalid private key format');
1085
+ }
1086
+ }
1087
+ return undefined;
1088
+ }
1089
+ }
1090
+ exports.Agent = Agent;
1091
+ //# sourceMappingURL=Agent.js.map