mppx 0.6.31 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/Challenge.d.ts.map +1 -1
  3. package/dist/Challenge.js +9 -7
  4. package/dist/Challenge.js.map +1 -1
  5. package/dist/Constants.d.ts +46 -0
  6. package/dist/Constants.d.ts.map +1 -0
  7. package/dist/Constants.js +46 -0
  8. package/dist/Constants.js.map +1 -0
  9. package/dist/Credential.d.ts.map +1 -1
  10. package/dist/Credential.js +5 -4
  11. package/dist/Credential.js.map +1 -1
  12. package/dist/Method.d.ts +32 -4
  13. package/dist/Method.d.ts.map +1 -1
  14. package/dist/Method.js +5 -2
  15. package/dist/Method.js.map +1 -1
  16. package/dist/Receipt.d.ts.map +1 -1
  17. package/dist/Receipt.js +3 -2
  18. package/dist/Receipt.js.map +1 -1
  19. package/dist/cli/cli.d.ts.map +1 -1
  20. package/dist/cli/cli.js +19 -11
  21. package/dist/cli/cli.js.map +1 -1
  22. package/dist/cli/plugins/tempo.d.ts.map +1 -1
  23. package/dist/cli/plugins/tempo.js +17 -6
  24. package/dist/cli/plugins/tempo.js.map +1 -1
  25. package/dist/cli/utils.d.ts +5 -0
  26. package/dist/cli/utils.d.ts.map +1 -1
  27. package/dist/cli/utils.js +10 -0
  28. package/dist/cli/utils.js.map +1 -1
  29. package/dist/client/Methods.d.ts +5 -2
  30. package/dist/client/Methods.d.ts.map +1 -1
  31. package/dist/client/Methods.js +5 -2
  32. package/dist/client/Methods.js.map +1 -1
  33. package/dist/client/Transport.d.ts.map +1 -1
  34. package/dist/client/Transport.js +4 -5
  35. package/dist/client/Transport.js.map +1 -1
  36. package/dist/client/index.d.ts +2 -1
  37. package/dist/client/index.d.ts.map +1 -1
  38. package/dist/client/index.js +2 -1
  39. package/dist/client/index.js.map +1 -1
  40. package/dist/client/internal/Fetch.d.ts.map +1 -1
  41. package/dist/client/internal/Fetch.js +14 -6
  42. package/dist/client/internal/Fetch.js.map +1 -1
  43. package/dist/evm/server/Methods.d.ts +1 -1
  44. package/dist/evm/server/Methods.d.ts.map +1 -1
  45. package/dist/index.d.ts +1 -0
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +1 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/internal/AcceptPayment.d.ts +3 -0
  50. package/dist/internal/AcceptPayment.d.ts.map +1 -1
  51. package/dist/internal/AcceptPayment.js +15 -11
  52. package/dist/internal/AcceptPayment.js.map +1 -1
  53. package/dist/mcp-sdk/client/McpClient.d.ts +12 -5
  54. package/dist/mcp-sdk/client/McpClient.d.ts.map +1 -1
  55. package/dist/mcp-sdk/client/McpClient.js +55 -42
  56. package/dist/mcp-sdk/client/McpClient.js.map +1 -1
  57. package/dist/server/Mppx.d.ts +11 -3
  58. package/dist/server/Mppx.d.ts.map +1 -1
  59. package/dist/server/Mppx.js +76 -27
  60. package/dist/server/Mppx.js.map +1 -1
  61. package/dist/server/Response.d.ts.map +1 -1
  62. package/dist/server/Response.js +2 -1
  63. package/dist/server/Response.js.map +1 -1
  64. package/dist/server/Transport.d.ts.map +1 -1
  65. package/dist/server/Transport.js +4 -3
  66. package/dist/server/Transport.js.map +1 -1
  67. package/dist/server/index.d.ts +1 -0
  68. package/dist/server/index.d.ts.map +1 -1
  69. package/dist/server/index.js +1 -0
  70. package/dist/server/index.js.map +1 -1
  71. package/dist/stripe/client/Charge.d.ts +1 -1
  72. package/dist/stripe/client/Charge.d.ts.map +1 -1
  73. package/dist/stripe/client/Charge.js +3 -1
  74. package/dist/stripe/client/Charge.js.map +1 -1
  75. package/dist/stripe/server/Charge.d.ts +1 -1
  76. package/dist/stripe/server/Charge.d.ts.map +1 -1
  77. package/dist/stripe/server/Charge.js +9 -2
  78. package/dist/stripe/server/Charge.js.map +1 -1
  79. package/dist/stripe/server/Methods.d.ts +1 -1
  80. package/dist/stripe/server/Methods.d.ts.map +1 -1
  81. package/dist/stripe/server/internal/html.gen.d.ts +1 -1
  82. package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
  83. package/dist/stripe/server/internal/html.gen.js +1 -1
  84. package/dist/stripe/server/internal/html.gen.js.map +1 -1
  85. package/dist/tempo/Methods.d.ts +18 -0
  86. package/dist/tempo/Methods.d.ts.map +1 -1
  87. package/dist/tempo/Methods.js +16 -1
  88. package/dist/tempo/Methods.js.map +1 -1
  89. package/dist/tempo/client/Charge.d.ts +6 -0
  90. package/dist/tempo/client/Charge.d.ts.map +1 -1
  91. package/dist/tempo/client/Charge.js +9 -2
  92. package/dist/tempo/client/Charge.js.map +1 -1
  93. package/dist/tempo/client/Methods.d.ts +36 -7
  94. package/dist/tempo/client/Methods.d.ts.map +1 -1
  95. package/dist/tempo/client/Methods.js +12 -5
  96. package/dist/tempo/client/Methods.js.map +1 -1
  97. package/dist/tempo/client/index.d.ts +7 -4
  98. package/dist/tempo/client/index.d.ts.map +1 -1
  99. package/dist/tempo/client/index.js +5 -3
  100. package/dist/tempo/client/index.js.map +1 -1
  101. package/dist/tempo/index.d.ts +1 -0
  102. package/dist/tempo/index.d.ts.map +1 -1
  103. package/dist/tempo/index.js +1 -0
  104. package/dist/tempo/index.js.map +1 -1
  105. package/dist/tempo/internal/fee-payer.d.ts +21 -1
  106. package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
  107. package/dist/tempo/internal/fee-payer.js +109 -4
  108. package/dist/tempo/internal/fee-payer.js.map +1 -1
  109. package/dist/tempo/{client → legacy/client}/ChannelOps.d.ts +19 -6
  110. package/dist/tempo/legacy/client/ChannelOps.d.ts.map +1 -0
  111. package/dist/tempo/{client → legacy/client}/ChannelOps.js +9 -3
  112. package/dist/tempo/legacy/client/ChannelOps.js.map +1 -0
  113. package/dist/tempo/{client → legacy/client}/Session.d.ts +23 -4
  114. package/dist/tempo/legacy/client/Session.d.ts.map +1 -0
  115. package/dist/tempo/{client → legacy/client}/Session.js +14 -7
  116. package/dist/tempo/legacy/client/Session.js.map +1 -0
  117. package/dist/tempo/{client → legacy/client}/SessionManager.d.ts +20 -5
  118. package/dist/tempo/legacy/client/SessionManager.d.ts.map +1 -0
  119. package/dist/tempo/{client → legacy/client}/SessionManager.js +20 -16
  120. package/dist/tempo/legacy/client/SessionManager.js.map +1 -0
  121. package/dist/tempo/legacy/client/index.d.ts +7 -0
  122. package/dist/tempo/legacy/client/index.d.ts.map +1 -0
  123. package/dist/tempo/legacy/client/index.js +5 -0
  124. package/dist/tempo/legacy/client/index.js.map +1 -0
  125. package/dist/tempo/legacy/index.d.ts +7 -0
  126. package/dist/tempo/legacy/index.d.ts.map +1 -0
  127. package/dist/tempo/legacy/index.js +7 -0
  128. package/dist/tempo/legacy/index.js.map +1 -0
  129. package/dist/tempo/{server → legacy/server}/Session.d.ts +28 -11
  130. package/dist/tempo/legacy/server/Session.d.ts.map +1 -0
  131. package/dist/tempo/{server → legacy/server}/Session.js +12 -10
  132. package/dist/tempo/legacy/server/Session.js.map +1 -0
  133. package/dist/tempo/legacy/server/index.d.ts +5 -0
  134. package/dist/tempo/legacy/server/index.d.ts.map +1 -0
  135. package/dist/tempo/legacy/server/index.js +5 -0
  136. package/dist/tempo/legacy/server/index.js.map +1 -0
  137. package/dist/tempo/{session → legacy/session}/Chain.d.ts +30 -23
  138. package/dist/tempo/legacy/session/Chain.d.ts.map +1 -0
  139. package/dist/tempo/{session → legacy/session}/Chain.js +12 -11
  140. package/dist/tempo/legacy/session/Chain.js.map +1 -0
  141. package/dist/tempo/{session → legacy/session}/Channel.d.ts +1 -0
  142. package/dist/tempo/legacy/session/Channel.d.ts.map +1 -0
  143. package/dist/tempo/legacy/session/Channel.js.map +1 -0
  144. package/dist/tempo/legacy/session/ChannelStore.d.ts +22 -0
  145. package/dist/tempo/legacy/session/ChannelStore.d.ts.map +1 -0
  146. package/dist/tempo/legacy/session/ChannelStore.js +6 -0
  147. package/dist/tempo/legacy/session/ChannelStore.js.map +1 -0
  148. package/dist/tempo/legacy/session/Types.d.ts +73 -0
  149. package/dist/tempo/legacy/session/Types.d.ts.map +1 -0
  150. package/dist/tempo/legacy/session/Types.js.map +1 -0
  151. package/dist/tempo/{session → legacy/session}/Voucher.d.ts +4 -4
  152. package/dist/tempo/legacy/session/Voucher.d.ts.map +1 -0
  153. package/dist/tempo/{session → legacy/session}/Voucher.js +1 -1
  154. package/dist/tempo/legacy/session/Voucher.js.map +1 -0
  155. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts +1 -0
  156. package/dist/tempo/{session → legacy/session}/escrow.abi.d.ts.map +1 -1
  157. package/dist/tempo/{session → legacy/session}/escrow.abi.js +1 -0
  158. package/dist/tempo/legacy/session/escrow.abi.js.map +1 -0
  159. package/dist/tempo/legacy/session/index.d.ts +9 -0
  160. package/dist/tempo/legacy/session/index.d.ts.map +1 -0
  161. package/dist/tempo/legacy/session/index.js +9 -0
  162. package/dist/tempo/legacy/session/index.js.map +1 -0
  163. package/dist/tempo/server/Charge.d.ts +1 -1
  164. package/dist/tempo/server/Charge.d.ts.map +1 -1
  165. package/dist/tempo/server/Charge.js +13 -16
  166. package/dist/tempo/server/Charge.js.map +1 -1
  167. package/dist/tempo/server/Methods.d.ts +63 -6
  168. package/dist/tempo/server/Methods.d.ts.map +1 -1
  169. package/dist/tempo/server/Methods.js +36 -8
  170. package/dist/tempo/server/Methods.js.map +1 -1
  171. package/dist/tempo/server/Subscription.d.ts +1 -1
  172. package/dist/tempo/server/Subscription.d.ts.map +1 -1
  173. package/dist/tempo/server/index.d.ts +6 -5
  174. package/dist/tempo/server/index.d.ts.map +1 -1
  175. package/dist/tempo/server/index.js +5 -5
  176. package/dist/tempo/server/index.js.map +1 -1
  177. package/dist/tempo/server/internal/html.gen.d.ts +1 -1
  178. package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
  179. package/dist/tempo/server/internal/html.gen.js +1 -1
  180. package/dist/tempo/server/internal/html.gen.js.map +1 -1
  181. package/dist/tempo/server/internal/request-body.d.ts +7 -2
  182. package/dist/tempo/server/internal/request-body.d.ts.map +1 -1
  183. package/dist/tempo/server/internal/request-body.js +20 -3
  184. package/dist/tempo/server/internal/request-body.js.map +1 -1
  185. package/dist/tempo/server/internal/transport.d.ts +8 -4
  186. package/dist/tempo/server/internal/transport.d.ts.map +1 -1
  187. package/dist/tempo/server/internal/transport.js +8 -7
  188. package/dist/tempo/server/internal/transport.js.map +1 -1
  189. package/dist/tempo/session/Snapshot.d.ts +32 -0
  190. package/dist/tempo/session/Snapshot.d.ts.map +1 -0
  191. package/dist/tempo/session/Snapshot.js +37 -0
  192. package/dist/tempo/session/Snapshot.js.map +1 -0
  193. package/dist/tempo/session/client/ChannelOps.d.ts +82 -0
  194. package/dist/tempo/session/client/ChannelOps.d.ts.map +1 -0
  195. package/dist/tempo/session/client/ChannelOps.js +204 -0
  196. package/dist/tempo/session/client/ChannelOps.js.map +1 -0
  197. package/dist/tempo/session/client/CredentialState.d.ts +262 -0
  198. package/dist/tempo/session/client/CredentialState.d.ts.map +1 -0
  199. package/dist/tempo/session/client/CredentialState.js +417 -0
  200. package/dist/tempo/session/client/CredentialState.js.map +1 -0
  201. package/dist/tempo/session/client/ReceiptCoordinator.d.ts +26 -0
  202. package/dist/tempo/session/client/ReceiptCoordinator.d.ts.map +1 -0
  203. package/dist/tempo/session/client/ReceiptCoordinator.js +61 -0
  204. package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -0
  205. package/dist/tempo/session/client/Runtime.d.ts +464 -0
  206. package/dist/tempo/session/client/Runtime.d.ts.map +1 -0
  207. package/dist/tempo/session/client/Runtime.js +499 -0
  208. package/dist/tempo/session/client/Runtime.js.map +1 -0
  209. package/dist/tempo/session/client/Session.d.ts +132 -0
  210. package/dist/tempo/session/client/Session.d.ts.map +1 -0
  211. package/dist/tempo/session/client/Session.js +55 -0
  212. package/dist/tempo/session/client/Session.js.map +1 -0
  213. package/dist/tempo/session/client/SessionManager.d.ts +120 -0
  214. package/dist/tempo/session/client/SessionManager.d.ts.map +1 -0
  215. package/dist/tempo/session/client/SessionManager.js +627 -0
  216. package/dist/tempo/session/client/SessionManager.js.map +1 -0
  217. package/dist/tempo/session/client/Transports.d.ts +449 -0
  218. package/dist/tempo/session/client/Transports.d.ts.map +1 -0
  219. package/dist/tempo/session/client/Transports.js +721 -0
  220. package/dist/tempo/session/client/Transports.js.map +1 -0
  221. package/dist/tempo/session/client/index.d.ts +12 -0
  222. package/dist/tempo/session/client/index.d.ts.map +1 -0
  223. package/dist/tempo/session/client/index.js +5 -0
  224. package/dist/tempo/session/client/index.js.map +1 -0
  225. package/dist/tempo/session/index.d.ts +7 -8
  226. package/dist/tempo/session/index.d.ts.map +1 -1
  227. package/dist/tempo/session/index.js +7 -8
  228. package/dist/tempo/session/index.js.map +1 -1
  229. package/dist/tempo/session/precompile/Chain.d.ts +319 -0
  230. package/dist/tempo/session/precompile/Chain.d.ts.map +1 -0
  231. package/dist/tempo/session/precompile/Chain.js +492 -0
  232. package/dist/tempo/session/precompile/Chain.js.map +1 -0
  233. package/dist/tempo/session/precompile/Channel.d.ts +46 -0
  234. package/dist/tempo/session/precompile/Channel.d.ts.map +1 -0
  235. package/dist/tempo/session/precompile/Channel.js +56 -0
  236. package/dist/tempo/session/precompile/Channel.js.map +1 -0
  237. package/dist/tempo/session/precompile/Protocol.d.ts +308 -0
  238. package/dist/tempo/session/precompile/Protocol.d.ts.map +1 -0
  239. package/dist/tempo/session/precompile/Protocol.js +264 -0
  240. package/dist/tempo/session/precompile/Protocol.js.map +1 -0
  241. package/dist/tempo/session/precompile/Voucher.d.ts +40 -0
  242. package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -0
  243. package/dist/tempo/session/precompile/Voucher.js +126 -0
  244. package/dist/tempo/session/precompile/Voucher.js.map +1 -0
  245. package/dist/tempo/session/precompile/escrow.abi.d.ts +522 -0
  246. package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -0
  247. package/dist/tempo/session/precompile/escrow.abi.js +224 -0
  248. package/dist/tempo/session/precompile/escrow.abi.js.map +1 -0
  249. package/dist/tempo/session/precompile/index.d.ts +24 -0
  250. package/dist/tempo/session/precompile/index.d.ts.map +1 -0
  251. package/dist/tempo/session/precompile/index.js +22 -0
  252. package/dist/tempo/session/precompile/index.js.map +1 -0
  253. package/dist/tempo/session/server/ChannelOps.d.ts +56 -0
  254. package/dist/tempo/session/server/ChannelOps.d.ts.map +1 -0
  255. package/dist/tempo/session/server/ChannelOps.js +91 -0
  256. package/dist/tempo/session/server/ChannelOps.js.map +1 -0
  257. package/dist/tempo/session/server/ChannelStore.d.ts +347 -0
  258. package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -0
  259. package/dist/tempo/session/server/ChannelStore.js +404 -0
  260. package/dist/tempo/session/server/ChannelStore.js.map +1 -0
  261. package/dist/tempo/session/server/CredentialVerification.d.ts +85 -0
  262. package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -0
  263. package/dist/tempo/session/server/CredentialVerification.js +494 -0
  264. package/dist/tempo/session/server/CredentialVerification.js.map +1 -0
  265. package/dist/tempo/session/server/MeteredStream.d.ts +40 -0
  266. package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -0
  267. package/dist/tempo/session/server/MeteredStream.js +42 -0
  268. package/dist/tempo/session/server/MeteredStream.js.map +1 -0
  269. package/dist/tempo/session/server/RequestState.d.ts +208 -0
  270. package/dist/tempo/session/server/RequestState.d.ts.map +1 -0
  271. package/dist/tempo/session/server/RequestState.js +252 -0
  272. package/dist/tempo/session/server/RequestState.js.map +1 -0
  273. package/dist/tempo/session/server/Session.d.ts +169 -0
  274. package/dist/tempo/session/server/Session.d.ts.map +1 -0
  275. package/dist/tempo/session/server/Session.js +351 -0
  276. package/dist/tempo/session/server/Session.js.map +1 -0
  277. package/dist/tempo/session/server/Settlement.d.ts +185 -0
  278. package/dist/tempo/session/server/Settlement.d.ts.map +1 -0
  279. package/dist/tempo/session/server/Settlement.js +250 -0
  280. package/dist/tempo/session/server/Settlement.js.map +1 -0
  281. package/dist/tempo/session/{Sse.d.ts → server/Sse.d.ts} +9 -56
  282. package/dist/tempo/session/server/Sse.d.ts.map +1 -0
  283. package/dist/tempo/session/server/Sse.js +184 -0
  284. package/dist/tempo/session/server/Sse.js.map +1 -0
  285. package/dist/tempo/session/server/Transports.d.ts +89 -0
  286. package/dist/tempo/session/server/Transports.d.ts.map +1 -0
  287. package/dist/tempo/session/server/Transports.js +149 -0
  288. package/dist/tempo/session/server/Transports.js.map +1 -0
  289. package/dist/tempo/session/server/Ws.d.ts +48 -0
  290. package/dist/tempo/session/server/Ws.d.ts.map +1 -0
  291. package/dist/tempo/session/server/Ws.js +244 -0
  292. package/dist/tempo/session/server/Ws.js.map +1 -0
  293. package/dist/tempo/session/server/index.d.ts +4 -0
  294. package/dist/tempo/session/server/index.d.ts.map +1 -0
  295. package/dist/tempo/session/server/index.js +2 -0
  296. package/dist/tempo/session/server/index.js.map +1 -0
  297. package/package.json +6 -1
  298. package/src/Challenge.ts +9 -7
  299. package/src/Constants.ts +58 -0
  300. package/src/Credential.ts +5 -4
  301. package/src/Method.ts +46 -5
  302. package/src/Receipt.ts +3 -2
  303. package/src/cli/cli.test.ts +23 -28
  304. package/src/cli/cli.ts +23 -10
  305. package/src/cli/mcp.test.ts +21 -7
  306. package/src/cli/plugins/tempo.ts +21 -8
  307. package/src/cli/utils.test.ts +25 -1
  308. package/src/cli/utils.ts +10 -0
  309. package/src/client/Methods.ts +5 -2
  310. package/src/client/Mppx.test-d.ts +10 -0
  311. package/src/client/Mppx.test.ts +75 -0
  312. package/src/client/Transport.ts +4 -5
  313. package/src/client/index.ts +11 -1
  314. package/src/client/internal/Fetch.test.ts +29 -4
  315. package/src/client/internal/Fetch.ts +17 -5
  316. package/src/env.d.ts +1 -1
  317. package/src/index.ts +1 -0
  318. package/src/internal/AcceptPayment.test.ts +61 -0
  319. package/src/internal/AcceptPayment.ts +21 -14
  320. package/src/mcp-sdk/client/McpClient.integration.test.ts +8 -7
  321. package/src/mcp-sdk/client/McpClient.test-d.ts +7 -0
  322. package/src/mcp-sdk/client/McpClient.ts +99 -67
  323. package/src/mcp-sdk/client/McpClient.unit.test.ts +131 -0
  324. package/src/middlewares/elysia.test.ts +8 -4
  325. package/src/middlewares/express.test.ts +8 -4
  326. package/src/middlewares/hono.test.ts +4 -4
  327. package/src/middlewares/nextjs.test.ts +8 -4
  328. package/src/proxy/Proxy.test.ts +8 -8
  329. package/src/server/Mppx.test-d.ts +54 -0
  330. package/src/server/Mppx.test.ts +200 -7
  331. package/src/server/Mppx.ts +487 -406
  332. package/src/server/Response.ts +2 -1
  333. package/src/server/Transport.ts +4 -3
  334. package/src/server/index.ts +1 -0
  335. package/src/stripe/client/Charge.test.ts +20 -5
  336. package/src/stripe/client/Charge.ts +6 -2
  337. package/src/stripe/server/Charge.test.ts +114 -1
  338. package/src/stripe/server/Charge.ts +13 -2
  339. package/src/stripe/server/internal/html.gen.ts +1 -1
  340. package/src/tempo/AccessKeyAuthorization.test.ts +4 -94
  341. package/src/tempo/Methods.test.ts +45 -17
  342. package/src/tempo/Methods.ts +22 -0
  343. package/src/tempo/PublicExports.test-d.ts +105 -0
  344. package/src/tempo/client/Charge.test.ts +85 -0
  345. package/src/tempo/client/Charge.ts +19 -2
  346. package/src/tempo/client/Methods.ts +18 -6
  347. package/src/tempo/client/index.ts +15 -4
  348. package/src/tempo/index.ts +1 -0
  349. package/src/tempo/internal/fee-payer.test.ts +241 -17
  350. package/src/tempo/internal/fee-payer.ts +150 -4
  351. package/src/tempo/internal/fee-token.test.ts +14 -9
  352. package/src/tempo/legacy/AccessKeyAuthorization.test.ts +162 -0
  353. package/src/tempo/legacy/README.md +9 -0
  354. package/src/tempo/{client → legacy/client}/ChannelOps.test.ts +6 -7
  355. package/src/tempo/{client → legacy/client}/ChannelOps.ts +22 -9
  356. package/src/tempo/{client → legacy/client}/Session.test.ts +51 -9
  357. package/src/tempo/{client → legacy/client}/Session.ts +25 -11
  358. package/src/tempo/{client → legacy/client}/SessionManager.test.ts +81 -9
  359. package/src/tempo/{client → legacy/client}/SessionManager.ts +41 -20
  360. package/src/tempo/legacy/client/index.ts +6 -0
  361. package/src/tempo/legacy/index.ts +6 -0
  362. package/src/tempo/{server → legacy/server}/Session.test.ts +45 -45
  363. package/src/tempo/{server → legacy/server}/Session.ts +32 -23
  364. package/src/tempo/legacy/server/index.ts +4 -0
  365. package/src/tempo/{session → legacy/session}/Chain.test.ts +3 -4
  366. package/src/tempo/{session → legacy/session}/Chain.ts +94 -63
  367. package/src/tempo/{session → legacy/session}/Channel.ts +1 -0
  368. package/src/tempo/legacy/session/ChannelStore.test.ts +58 -0
  369. package/src/tempo/legacy/session/ChannelStore.ts +39 -0
  370. package/src/tempo/legacy/session/Types.ts +91 -0
  371. package/src/tempo/{session → legacy/session}/Voucher.ts +12 -8
  372. package/src/tempo/{session → legacy/session}/escrow.abi.ts +1 -0
  373. package/src/tempo/legacy/session/index.ts +8 -0
  374. package/src/tempo/server/AtomicStore.test-d.ts +16 -11
  375. package/src/tempo/server/Charge.test.ts +92 -14
  376. package/src/tempo/server/Charge.ts +18 -16
  377. package/src/tempo/server/Methods.ts +54 -8
  378. package/src/tempo/server/Sse.test.ts +2 -2
  379. package/src/tempo/server/index.ts +6 -5
  380. package/src/tempo/server/internal/html.gen.ts +1 -1
  381. package/src/tempo/server/internal/request-body.test.ts +37 -4
  382. package/src/tempo/server/internal/request-body.ts +25 -6
  383. package/src/tempo/server/internal/transport.test.ts +4 -4
  384. package/src/tempo/server/internal/transport.ts +19 -10
  385. package/src/tempo/session/Snapshot.test.ts +41 -0
  386. package/src/tempo/session/Snapshot.ts +74 -0
  387. package/src/tempo/session/client/ChannelOps.test.ts +163 -0
  388. package/src/tempo/session/client/ChannelOps.ts +344 -0
  389. package/src/tempo/session/client/CredentialState.test.ts +645 -0
  390. package/src/tempo/session/client/CredentialState.ts +814 -0
  391. package/src/tempo/session/client/ReceiptCoordinator.ts +95 -0
  392. package/src/tempo/session/client/Runtime.test.ts +1092 -0
  393. package/src/tempo/session/client/Runtime.ts +986 -0
  394. package/src/tempo/session/client/Session.test.ts +734 -0
  395. package/src/tempo/session/client/Session.ts +97 -0
  396. package/src/tempo/session/client/SessionManager.test.ts +1308 -0
  397. package/src/tempo/session/client/SessionManager.ts +845 -0
  398. package/src/tempo/session/client/Transports.test.ts +837 -0
  399. package/src/tempo/session/client/Transports.ts +1292 -0
  400. package/src/tempo/session/client/index.ts +37 -0
  401. package/src/tempo/session/index.ts +7 -8
  402. package/src/tempo/session/precompile/Chain.integration.test.ts +321 -0
  403. package/src/tempo/session/precompile/Chain.test.ts +1258 -0
  404. package/src/tempo/session/precompile/Chain.ts +979 -0
  405. package/src/tempo/session/precompile/Channel.test.ts +138 -0
  406. package/src/tempo/session/precompile/Channel.ts +103 -0
  407. package/src/tempo/session/precompile/Protocol.test.ts +358 -0
  408. package/src/tempo/session/precompile/Protocol.ts +520 -0
  409. package/src/tempo/session/precompile/Voucher.test.ts +316 -0
  410. package/src/tempo/session/precompile/Voucher.ts +160 -0
  411. package/src/tempo/session/precompile/escrow.abi.ts +226 -0
  412. package/src/tempo/session/precompile/index.ts +33 -0
  413. package/src/tempo/session/server/ChannelOps.test.ts +129 -0
  414. package/src/tempo/session/server/ChannelOps.ts +157 -0
  415. package/src/tempo/session/{ChannelStore.test.ts → server/ChannelStore.test.ts} +536 -29
  416. package/src/tempo/session/server/ChannelStore.ts +835 -0
  417. package/src/tempo/session/server/CredentialVerification.test.ts +146 -0
  418. package/src/tempo/session/server/CredentialVerification.ts +710 -0
  419. package/src/tempo/session/server/MeteredStream.ts +88 -0
  420. package/src/tempo/session/server/RequestState.test.ts +531 -0
  421. package/src/tempo/session/server/RequestState.ts +499 -0
  422. package/src/tempo/session/server/Session.integration.test.ts +444 -0
  423. package/src/tempo/session/server/Session.test.ts +3253 -0
  424. package/src/tempo/session/server/Session.ts +543 -0
  425. package/src/tempo/session/server/Settlement.test.ts +242 -0
  426. package/src/tempo/session/server/Settlement.ts +470 -0
  427. package/src/tempo/session/{Sse.test.ts → server/Sse.test.ts} +37 -3
  428. package/src/tempo/session/server/Sse.ts +256 -0
  429. package/src/tempo/session/server/Transports.test.ts +346 -0
  430. package/src/tempo/session/server/Transports.ts +255 -0
  431. package/src/tempo/session/{Ws.test.ts → server/Ws.test.ts} +4 -4
  432. package/src/tempo/session/server/Ws.ts +384 -0
  433. package/src/tempo/session/server/index.ts +8 -0
  434. package/dist/tempo/client/ChannelOps.d.ts.map +0 -1
  435. package/dist/tempo/client/ChannelOps.js.map +0 -1
  436. package/dist/tempo/client/Session.d.ts.map +0 -1
  437. package/dist/tempo/client/Session.js.map +0 -1
  438. package/dist/tempo/client/SessionManager.d.ts.map +0 -1
  439. package/dist/tempo/client/SessionManager.js.map +0 -1
  440. package/dist/tempo/server/Session.d.ts.map +0 -1
  441. package/dist/tempo/server/Session.js.map +0 -1
  442. package/dist/tempo/session/Chain.d.ts.map +0 -1
  443. package/dist/tempo/session/Chain.js.map +0 -1
  444. package/dist/tempo/session/Channel.d.ts.map +0 -1
  445. package/dist/tempo/session/Channel.js.map +0 -1
  446. package/dist/tempo/session/ChannelStore.d.ts +0 -117
  447. package/dist/tempo/session/ChannelStore.d.ts.map +0 -1
  448. package/dist/tempo/session/ChannelStore.js +0 -172
  449. package/dist/tempo/session/ChannelStore.js.map +0 -1
  450. package/dist/tempo/session/Receipt.d.ts +0 -22
  451. package/dist/tempo/session/Receipt.d.ts.map +0 -1
  452. package/dist/tempo/session/Receipt.js +0 -34
  453. package/dist/tempo/session/Receipt.js.map +0 -1
  454. package/dist/tempo/session/Sse.d.ts.map +0 -1
  455. package/dist/tempo/session/Sse.js +0 -363
  456. package/dist/tempo/session/Sse.js.map +0 -1
  457. package/dist/tempo/session/Types.d.ts +0 -78
  458. package/dist/tempo/session/Types.d.ts.map +0 -1
  459. package/dist/tempo/session/Types.js.map +0 -1
  460. package/dist/tempo/session/Voucher.d.ts.map +0 -1
  461. package/dist/tempo/session/Voucher.js.map +0 -1
  462. package/dist/tempo/session/Ws.d.ts +0 -87
  463. package/dist/tempo/session/Ws.d.ts.map +0 -1
  464. package/dist/tempo/session/Ws.js +0 -443
  465. package/dist/tempo/session/Ws.js.map +0 -1
  466. package/dist/tempo/session/escrow.abi.js.map +0 -1
  467. package/src/tempo/session/ChannelStore.ts +0 -308
  468. package/src/tempo/session/Receipt.test.ts +0 -89
  469. package/src/tempo/session/Receipt.ts +0 -46
  470. package/src/tempo/session/Sse.ts +0 -462
  471. package/src/tempo/session/Types.ts +0 -86
  472. package/src/tempo/session/Ws.ts +0 -576
  473. /package/dist/tempo/{session → legacy/session}/Channel.js +0 -0
  474. /package/dist/tempo/{session → legacy/session}/Types.js +0 -0
  475. /package/src/tempo/{session → legacy/session}/Channel.test.ts +0 -0
  476. /package/src/tempo/{session → legacy/session}/Voucher.test.ts +0 -0
  477. /package/src/tempo/session/{Sse.fuzz.test.ts → server/Sse.fuzz.test.ts} +0 -0
@@ -1,11 +1,16 @@
1
- import { encodeFunctionData, maxUint256 } from 'viem'
2
- import { Abis, Addresses } from 'viem/tempo'
3
- import { describe, expect, test } from 'vp/test'
1
+ import { encodeFunctionData, maxUint256, toHex } from 'viem'
2
+ import { Abis, Addresses, Transaction } from 'viem/tempo'
3
+ import { afterEach, describe, expect, test, vi } from 'vp/test'
4
4
 
5
+ import * as defaults from './defaults.js'
5
6
  import {
7
+ assertAllowedFeeToken,
6
8
  callScopes,
9
+ defaultAllowedFeeTokens,
7
10
  FeePayerValidationError,
11
+ fillHostedFeePayerTransaction,
8
12
  prepareSponsoredTransaction,
13
+ simulationTransaction,
9
14
  validateCalls,
10
15
  } from './fee-payer.js'
11
16
  import * as Selectors from './selectors.js'
@@ -19,8 +24,17 @@ const swapData = encodeFunctionData({
19
24
  functionName: 'swapExactAmountOut',
20
25
  args: [swapTokenIn, swapTokenOut, 100n, 100n],
21
26
  })
27
+ const feePayerSignature = {
28
+ r: '0x0000000000000000000000000000000000000000000000000000000000000002',
29
+ s: '0x0000000000000000000000000000000000000000000000000000000000000003',
30
+ yParity: 1,
31
+ }
22
32
  const sponsor = { address: bogus, type: 'local' } as any
23
33
 
34
+ afterEach(() => {
35
+ vi.unstubAllGlobals()
36
+ })
37
+
24
38
  describe('callScopes', () => {
25
39
  test('has 4 allowed patterns', () => {
26
40
  expect(callScopes).toHaveLength(4)
@@ -423,6 +437,216 @@ describe('validateCalls', () => {
423
437
  })
424
438
  })
425
439
 
440
+ describe('fee token allowlist', () => {
441
+ test('includes pathUSD and the chain default currency', () => {
442
+ expect(defaultAllowedFeeTokens(defaults.chainId.mainnet)).toEqual([
443
+ defaults.tokens.pathUsd,
444
+ defaults.tokens.usdc,
445
+ ])
446
+ })
447
+
448
+ test('dedupes when pathUSD is the chain default currency', () => {
449
+ expect(defaultAllowedFeeTokens(defaults.chainId.testnet)).toEqual([defaults.tokens.pathUsd])
450
+ })
451
+
452
+ test('accepts allowlisted fee tokens', () => {
453
+ expect(() =>
454
+ assertAllowedFeeToken(
455
+ { feeToken: defaults.tokens.usdc },
456
+ defaultAllowedFeeTokens(defaults.chainId.mainnet),
457
+ ),
458
+ ).not.toThrow()
459
+ })
460
+
461
+ test('error: rejects non-string fee tokens', () => {
462
+ expect(() =>
463
+ assertAllowedFeeToken({ feeToken: 1n }, defaultAllowedFeeTokens(defaults.chainId.mainnet)),
464
+ ).toThrow('feeToken is invalid')
465
+ })
466
+
467
+ test('error: rejects fee tokens outside the allowlist', () => {
468
+ expect(() =>
469
+ assertAllowedFeeToken(
470
+ { feeToken: swapTokenIn },
471
+ defaultAllowedFeeTokens(defaults.chainId.mainnet),
472
+ ),
473
+ ).toThrow('feeToken is not allowed')
474
+ })
475
+ })
476
+
477
+ describe('fillHostedFeePayerTransaction', () => {
478
+ const hostedTransaction = {
479
+ accessList: [],
480
+ calls: [
481
+ {
482
+ data: encodeFunctionData({
483
+ abi: Abis.tip20,
484
+ functionName: 'transfer',
485
+ args: [bogus, 100n],
486
+ }),
487
+ to: bogus,
488
+ },
489
+ ],
490
+ chainId: defaults.chainId.mainnet,
491
+ from: bogus,
492
+ gas: 150_000n,
493
+ maxFeePerGas: 1_000_000_000n,
494
+ maxPriorityFeePerGas: 0n,
495
+ nonce: 1n,
496
+ nonceKey: maxUint256,
497
+ signature: { r: 1n, s: 1n, yParity: 0 } as any,
498
+ validBefore: Math.floor(Date.now() / 1_000) + 300,
499
+ } as const
500
+
501
+ test('uses hosted fillTransaction and preserves sender-committed fields', async () => {
502
+ const calls: { init?: RequestInit | undefined; input: RequestInfo | URL }[] = []
503
+ const fetchMock = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
504
+ calls.push({ init, input })
505
+ return new Response(
506
+ JSON.stringify({
507
+ result: {
508
+ tx: {
509
+ feePayerSignature,
510
+ feeToken: defaults.tokens.pathUsd,
511
+ gas: '0x1',
512
+ maxFeePerGas: '0x2',
513
+ },
514
+ },
515
+ }),
516
+ )
517
+ })
518
+ vi.stubGlobal('fetch', fetchMock)
519
+
520
+ const serialized = await fillHostedFeePayerTransaction({
521
+ allowedFeeTokens: defaultAllowedFeeTokens(defaults.chainId.mainnet),
522
+ transaction: hostedTransaction as any,
523
+ url: 'https://sponsor.example/tp_key',
524
+ })
525
+
526
+ expect(fetchMock).toHaveBeenCalledOnce()
527
+ expect(calls[0]!.input).toBe('https://sponsor.example/tp_key')
528
+ const body = JSON.parse(calls[0]!.init!.body as string)
529
+ expect(body).toMatchObject({
530
+ jsonrpc: '2.0',
531
+ method: 'eth_fillTransaction',
532
+ })
533
+ expect(body.params[0]).toMatchObject({
534
+ calls: hostedTransaction.calls.map((call) => ({
535
+ data: call.data,
536
+ to: call.to,
537
+ value: '0x',
538
+ })),
539
+ feePayer: true,
540
+ from: hostedTransaction.from,
541
+ gas: toHex(hostedTransaction.gas),
542
+ maxFeePerGas: toHex(hostedTransaction.maxFeePerGas),
543
+ maxPriorityFeePerGas: toHex(hostedTransaction.maxPriorityFeePerGas),
544
+ nonce: toHex(hostedTransaction.nonce),
545
+ nonceKey: toHex(hostedTransaction.nonceKey),
546
+ type: '0x76',
547
+ validBefore: toHex(hostedTransaction.validBefore),
548
+ })
549
+
550
+ const transaction: Transaction.TransactionSerializableTempo = Transaction.deserialize(
551
+ serialized as Transaction.TransactionSerializedTempo,
552
+ )
553
+ expect(transaction.gas).toBe(hostedTransaction.gas)
554
+ expect(transaction.maxFeePerGas).toBe(hostedTransaction.maxFeePerGas)
555
+ expect(transaction.calls).toEqual(hostedTransaction.calls)
556
+ expect(transaction.feeToken).toBe(defaults.tokens.pathUsd)
557
+ expect(transaction.feePayerSignature).toEqual(feePayerSignature)
558
+ })
559
+
560
+ test('error: requires hosted fee payer to return a feeToken', async () => {
561
+ vi.stubGlobal(
562
+ 'fetch',
563
+ vi.fn(async () => new Response(JSON.stringify({ result: { tx: { feePayerSignature } } }))),
564
+ )
565
+
566
+ await expect(
567
+ fillHostedFeePayerTransaction({
568
+ allowedFeeTokens: defaultAllowedFeeTokens(defaults.chainId.mainnet),
569
+ transaction: hostedTransaction as any,
570
+ url: 'https://sponsor.example/tp_key',
571
+ }),
572
+ ).rejects.toThrow('did not return a feeToken')
573
+ })
574
+
575
+ test('error: rejects hosted feeToken outside the allowlist', async () => {
576
+ vi.stubGlobal(
577
+ 'fetch',
578
+ vi.fn(
579
+ async () =>
580
+ new Response(
581
+ JSON.stringify({
582
+ result: { tx: { feePayerSignature, feeToken: swapTokenIn } },
583
+ }),
584
+ ),
585
+ ),
586
+ )
587
+
588
+ await expect(
589
+ fillHostedFeePayerTransaction({
590
+ allowedFeeTokens: defaultAllowedFeeTokens(defaults.chainId.mainnet),
591
+ transaction: hostedTransaction as any,
592
+ url: 'https://sponsor.example/tp_key',
593
+ }),
594
+ ).rejects.toThrow('feeToken is not allowed')
595
+ })
596
+
597
+ test('error: surfaces hosted fee payer errors', async () => {
598
+ vi.stubGlobal(
599
+ 'fetch',
600
+ vi.fn(
601
+ async () =>
602
+ new Response(JSON.stringify({ error: { message: 'Invalid or revoked API key' } }), {
603
+ status: 401,
604
+ }),
605
+ ),
606
+ )
607
+
608
+ await expect(
609
+ fillHostedFeePayerTransaction({
610
+ allowedFeeTokens: defaultAllowedFeeTokens(defaults.chainId.mainnet),
611
+ transaction: hostedTransaction as any,
612
+ url: 'https://sponsor.example/tp_key',
613
+ }),
614
+ ).rejects.toThrow('Invalid or revoked API key')
615
+ })
616
+ })
617
+
618
+ describe('simulationTransaction', () => {
619
+ test('strips signed fee-payer fields for sponsored preflight simulation', () => {
620
+ const transaction = {
621
+ calls: [{ to: bogus }],
622
+ feePayerSignature,
623
+ from: bogus,
624
+ }
625
+
626
+ expect(simulationTransaction(transaction as any, { feePayer: true })).toEqual({
627
+ account: bogus,
628
+ calls: transaction.calls,
629
+ })
630
+ })
631
+
632
+ test('preserves non-sponsored transaction fields except feePayerSignature', () => {
633
+ const transaction = {
634
+ calls: [{ to: bogus }],
635
+ feePayerSignature,
636
+ from: bogus,
637
+ gas: 1n,
638
+ }
639
+
640
+ expect(simulationTransaction(transaction as any, { feePayer: false })).toEqual({
641
+ account: bogus,
642
+ calls: transaction.calls,
643
+ from: bogus,
644
+ gas: 1n,
645
+ feePayerSignature: undefined,
646
+ })
647
+ })
648
+ })
649
+
426
650
  describe('prepareSponsoredTransaction', () => {
427
651
  const baseTransaction = {
428
652
  accessList: [],
@@ -454,7 +678,7 @@ describe('prepareSponsoredTransaction', () => {
454
678
  account: sponsor,
455
679
  chainId: 42431,
456
680
  details,
457
- expectedFeeToken: bogus,
681
+ allowedFeeTokens: [bogus],
458
682
  transaction: baseTransaction as any,
459
683
  }),
460
684
  ).not.toThrow()
@@ -466,7 +690,7 @@ describe('prepareSponsoredTransaction', () => {
466
690
  account: sponsor,
467
691
  chainId: 42431,
468
692
  details,
469
- expectedFeeToken: bogus,
693
+ allowedFeeTokens: [bogus],
470
694
  transaction: {
471
695
  ...baseTransaction,
472
696
  nonceKey: maxUint256,
@@ -481,7 +705,7 @@ describe('prepareSponsoredTransaction', () => {
481
705
  account: sponsor,
482
706
  chainId: 42431,
483
707
  details,
484
- expectedFeeToken: bogus,
708
+ allowedFeeTokens: [bogus],
485
709
  transaction: {
486
710
  ...baseTransaction,
487
711
  nonceKey: 1n,
@@ -496,7 +720,7 @@ describe('prepareSponsoredTransaction', () => {
496
720
  account: sponsor,
497
721
  chainId: 42431,
498
722
  details,
499
- expectedFeeToken: bogus,
723
+ allowedFeeTokens: [bogus],
500
724
  transaction: {
501
725
  ...baseTransaction,
502
726
  gas: 626_497n,
@@ -513,7 +737,7 @@ describe('prepareSponsoredTransaction', () => {
513
737
  account: sponsor,
514
738
  chainId: 4217,
515
739
  details,
516
- expectedFeeToken: bogus,
740
+ allowedFeeTokens: [bogus],
517
741
  policy: { maxPriorityFeePerGas: 50_000_000_000n },
518
742
  transaction: {
519
743
  ...baseTransaction,
@@ -532,7 +756,7 @@ describe('prepareSponsoredTransaction', () => {
532
756
  account: sponsor,
533
757
  chainId: 4217,
534
758
  details,
535
- expectedFeeToken: bogus,
759
+ allowedFeeTokens: [bogus],
536
760
  policy: { maxPriorityFeePerGas: 20_000_000_000n },
537
761
  transaction: {
538
762
  ...baseTransaction,
@@ -551,7 +775,7 @@ describe('prepareSponsoredTransaction', () => {
551
775
  account: sponsor,
552
776
  chainId: 4217,
553
777
  details,
554
- expectedFeeToken: bogus,
778
+ allowedFeeTokens: [bogus],
555
779
  policy: { maxPriorityFeePerGas: undefined } as any,
556
780
  transaction: {
557
781
  ...baseTransaction,
@@ -578,7 +802,7 @@ describe('prepareSponsoredTransaction', () => {
578
802
  account: sponsor,
579
803
  chainId: 42431,
580
804
  details,
581
- expectedFeeToken: bogus,
805
+ allowedFeeTokens: [bogus],
582
806
  transaction: { ...baseTransaction, keyAuthorization } as any,
583
807
  }) as { keyAuthorization?: unknown }
584
808
 
@@ -591,7 +815,7 @@ describe('prepareSponsoredTransaction', () => {
591
815
  account: sponsor,
592
816
  chainId: 42431,
593
817
  details,
594
- expectedFeeToken: bogus,
818
+ allowedFeeTokens: [bogus],
595
819
  transaction: { ...baseTransaction, unexpectedField: 'ignored' } as any,
596
820
  }),
597
821
  ).toThrow('contains unsupported fields')
@@ -603,7 +827,7 @@ describe('prepareSponsoredTransaction', () => {
603
827
  account: sponsor,
604
828
  chainId: 42431,
605
829
  details,
606
- expectedFeeToken: bogus,
830
+ allowedFeeTokens: [bogus],
607
831
  transaction: {
608
832
  ...baseTransaction,
609
833
  feePayerSignature: { r: 2n, s: 3n, yParity: 1 },
@@ -618,7 +842,7 @@ describe('prepareSponsoredTransaction', () => {
618
842
  account: sponsor,
619
843
  chainId: 42431,
620
844
  details,
621
- expectedFeeToken: bogus,
845
+ allowedFeeTokens: [bogus],
622
846
  transaction: {
623
847
  ...baseTransaction,
624
848
  maxFeePerGas: 200_000_000_000n,
@@ -633,7 +857,7 @@ describe('prepareSponsoredTransaction', () => {
633
857
  account: sponsor,
634
858
  chainId: 42431,
635
859
  details,
636
- expectedFeeToken: bogus,
860
+ allowedFeeTokens: [bogus],
637
861
  transaction: {
638
862
  ...baseTransaction,
639
863
  gas: 1_500_000n,
@@ -649,7 +873,7 @@ describe('prepareSponsoredTransaction', () => {
649
873
  account: sponsor,
650
874
  chainId: 42431,
651
875
  details,
652
- expectedFeeToken: '0x0000000000000000000000000000000000000002',
876
+ allowedFeeTokens: ['0x0000000000000000000000000000000000000002'],
653
877
  transaction: baseTransaction as any,
654
878
  }),
655
879
  ).toThrow('feeToken is not allowed')
@@ -661,7 +885,7 @@ describe('prepareSponsoredTransaction', () => {
661
885
  account: sponsor,
662
886
  chainId: 42431,
663
887
  details,
664
- expectedFeeToken: bogus,
888
+ allowedFeeTokens: [bogus],
665
889
  transaction: {
666
890
  ...baseTransaction,
667
891
  validBefore: Math.floor(Date.now() / 1_000) + 3_600,
@@ -2,7 +2,7 @@ import type { TempoAddress } from 'ox/tempo'
2
2
  import { TxEnvelopeTempo } from 'ox/tempo'
3
3
  import type { Hex } from 'viem'
4
4
  import type { Account } from 'viem'
5
- import { decodeFunctionData, maxUint256 } from 'viem'
5
+ import { decodeFunctionData, maxUint256, toHex } from 'viem'
6
6
  import { Abis, Addresses, Transaction } from 'viem/tempo'
7
7
 
8
8
  import * as TempoAddress_internal from './address.js'
@@ -43,6 +43,16 @@ export type Policy = {
43
43
  // Tempo transaction fields.
44
44
  type SponsoredTransaction = ReturnType<(typeof Transaction)['deserialize']>
45
45
 
46
+ type HostedFeePayerFillResponse = {
47
+ error?: { message?: string | undefined } | undefined
48
+ result?: {
49
+ tx?: {
50
+ feePayerSignature?: unknown
51
+ feeToken?: unknown
52
+ }
53
+ }
54
+ }
55
+
46
56
  type ExpectedTransfer = {
47
57
  amount: string
48
58
  allowAnyMemo?: boolean | undefined
@@ -92,6 +102,137 @@ const supportedTransactionKeys = new Set<string>([
92
102
  ...rewrittenTransactionKeys,
93
103
  ])
94
104
 
105
+ function pushAllowedFeeToken(tokens: TempoAddress.Address[], token: string | undefined) {
106
+ if (!token) return
107
+ const normalized = token as TempoAddress.Address
108
+ if (tokens.some((existing) => TempoAddress_internal.isEqual(existing, normalized))) return
109
+ tokens.push(normalized)
110
+ }
111
+
112
+ /** Returns fee tokens that mppx allows sponsored transactions to charge. */
113
+ export function defaultAllowedFeeTokens(chainId: number | undefined) {
114
+ const tokens: TempoAddress.Address[] = []
115
+ pushAllowedFeeToken(tokens, defaults.tokens.pathUsd)
116
+ pushAllowedFeeToken(tokens, defaults.currency[chainId as keyof typeof defaults.currency])
117
+ return tokens
118
+ }
119
+
120
+ /** Rejects a sponsored fee token outside the server's allowlist. */
121
+ export function assertAllowedFeeToken(
122
+ transaction: { feeToken?: unknown },
123
+ allowedFeeTokens: readonly TempoAddress.Address[],
124
+ ) {
125
+ const { feeToken } = transaction
126
+ if (feeToken === undefined) return
127
+ if (typeof feeToken !== 'string')
128
+ throw new FeePayerValidationError('fee-sponsored transaction feeToken is invalid', {})
129
+ const normalized = feeToken as TempoAddress.Address
130
+ if (!allowedFeeTokens.some((allowed) => TempoAddress_internal.isEqual(allowed, normalized)))
131
+ throw new FeePayerValidationError('fee-sponsored transaction feeToken is not allowed', {
132
+ feeToken,
133
+ })
134
+ }
135
+
136
+ function hostedFeePayerRequest(transaction: SponsoredTransaction) {
137
+ return {
138
+ ...(transaction.accessList?.length ? { accessList: transaction.accessList } : {}),
139
+ calls: transaction.calls.map(
140
+ (call: {
141
+ data?: `0x${string}` | undefined
142
+ to?: TempoAddress.Address | undefined
143
+ value?: bigint | undefined
144
+ }) => ({
145
+ ...(call.to ? { to: call.to } : {}),
146
+ ...(call.data ? { data: call.data } : {}),
147
+ value: call.value === undefined ? '0x' : toHex(call.value),
148
+ }),
149
+ ),
150
+ feePayer: true,
151
+ from: transaction.from,
152
+ ...(transaction.gas !== undefined ? { gas: toHex(transaction.gas) } : {}),
153
+ ...(transaction.keyAuthorization !== undefined
154
+ ? { keyAuthorization: transaction.keyAuthorization }
155
+ : {}),
156
+ ...(transaction.maxFeePerGas !== undefined
157
+ ? { maxFeePerGas: toHex(transaction.maxFeePerGas) }
158
+ : {}),
159
+ ...(transaction.maxPriorityFeePerGas !== undefined
160
+ ? { maxPriorityFeePerGas: toHex(transaction.maxPriorityFeePerGas) }
161
+ : {}),
162
+ nonce: toHex(transaction.nonce ?? 0),
163
+ ...(transaction.nonceKey !== undefined ? { nonceKey: toHex(transaction.nonceKey) } : {}),
164
+ type: '0x76',
165
+ ...(transaction.validAfter !== undefined ? { validAfter: toHex(transaction.validAfter) } : {}),
166
+ ...(transaction.validBefore !== undefined
167
+ ? { validBefore: toHex(transaction.validBefore) }
168
+ : {}),
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Co-signs a sender-signed partial sponsorship envelope using a hosted
174
+ * fee-payer endpoint without letting the endpoint mutate sender-committed
175
+ * transaction fields.
176
+ */
177
+ export async function fillHostedFeePayerTransaction(parameters: {
178
+ allowedFeeTokens: readonly TempoAddress.Address[]
179
+ transaction: SponsoredTransaction
180
+ url: string
181
+ }) {
182
+ const { allowedFeeTokens, transaction, url } = parameters
183
+ const response = await fetch(url, {
184
+ body: JSON.stringify(
185
+ {
186
+ id: 1,
187
+ jsonrpc: '2.0',
188
+ method: 'eth_fillTransaction',
189
+ params: [hostedFeePayerRequest(transaction)],
190
+ },
191
+ (_key, value) => (typeof value === 'bigint' ? toHex(value) : value),
192
+ ),
193
+ headers: { 'content-type': 'application/json' },
194
+ method: 'POST',
195
+ })
196
+ const payload = (await response.json().catch(async () => ({
197
+ error: { message: await response.text() },
198
+ }))) as HostedFeePayerFillResponse
199
+ const filled = payload.result?.tx
200
+ if (!response.ok || payload.error || !filled?.feePayerSignature)
201
+ throw new FeePayerValidationError(
202
+ payload.error?.message ?? 'hosted fee payer failed to sponsor transaction',
203
+ {},
204
+ )
205
+ if (typeof filled.feeToken !== 'string')
206
+ throw new FeePayerValidationError('hosted fee payer did not return a feeToken', {})
207
+
208
+ assertAllowedFeeToken({ feeToken: filled.feeToken }, allowedFeeTokens)
209
+
210
+ return Transaction.serialize({
211
+ ...transaction,
212
+ feePayer: true,
213
+ feePayerSignature: filled.feePayerSignature,
214
+ feeToken: filled.feeToken,
215
+ } as never)
216
+ }
217
+
218
+ /** Returns a transaction shape suitable for pre-broadcast simulation. */
219
+ export function simulationTransaction(
220
+ transaction: SponsoredTransaction,
221
+ options: { feePayer: boolean },
222
+ ) {
223
+ if (options.feePayer)
224
+ return {
225
+ account: transaction.from,
226
+ calls: transaction.calls,
227
+ }
228
+ return {
229
+ ...transaction,
230
+ account: transaction.from,
231
+ calls: transaction.calls,
232
+ feePayerSignature: undefined,
233
+ }
234
+ }
235
+
95
236
  /**
96
237
  * maxTotalFee must be high enough to cover `transferWithMemo` and
97
238
  * swap transactions at peak gas prices. Bumped from 0.01 ETH in #327.
@@ -258,20 +399,20 @@ export function validateCalls(
258
399
 
259
400
  export function prepareSponsoredTransaction(parameters: {
260
401
  account: Account
402
+ allowedFeeTokens?: readonly TempoAddress.Address[] | undefined
261
403
  challengeExpires?: string | undefined
262
404
  chainId: number
263
405
  details: Record<string, string>
264
- expectedFeeToken?: TempoAddress.Address | undefined
265
406
  now?: Date | undefined
266
407
  policy?: Partial<Policy> | undefined
267
408
  transaction: SponsoredTransaction
268
409
  }) {
269
410
  const {
270
411
  account,
412
+ allowedFeeTokens,
271
413
  challengeExpires,
272
414
  chainId,
273
415
  details,
274
- expectedFeeToken,
275
416
  now = new Date(),
276
417
  policy: policyOverrides,
277
418
  transaction,
@@ -392,7 +533,12 @@ export function prepareSponsoredTransaction(parameters: {
392
533
  })()
393
534
 
394
535
  if (normalizedFeeToken !== undefined) {
395
- if (expectedFeeToken && !TempoAddress_internal.isEqual(normalizedFeeToken, expectedFeeToken))
536
+ if (
537
+ allowedFeeTokens &&
538
+ !allowedFeeTokens.some((allowed) =>
539
+ TempoAddress_internal.isEqual(normalizedFeeToken, allowed),
540
+ )
541
+ )
396
542
  fail('fee-sponsored transaction feeToken is not allowed', {
397
543
  feeToken: normalizedFeeToken,
398
544
  })
@@ -1,13 +1,14 @@
1
1
  import type { Account } from 'viem'
2
2
  import { createClient } from 'viem'
3
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
3
4
  import { Actions, Addresses } from 'viem/tempo'
4
5
  import { describe, expect, test } from 'vp/test'
5
- import { nodeEnv } from '~test/config.js'
6
- import { accounts, asset, chain, fundAccount, http } from '~test/tempo/viem.js'
6
+ import { tempoNetwork } from '~test/config.js'
7
+ import { asset, chain, fundAccount, http } from '~test/tempo/viem.js'
7
8
 
8
9
  import { resolveFeeToken } from './fee-token.js'
9
10
 
10
- const isLocalnet = nodeEnv === 'localnet'
11
+ const isLocalnet = tempoNetwork === 'localnet'
11
12
 
12
13
  function clientFor(account: Account) {
13
14
  return createClient({
@@ -21,9 +22,13 @@ function expectAddress(actual: string | undefined, expected: string) {
21
22
  expect(actual?.toLowerCase()).toBe(expected.toLowerCase())
22
23
  }
23
24
 
25
+ function testAccount() {
26
+ return privateKeyToAccount(generatePrivateKey())
27
+ }
28
+
24
29
  describe.runIf(isLocalnet)('resolveFeeToken', () => {
25
30
  test('uses the funded account fee preference first', async () => {
26
- const account = accounts[11]
31
+ const account = testAccount()
27
32
  const client = clientFor(account)
28
33
  await fundAccount({ address: account.address, token: asset })
29
34
  await Actions.fee.setUserTokenSync(client, {
@@ -41,7 +46,7 @@ describe.runIf(isLocalnet)('resolveFeeToken', () => {
41
46
  })
42
47
 
43
48
  test('falls through to the first funded candidate token', async () => {
44
- const account = accounts[12]
49
+ const account = testAccount()
45
50
  const client = clientFor(account)
46
51
  await fundAccount({ address: account.address, token: asset })
47
52
 
@@ -55,7 +60,7 @@ describe.runIf(isLocalnet)('resolveFeeToken', () => {
55
60
  })
56
61
 
57
62
  test('falls through from an unfunded account fee preference', async () => {
58
- const account = accounts[13]
63
+ const account = testAccount()
59
64
  const client = clientFor(account)
60
65
  await fundAccount({ address: account.address, token: asset })
61
66
  await Actions.fee.setUserTokenSync(client, {
@@ -73,7 +78,7 @@ describe.runIf(isLocalnet)('resolveFeeToken', () => {
73
78
  })
74
79
 
75
80
  test('uses a funded chain fee token when configured', async () => {
76
- const account = accounts[14]
81
+ const account = testAccount()
77
82
  const client = createClient({
78
83
  account,
79
84
  chain: { ...chain, feeToken: asset },
@@ -91,7 +96,7 @@ describe.runIf(isLocalnet)('resolveFeeToken', () => {
91
96
  })
92
97
 
93
98
  test('falls through from an unfunded chain fee token', async () => {
94
- const account = accounts[15]
99
+ const account = testAccount()
95
100
  const client = createClient({
96
101
  account,
97
102
  chain: { ...chain, feeToken: Addresses.pathUsd },
@@ -109,7 +114,7 @@ describe.runIf(isLocalnet)('resolveFeeToken', () => {
109
114
  })
110
115
 
111
116
  test('falls back to the first known token when none are funded', async () => {
112
- const account = accounts[16]
117
+ const account = testAccount()
113
118
  const client = clientFor(account)
114
119
 
115
120
  const feeToken = await resolveFeeToken({