tapimo 0.1.0 → 0.2.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 (385) hide show
  1. package/README.md +28 -15
  2. package/dist/ApiKey.d.ts +3 -1
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +1 -0
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +71 -3
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +117 -1
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +7139 -4197
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +133 -329
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +11 -4
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +12 -4
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/Webhooks.d.ts +2 -2
  19. package/dist/Webhooks.d.ts.map +1 -1
  20. package/dist/Webhooks.js +2 -2
  21. package/dist/Webhooks.js.map +1 -1
  22. package/dist/admin/App.d.ts +126 -53
  23. package/dist/admin/App.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.d.ts +104 -6
  25. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  26. package/dist/admin/apps/api-keys.js +67 -0
  27. package/dist/admin/apps/api-keys.js.map +1 -1
  28. package/dist/admin/apps/scopes.d.ts +4 -1
  29. package/dist/admin/apps/scopes.d.ts.map +1 -1
  30. package/dist/admin/apps/verified-tokens.d.ts +115 -115
  31. package/dist/admin/apps/verified-tokens.js +1 -1
  32. package/dist/admin/apps/verified-tokens.js.map +1 -1
  33. package/dist/admin/ui.generated.d.ts +1 -1
  34. package/dist/admin/ui.generated.js +1 -1
  35. package/dist/apps/data/App.d.ts +19176 -0
  36. package/dist/apps/data/App.d.ts.map +1 -0
  37. package/dist/apps/data/App.js +236 -0
  38. package/dist/apps/data/App.js.map +1 -0
  39. package/dist/apps/data/index.d.ts +3 -0
  40. package/dist/apps/data/index.d.ts.map +1 -0
  41. package/dist/apps/data/index.js +3 -0
  42. package/dist/apps/data/index.js.map +1 -0
  43. package/dist/apps/{activities.d.ts → data/routes/activities.d.ts} +32 -32
  44. package/dist/apps/{activities.d.ts.map → data/routes/activities.d.ts.map} +1 -1
  45. package/dist/apps/{activities.js → data/routes/activities.js} +13 -13
  46. package/dist/apps/data/routes/activities.js.map +1 -0
  47. package/dist/apps/{addresses.d.ts → data/routes/addresses.d.ts} +22 -22
  48. package/dist/apps/{addresses.d.ts.map → data/routes/addresses.d.ts.map} +1 -1
  49. package/dist/apps/{addresses.js → data/routes/addresses.js} +5 -5
  50. package/dist/apps/data/routes/addresses.js.map +1 -0
  51. package/dist/apps/{balances.d.ts → data/routes/balances.d.ts} +49 -49
  52. package/dist/apps/data/routes/balances.d.ts.map +1 -0
  53. package/dist/apps/{balances.js → data/routes/balances.js} +42 -11
  54. package/dist/apps/data/routes/balances.js.map +1 -0
  55. package/dist/apps/{blocks.d.ts → data/routes/blocks.d.ts} +47 -47
  56. package/dist/apps/data/routes/blocks.d.ts.map +1 -0
  57. package/dist/apps/{blocks.js → data/routes/blocks.js} +13 -13
  58. package/dist/apps/data/routes/blocks.js.map +1 -0
  59. package/dist/apps/{coingecko.d.ts → data/routes/coingecko.d.ts} +183 -183
  60. package/dist/apps/data/routes/coingecko.d.ts.map +1 -0
  61. package/dist/apps/{coingecko.js → data/routes/coingecko.js} +13 -13
  62. package/dist/apps/data/routes/coingecko.js.map +1 -0
  63. package/dist/apps/{exchanges.d.ts → data/routes/exchanges.d.ts} +460 -460
  64. package/dist/apps/data/routes/exchanges.d.ts.map +1 -0
  65. package/dist/apps/{exchanges.js → data/routes/exchanges.js} +19 -19
  66. package/dist/apps/data/routes/exchanges.js.map +1 -0
  67. package/dist/apps/{fee-amm.d.ts → data/routes/fee-amm.d.ts} +94 -94
  68. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -0
  69. package/dist/apps/{fee-amm.js → data/routes/fee-amm.js} +17 -17
  70. package/dist/apps/data/routes/fee-amm.js.map +1 -0
  71. package/dist/apps/{indexer.d.ts → data/routes/indexer.d.ts} +4 -4
  72. package/dist/apps/data/routes/indexer.d.ts.map +1 -0
  73. package/dist/apps/{indexer.js → data/routes/indexer.js} +13 -9
  74. package/dist/apps/data/routes/indexer.js.map +1 -0
  75. package/dist/apps/{receipts.d.ts → data/routes/receipts.d.ts} +49 -49
  76. package/dist/apps/data/routes/receipts.d.ts.map +1 -0
  77. package/dist/apps/{receipts.js → data/routes/receipts.js} +12 -12
  78. package/dist/apps/data/routes/receipts.js.map +1 -0
  79. package/dist/apps/{rpc.d.ts → data/routes/rpc.d.ts} +4 -4
  80. package/dist/apps/data/routes/rpc.d.ts.map +1 -0
  81. package/dist/apps/{rpc.js → data/routes/rpc.js} +6 -6
  82. package/dist/apps/data/routes/rpc.js.map +1 -0
  83. package/dist/apps/{tokenlist.d.ts → data/routes/tokenlist.d.ts} +4 -4
  84. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -0
  85. package/dist/apps/{tokenlist.js → data/routes/tokenlist.js} +8 -8
  86. package/dist/apps/data/routes/tokenlist.js.map +1 -0
  87. package/dist/apps/{tokens.d.ts → data/routes/tokens.d.ts} +468 -468
  88. package/dist/apps/data/routes/tokens.d.ts.map +1 -0
  89. package/dist/apps/{tokens.js → data/routes/tokens.js} +19 -19
  90. package/dist/apps/data/routes/tokens.js.map +1 -0
  91. package/dist/apps/{transactions.d.ts → data/routes/transactions.d.ts} +304 -304
  92. package/dist/apps/data/routes/transactions.d.ts.map +1 -0
  93. package/dist/apps/{transactions.js → data/routes/transactions.js} +13 -13
  94. package/dist/apps/data/routes/transactions.js.map +1 -0
  95. package/dist/apps/{transfers.d.ts → data/routes/transfers.d.ts} +6 -6
  96. package/dist/apps/data/routes/transfers.d.ts.map +1 -0
  97. package/dist/apps/{transfers.js → data/routes/transfers.js} +13 -13
  98. package/dist/apps/data/routes/transfers.js.map +1 -0
  99. package/dist/apps/{verified-tokens.d.ts → data/routes/verified-tokens.d.ts} +42 -42
  100. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -0
  101. package/dist/apps/{verified-tokens.js → data/routes/verified-tokens.js} +9 -9
  102. package/dist/apps/data/routes/verified-tokens.js.map +1 -0
  103. package/dist/apps/{webhooks.d.ts → data/routes/webhooks.d.ts} +62 -62
  104. package/dist/apps/{webhooks.d.ts.map → data/routes/webhooks.d.ts.map} +1 -1
  105. package/dist/apps/{webhooks.js → data/routes/webhooks.js} +30 -26
  106. package/dist/apps/data/routes/webhooks.js.map +1 -0
  107. package/dist/apps/docs/App.d.ts +27 -0
  108. package/dist/apps/docs/App.d.ts.map +1 -0
  109. package/dist/apps/docs/App.js +122 -0
  110. package/dist/apps/docs/App.js.map +1 -0
  111. package/dist/{internal/OpenApi.fonts.d.ts → apps/docs/fonts.d.ts} +1 -1
  112. package/dist/apps/docs/fonts.d.ts.map +1 -0
  113. package/dist/{internal/OpenApi.fonts.js → apps/docs/fonts.js} +1 -1
  114. package/dist/apps/docs/fonts.js.map +1 -0
  115. package/dist/apps/docs/index.d.ts +2 -0
  116. package/dist/apps/docs/index.d.ts.map +1 -0
  117. package/dist/apps/docs/index.js +2 -0
  118. package/dist/apps/docs/index.js.map +1 -0
  119. package/dist/{internal/OpenApi.logo.d.ts → apps/docs/logo.d.ts} +1 -1
  120. package/dist/apps/docs/logo.d.ts.map +1 -0
  121. package/dist/{internal/OpenApi.logo.js → apps/docs/logo.js} +1 -1
  122. package/dist/apps/docs/logo.js.map +1 -0
  123. package/dist/apps/index.d.ts +4 -0
  124. package/dist/apps/index.d.ts.map +1 -0
  125. package/dist/apps/index.js +4 -0
  126. package/dist/apps/index.js.map +1 -0
  127. package/dist/apps/metadata.d.ts +7 -0
  128. package/dist/apps/metadata.d.ts.map +1 -0
  129. package/dist/apps/metadata.js +15 -0
  130. package/dist/apps/metadata.js.map +1 -0
  131. package/dist/apps/platform/App.d.ts +2985 -0
  132. package/dist/apps/platform/App.d.ts.map +1 -0
  133. package/dist/apps/platform/App.js +74 -0
  134. package/dist/apps/platform/App.js.map +1 -0
  135. package/dist/apps/platform/index.d.ts +2 -0
  136. package/dist/apps/platform/index.d.ts.map +1 -0
  137. package/dist/apps/platform/index.js +2 -0
  138. package/dist/apps/platform/index.js.map +1 -0
  139. package/dist/apps/platform/routes/api-keys.d.ts +681 -0
  140. package/dist/apps/platform/routes/api-keys.d.ts.map +1 -0
  141. package/dist/apps/platform/routes/api-keys.js +328 -0
  142. package/dist/apps/platform/routes/api-keys.js.map +1 -0
  143. package/dist/apps/platform/routes/invitations.d.ts +733 -0
  144. package/dist/apps/platform/routes/invitations.d.ts.map +1 -0
  145. package/dist/apps/platform/routes/invitations.js +413 -0
  146. package/dist/apps/platform/routes/invitations.js.map +1 -0
  147. package/dist/apps/platform/routes/me.d.ts +95 -0
  148. package/dist/apps/platform/routes/me.d.ts.map +1 -0
  149. package/dist/apps/platform/routes/me.js +81 -0
  150. package/dist/apps/platform/routes/me.js.map +1 -0
  151. package/dist/apps/platform/routes/members.d.ts +554 -0
  152. package/dist/apps/platform/routes/members.d.ts.map +1 -0
  153. package/dist/apps/platform/routes/members.js +251 -0
  154. package/dist/apps/platform/routes/members.js.map +1 -0
  155. package/dist/apps/platform/routes/orgs.d.ts +582 -0
  156. package/dist/apps/platform/routes/orgs.d.ts.map +1 -0
  157. package/dist/apps/platform/routes/orgs.js +265 -0
  158. package/dist/apps/platform/routes/orgs.js.map +1 -0
  159. package/dist/apps/platform/routes/projects.d.ts +740 -0
  160. package/dist/apps/platform/routes/projects.d.ts.map +1 -0
  161. package/dist/apps/platform/routes/projects.js +286 -0
  162. package/dist/apps/platform/routes/projects.js.map +1 -0
  163. package/dist/apps/relay/App.d.ts +41 -0
  164. package/dist/apps/relay/App.d.ts.map +1 -0
  165. package/dist/apps/relay/App.js +103 -0
  166. package/dist/apps/relay/App.js.map +1 -0
  167. package/dist/apps/relay/Sponsorships.d.ts +107 -0
  168. package/dist/apps/relay/Sponsorships.d.ts.map +1 -0
  169. package/dist/apps/relay/Sponsorships.js +193 -0
  170. package/dist/apps/relay/Sponsorships.js.map +1 -0
  171. package/dist/apps/relay/index.d.ts +3 -0
  172. package/dist/apps/relay/index.d.ts.map +1 -0
  173. package/dist/apps/relay/index.js +3 -0
  174. package/dist/apps/relay/index.js.map +1 -0
  175. package/dist/cli/Cli.d.ts +1 -1
  176. package/dist/cli/Cli.js +1 -1
  177. package/dist/cli/commands/admin.d.ts +1 -1
  178. package/dist/cli/commands/admin.js +2 -2
  179. package/dist/cli/commands/admin.js.map +1 -1
  180. package/dist/db/Db.d.ts +10 -0
  181. package/dist/db/Db.d.ts.map +1 -1
  182. package/dist/db/Db.js +128 -0
  183. package/dist/db/Db.js.map +1 -1
  184. package/dist/db/Schema.d.ts +80 -0
  185. package/dist/db/Schema.d.ts.map +1 -1
  186. package/dist/db/Schema.js +99 -0
  187. package/dist/db/Schema.js.map +1 -1
  188. package/dist/db/tables/invitations.d.ts +84 -0
  189. package/dist/db/tables/invitations.d.ts.map +1 -0
  190. package/dist/db/tables/invitations.js +165 -0
  191. package/dist/db/tables/invitations.js.map +1 -0
  192. package/dist/db/tables/memberships.d.ts +108 -0
  193. package/dist/db/tables/memberships.d.ts.map +1 -0
  194. package/dist/db/tables/memberships.js +153 -0
  195. package/dist/db/tables/memberships.js.map +1 -0
  196. package/dist/db/tables/organizations.d.ts +44 -0
  197. package/dist/db/tables/organizations.d.ts.map +1 -1
  198. package/dist/db/tables/organizations.js +89 -0
  199. package/dist/db/tables/organizations.js.map +1 -1
  200. package/dist/db/tables/projects.d.ts +65 -0
  201. package/dist/db/tables/projects.d.ts.map +1 -0
  202. package/dist/db/tables/projects.js +75 -0
  203. package/dist/db/tables/projects.js.map +1 -0
  204. package/dist/db/tables/sponsoredTransactions.d.ts +120 -0
  205. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -0
  206. package/dist/db/tables/sponsoredTransactions.js +161 -0
  207. package/dist/db/tables/sponsoredTransactions.js.map +1 -0
  208. package/dist/db/tables/users.d.ts +48 -0
  209. package/dist/db/tables/users.d.ts.map +1 -0
  210. package/dist/db/tables/users.js +65 -0
  211. package/dist/db/tables/users.js.map +1 -0
  212. package/dist/handlers/internal/executionError.d.ts.map +1 -1
  213. package/dist/handlers/internal/executionError.js +2 -0
  214. package/dist/handlers/internal/executionError.js.map +1 -1
  215. package/dist/handlers/internal/multisig.d.ts +2 -6
  216. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  217. package/dist/handlers/internal/multisig.js +11 -36
  218. package/dist/handlers/internal/multisig.js.map +1 -1
  219. package/dist/handlers/internal/sponsorship.d.ts +32 -2
  220. package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
  221. package/dist/handlers/internal/sponsorship.js +34 -9
  222. package/dist/handlers/internal/sponsorship.js.map +1 -1
  223. package/dist/handlers/relay.d.ts +6 -2
  224. package/dist/handlers/relay.d.ts.map +1 -1
  225. package/dist/handlers/relay.js +16 -2
  226. package/dist/handlers/relay.js.map +1 -1
  227. package/dist/internal/Auth.d.ts +208 -6
  228. package/dist/internal/Auth.d.ts.map +1 -1
  229. package/dist/internal/Auth.js +500 -21
  230. package/dist/internal/Auth.js.map +1 -1
  231. package/dist/internal/Log.d.ts +7 -3
  232. package/dist/internal/Log.d.ts.map +1 -1
  233. package/dist/internal/Log.js +4 -0
  234. package/dist/internal/Log.js.map +1 -1
  235. package/dist/internal/OpenApi.d.ts +0 -19
  236. package/dist/internal/OpenApi.d.ts.map +1 -1
  237. package/dist/internal/OpenApi.js +0 -57
  238. package/dist/internal/OpenApi.js.map +1 -1
  239. package/dist/internal/Store.d.ts +7 -1
  240. package/dist/internal/Store.d.ts.map +1 -1
  241. package/dist/internal/Store.js +16 -2
  242. package/dist/internal/Store.js.map +1 -1
  243. package/dist/internal/Viem.d.ts +84 -0
  244. package/dist/internal/Viem.d.ts.map +1 -1
  245. package/dist/internal/Webhooks.d.ts +1 -1
  246. package/dist/internal/Webhooks.d.ts.map +1 -1
  247. package/package.json +31 -5
  248. package/src/ApiKey.ts +1 -0
  249. package/src/ApiKeys.test.ts +104 -1
  250. package/src/ApiKeys.ts +154 -1
  251. package/src/App.test.ts +11187 -179
  252. package/src/App.ts +200 -420
  253. package/src/Client.test-d.ts +306 -15
  254. package/src/Scope.ts +13 -4
  255. package/src/Webhooks.ts +2 -2
  256. package/src/admin/apps/api-keys.test.ts +51 -0
  257. package/src/admin/apps/api-keys.ts +84 -0
  258. package/src/admin/apps/scopes.test.ts +5 -1
  259. package/src/admin/apps/verified-tokens.ts +1 -1
  260. package/src/admin/ui.generated.ts +1 -1
  261. package/src/apps/composition.test.ts +66 -0
  262. package/src/apps/data/App.ts +295 -0
  263. package/src/apps/data/index.ts +2 -0
  264. package/src/apps/{activities.test.ts → data/routes/activities.test.ts} +3 -3
  265. package/src/apps/{activities.ts → data/routes/activities.ts} +15 -15
  266. package/src/apps/{addresses.ts → data/routes/addresses.ts} +6 -6
  267. package/src/apps/{balances.test.ts → data/routes/balances.test.ts} +2 -2
  268. package/src/apps/{balances.ts → data/routes/balances.ts} +46 -12
  269. package/src/apps/{blocks.test.ts → data/routes/blocks.test.ts} +3 -3
  270. package/src/apps/{blocks.ts → data/routes/blocks.ts} +14 -14
  271. package/src/apps/{coingecko.test.ts → data/routes/coingecko.test.ts} +2 -2
  272. package/src/apps/{coingecko.ts → data/routes/coingecko.ts} +14 -14
  273. package/src/apps/{exchanges.test.ts → data/routes/exchanges.test.ts} +1 -1
  274. package/src/apps/{exchanges.ts → data/routes/exchanges.ts} +20 -20
  275. package/src/apps/{fee-amm.test.ts → data/routes/fee-amm.test.ts} +3 -3
  276. package/src/apps/{fee-amm.ts → data/routes/fee-amm.ts} +18 -18
  277. package/src/apps/{indexer.test.ts → data/routes/indexer.test.ts} +26 -5
  278. package/src/apps/{indexer.ts → data/routes/indexer.ts} +13 -10
  279. package/src/apps/{receipts.test.ts → data/routes/receipts.test.ts} +3 -3
  280. package/src/apps/{receipts.ts → data/routes/receipts.ts} +13 -13
  281. package/src/apps/{rpc.test.ts → data/routes/rpc.test.ts} +44 -5
  282. package/src/apps/{rpc.ts → data/routes/rpc.ts} +7 -7
  283. package/src/apps/{tokenlist.test.ts → data/routes/tokenlist.test.ts} +3 -3
  284. package/src/apps/{tokenlist.ts → data/routes/tokenlist.ts} +9 -9
  285. package/src/apps/{tokens.test.ts → data/routes/tokens.test.ts} +2 -2
  286. package/src/apps/{tokens.ts → data/routes/tokens.ts} +20 -20
  287. package/src/apps/{transactions.test.ts → data/routes/transactions.test.ts} +3 -3
  288. package/src/apps/{transactions.ts → data/routes/transactions.ts} +15 -15
  289. package/src/apps/{transfers.test.ts → data/routes/transfers.test.ts} +2 -2
  290. package/src/apps/{transfers.ts → data/routes/transfers.ts} +15 -15
  291. package/src/apps/{verified-tokens.test.ts → data/routes/verified-tokens.test.ts} +3 -3
  292. package/src/apps/{verified-tokens.ts → data/routes/verified-tokens.ts} +10 -10
  293. package/src/apps/{webhooks.test.ts → data/routes/webhooks.test.ts} +6 -6
  294. package/src/apps/{webhooks.ts → data/routes/webhooks.ts} +39 -35
  295. package/src/apps/docs/App.ts +136 -0
  296. package/src/apps/docs/index.ts +1 -0
  297. package/src/apps/index.ts +3 -0
  298. package/src/apps/metadata.ts +23 -0
  299. package/src/apps/platform/App.ts +130 -0
  300. package/src/apps/platform/index.ts +1 -0
  301. package/src/apps/platform/routes/api-keys.test.ts +330 -0
  302. package/src/apps/platform/routes/api-keys.ts +427 -0
  303. package/src/apps/platform/routes/invitations.test.ts +361 -0
  304. package/src/apps/platform/routes/invitations.ts +519 -0
  305. package/src/apps/platform/routes/me.test.ts +121 -0
  306. package/src/apps/platform/routes/me.ts +106 -0
  307. package/src/apps/platform/routes/members.test.ts +195 -0
  308. package/src/apps/platform/routes/members.ts +313 -0
  309. package/src/apps/platform/routes/orgs.test.ts +313 -0
  310. package/src/apps/platform/routes/orgs.ts +343 -0
  311. package/src/apps/platform/routes/projects.test.ts +181 -0
  312. package/src/apps/platform/routes/projects.ts +367 -0
  313. package/src/apps/relay/App.test.ts +484 -0
  314. package/src/apps/relay/App.ts +128 -0
  315. package/src/apps/relay/Sponsorships.test.ts +375 -0
  316. package/src/apps/relay/Sponsorships.ts +305 -0
  317. package/src/apps/relay/index.ts +2 -0
  318. package/src/cli/Cli.ts +1 -1
  319. package/src/cli/commands/admin.ts +2 -2
  320. package/src/db/Db.ts +159 -0
  321. package/src/db/Schema.ts +137 -0
  322. package/src/db/tables/invitations.ts +198 -0
  323. package/src/db/tables/memberships.ts +208 -0
  324. package/src/db/tables/organizations.test.ts +37 -1
  325. package/src/db/tables/organizations.ts +105 -0
  326. package/src/db/tables/projects.ts +107 -0
  327. package/src/db/tables/sponsoredTransactions.test.ts +218 -0
  328. package/src/db/tables/sponsoredTransactions.ts +236 -0
  329. package/src/db/tables/users.ts +85 -0
  330. package/src/handlers/internal/executionError.ts +2 -0
  331. package/src/handlers/internal/multisig.test.ts +84 -10
  332. package/src/handlers/internal/multisig.ts +15 -50
  333. package/src/handlers/internal/sponsorship.ts +74 -15
  334. package/src/handlers/{internal/relay.localnet.test.ts → relay.test.ts} +2 -2
  335. package/src/handlers/relay.ts +23 -5
  336. package/src/internal/Auth.test.ts +316 -0
  337. package/src/internal/Auth.ts +691 -25
  338. package/src/internal/Cursor.test.ts +3 -2
  339. package/src/internal/Log.test.ts +1 -1
  340. package/src/internal/Log.ts +11 -3
  341. package/src/internal/MetricSink.ts +1 -1
  342. package/src/internal/OpenApi.ts +0 -59
  343. package/src/internal/Store.test.ts +52 -0
  344. package/src/internal/Store.ts +24 -5
  345. package/src/internal/Tidx.local.test.ts +1 -1
  346. package/src/internal/VerifiedTokens.test.ts +1 -1
  347. package/src/internal/WebhookDestination.test.ts +1 -1
  348. package/src/internal/Webhooks.test.ts +4 -4
  349. package/src/internal/Webhooks.ts +1 -1
  350. package/dist/apps/activities.js.map +0 -1
  351. package/dist/apps/addresses.js.map +0 -1
  352. package/dist/apps/balances.d.ts.map +0 -1
  353. package/dist/apps/balances.js.map +0 -1
  354. package/dist/apps/blocks.d.ts.map +0 -1
  355. package/dist/apps/blocks.js.map +0 -1
  356. package/dist/apps/coingecko.d.ts.map +0 -1
  357. package/dist/apps/coingecko.js.map +0 -1
  358. package/dist/apps/exchanges.d.ts.map +0 -1
  359. package/dist/apps/exchanges.js.map +0 -1
  360. package/dist/apps/fee-amm.d.ts.map +0 -1
  361. package/dist/apps/fee-amm.js.map +0 -1
  362. package/dist/apps/indexer.d.ts.map +0 -1
  363. package/dist/apps/indexer.js.map +0 -1
  364. package/dist/apps/receipts.d.ts.map +0 -1
  365. package/dist/apps/receipts.js.map +0 -1
  366. package/dist/apps/rpc.d.ts.map +0 -1
  367. package/dist/apps/rpc.js.map +0 -1
  368. package/dist/apps/tokenlist.d.ts.map +0 -1
  369. package/dist/apps/tokenlist.js.map +0 -1
  370. package/dist/apps/tokens.d.ts.map +0 -1
  371. package/dist/apps/tokens.js.map +0 -1
  372. package/dist/apps/transactions.d.ts.map +0 -1
  373. package/dist/apps/transactions.js.map +0 -1
  374. package/dist/apps/transfers.d.ts.map +0 -1
  375. package/dist/apps/transfers.js.map +0 -1
  376. package/dist/apps/verified-tokens.d.ts.map +0 -1
  377. package/dist/apps/verified-tokens.js.map +0 -1
  378. package/dist/apps/webhooks.js.map +0 -1
  379. package/dist/internal/OpenApi.fonts.d.ts.map +0 -1
  380. package/dist/internal/OpenApi.fonts.js.map +0 -1
  381. package/dist/internal/OpenApi.logo.d.ts.map +0 -1
  382. package/dist/internal/OpenApi.logo.js.map +0 -1
  383. package/src/handlers/internal/multisig.localnet.test.ts +0 -146
  384. /package/src/{internal/OpenApi.fonts.ts → apps/docs/fonts.ts} +0 -0
  385. /package/src/{internal/OpenApi.logo.ts → apps/docs/logo.ts} +0 -0
@@ -0,0 +1,484 @@
1
+ import { Hash, Secp256k1 } from 'ox'
2
+ import { createClient, http } from 'viem'
3
+ import { prepareTransactionRequest, sendRawTransactionSync, signTransaction } from 'viem/actions'
4
+ import { Account as TempoAccount, Actions, Transaction, withRelay } from 'viem/tempo'
5
+
6
+ import * as TestApp from '../../../test/App.js'
7
+ import * as Relay from '../../../test/Relay.js'
8
+ import * as Runtime from '../../../test/runtime.js'
9
+ import * as Tempo from '../../../test/Tempo.js'
10
+ import * as SponsoredTransactions from '../../db/tables/sponsoredTransactions.js'
11
+ import * as RequestListener from '../../handlers/internal/requestListener.js'
12
+ import * as Sponsorships from './Sponsorships.js'
13
+
14
+ const runtime = Runtime.get()
15
+
16
+ const feePayerAccount = Tempo.accounts[10]!
17
+ const senderAccount = Tempo.accounts[9]!
18
+
19
+ /** Keys covering the sponsorship policy matrix; all hold the base relay scope. */
20
+ const keys = [
21
+ {
22
+ id: 'key_sponsor',
23
+ orgId: 'org_1',
24
+ projectId: 'prj_1',
25
+ environment: 'sandbox',
26
+ scopes: ['rpc-relay:read', 'rpc-relay:sponsor'],
27
+ token: 'secret_sponsor',
28
+ },
29
+ {
30
+ id: 'key_sponsor_prod',
31
+ orgId: 'org_1',
32
+ projectId: 'prj_1',
33
+ environment: 'production',
34
+ scopes: ['rpc-relay:read', 'rpc-relay:sponsor'],
35
+ token: 'secret_sponsor_prod',
36
+ },
37
+ {
38
+ id: 'key_wildcard',
39
+ orgId: 'org_2',
40
+ projectId: 'prj_2',
41
+ environment: 'sandbox',
42
+ scopes: ['*'],
43
+ token: 'secret_wildcard',
44
+ },
45
+ {
46
+ id: 'key_unscoped',
47
+ orgId: 'org_1',
48
+ projectId: 'prj_1',
49
+ environment: 'sandbox',
50
+ scopes: ['rpc-relay:read'],
51
+ token: 'secret_unscoped',
52
+ },
53
+ {
54
+ id: 'key_unattributed',
55
+ orgId: 'org_1',
56
+ environment: 'sandbox',
57
+ scopes: ['rpc-relay:read', 'rpc-relay:sponsor'],
58
+ token: 'secret_unattributed',
59
+ },
60
+ ] as const satisfies readonly TestApp.kvStore.Key[]
61
+
62
+ describe.skipIf(runtime.mode !== 'localnet')('behavior: sponsorship', () => {
63
+ test('behavior: scoped keys sponsor, recorded with attribution', async () => {
64
+ const db = TestApp.database()
65
+ const app = TestApp.create({
66
+ auth: { keys },
67
+ db,
68
+ relay: { feePayer: { account: feePayerAccount } },
69
+ })
70
+
71
+ const body = await relayRequest(app, {
72
+ method: 'eth_signRawTransaction',
73
+ params: [await signSponsorable()],
74
+ token: 'secret_sponsor',
75
+ })
76
+ expect(body.error).toBeUndefined()
77
+ // The relay returned the envelope counter-signed by the fee payer.
78
+ const signed = Transaction.deserialize(body.result as `0x76${string}`)
79
+ expect(signed.feePayerSignature).toBeDefined()
80
+
81
+ const [row] = await SponsoredTransactions.listPending(db)
82
+ expect(row?.transactionHash).toBe(Hash.keccak256(body.result!))
83
+ expect(row?.signPayload).toMatch(/^0x/)
84
+ expect(row?.chainId).toBe(runtime.chainId)
85
+ // The stored envelope is exactly the counter-signed transaction returned.
86
+ expect(row?.transaction).toBe(body.result)
87
+ expect({ ...row, chainId: '<chainId>', createdAt: '<timestamp>', id: '<id>', signPayload: '<hash>', transaction: '<hex>', transactionHash: '<hash>' }) // prettier-ignore
88
+ .toMatchInlineSnapshot(`
89
+ {
90
+ "apiKeyId": "key_sponsor",
91
+ "billable": false,
92
+ "chainId": "<chainId>",
93
+ "createdAt": "<timestamp>",
94
+ "environment": "sandbox",
95
+ "feeAmount": null,
96
+ "feeToken": "0x20c0000000000000000000000000000000000000",
97
+ "finalizedAt": null,
98
+ "id": "<id>",
99
+ "orgId": "org_1",
100
+ "projectId": "prj_1",
101
+ "signPayload": "<hash>",
102
+ "status": "pending",
103
+ "transaction": "<hex>",
104
+ "transactionHash": "<hash>",
105
+ }
106
+ `)
107
+ })
108
+
109
+ test('behavior: production keys record billable rows', async () => {
110
+ const db = TestApp.database()
111
+ const app = TestApp.create({
112
+ auth: { keys },
113
+ db,
114
+ relay: { feePayer: { account: feePayerAccount } },
115
+ })
116
+
117
+ const body = await relayRequest(app, {
118
+ method: 'eth_signRawTransaction',
119
+ params: [await signSponsorable()],
120
+ token: 'secret_sponsor_prod',
121
+ })
122
+ expect(body.error).toBeUndefined()
123
+
124
+ const [row] = await SponsoredTransactions.listPending(db)
125
+ expect(row?.billable).toBe(true)
126
+ expect(row?.environment).toMatchInlineSnapshot(`"production"`)
127
+ })
128
+
129
+ test('behavior: the wildcard scope grants sponsorship', async () => {
130
+ const db = TestApp.database()
131
+ const app = TestApp.create({
132
+ auth: { keys },
133
+ db,
134
+ relay: { feePayer: { account: feePayerAccount } },
135
+ })
136
+
137
+ const body = await relayRequest(app, {
138
+ method: 'eth_signRawTransaction',
139
+ params: [await signSponsorable()],
140
+ token: 'secret_wildcard',
141
+ })
142
+ expect(body.error).toBeUndefined()
143
+
144
+ const [row] = await SponsoredTransactions.listPending(db)
145
+ expect(row?.orgId).toMatchInlineSnapshot(`"org_2"`)
146
+ })
147
+
148
+ test('behavior: keys without the sponsor scope are refused', async () => {
149
+ const db = TestApp.database()
150
+ const app = TestApp.create({
151
+ auth: { keys },
152
+ db,
153
+ relay: { feePayer: { account: feePayerAccount } },
154
+ })
155
+
156
+ const body = await relayRequest(app, {
157
+ method: 'eth_signRawTransaction',
158
+ params: [await signSponsorable()],
159
+ token: 'secret_unscoped',
160
+ })
161
+ // "Sponsorship rejected." surfaces as invalid params (-32602).
162
+ expect(body.result).toBeUndefined()
163
+ expect(body.error?.code).toBe(-32602)
164
+ expect(await SponsoredTransactions.listPending(db)).toHaveLength(0)
165
+ })
166
+
167
+ test('behavior: keys without project attribution are refused', async () => {
168
+ const db = TestApp.database()
169
+ const app = TestApp.create({
170
+ auth: { keys },
171
+ db,
172
+ relay: { feePayer: { account: feePayerAccount } },
173
+ })
174
+
175
+ const body = await relayRequest(app, {
176
+ method: 'eth_signRawTransaction',
177
+ params: [await signSponsorable()],
178
+ token: 'secret_unattributed',
179
+ })
180
+ expect(body.result).toBeUndefined()
181
+ expect(body.error?.code).toBe(-32602)
182
+ expect(await SponsoredTransactions.listPending(db)).toHaveLength(0)
183
+ })
184
+
185
+ test('behavior: super admin principals are refused', async () => {
186
+ const db = TestApp.database()
187
+ const app = TestApp.create({
188
+ auth: { keys, superAdmin: { secret: 'super-admin-secret' } },
189
+ db,
190
+ relay: { feePayer: { account: feePayerAccount } },
191
+ })
192
+
193
+ const body = await relayRequest(app, {
194
+ method: 'eth_signRawTransaction',
195
+ params: [await signSponsorable()],
196
+ token: 'super-admin-secret',
197
+ })
198
+ expect(body.result).toBeUndefined()
199
+ expect(body.error?.code).toBe(-32602)
200
+ expect(await SponsoredTransactions.listPending(db)).toHaveLength(0)
201
+ })
202
+
203
+ test('behavior: sponsorship stays closed without a fee payer', async () => {
204
+ const db = TestApp.database()
205
+ const app = TestApp.create({ auth: { keys }, db })
206
+
207
+ const body = await relayRequest(app, {
208
+ method: 'eth_signRawTransaction',
209
+ params: [await signSponsorable()],
210
+ token: 'secret_sponsor',
211
+ })
212
+ expect(body.error?.code).toBe(-32601)
213
+ expect(await SponsoredTransactions.listPending(db)).toHaveLength(0)
214
+ })
215
+
216
+ test('behavior: mainnet sponsorship is refused until billing ships', async () => {
217
+ const db = TestApp.database()
218
+ const app = TestApp.create({
219
+ auth: { keys },
220
+ db,
221
+ relay: { feePayer: { account: feePayerAccount } },
222
+ })
223
+
224
+ const body = await relayRequest(app, {
225
+ method: 'eth_signRawTransaction',
226
+ params: [
227
+ await senderAccount.signTransaction({
228
+ chainId: 4217,
229
+ feePayer: true,
230
+ gas: 100_000n,
231
+ maxFeePerGas: 1_000_000n,
232
+ maxPriorityFeePerGas: 0n,
233
+ nonce: 0,
234
+ to: Tempo.accounts[8]!.address,
235
+ value: 0n,
236
+ }),
237
+ ],
238
+ token: 'secret_sponsor',
239
+ })
240
+ expect(body.result).toBeUndefined()
241
+ expect(body.error?.code).toBe(-32602)
242
+ expect(await SponsoredTransactions.listPending(db)).toHaveLength(0)
243
+ })
244
+
245
+ test('behavior: an app-provided fee payer URL cannot trigger the managed fee payer', async () => {
246
+ const db = TestApp.database()
247
+ const app = TestApp.create({
248
+ auth: { keys },
249
+ db,
250
+ relay: { feePayer: { account: feePayerAccount } },
251
+ })
252
+
253
+ const body = await relayRequest(app, {
254
+ method: 'eth_fillTransaction',
255
+ params: [
256
+ {
257
+ calls: [{ to: Tempo.accounts[8]!.address, value: '0x0' }],
258
+ chainId: `0x${runtime.chainId.toString(16)}`,
259
+ feePayer: 'https://example.com',
260
+ from: senderAccount.address,
261
+ gas: '0x186a0',
262
+ maxFeePerGas: '0xf4240',
263
+ maxPriorityFeePerGas: '0x0',
264
+ nonce: '0x0',
265
+ },
266
+ ],
267
+ token: 'secret_unscoped',
268
+ })
269
+ const result = body.result as unknown as
270
+ | { capabilities?: { sponsored?: boolean }; tx?: { feePayerSignature?: string | null } }
271
+ | undefined
272
+ expect(result?.tx?.feePayerSignature ?? null).toBeNull()
273
+ expect(result?.capabilities?.sponsored).toBe(false)
274
+ expect(await SponsoredTransactions.listPending(db)).toHaveLength(0)
275
+ })
276
+
277
+ test('behavior: sponsorship is refused for chains this deployment does not serve', async () => {
278
+ const db = TestApp.database()
279
+ const app = TestApp.create({
280
+ auth: { keys },
281
+ db,
282
+ relay: { feePayer: { account: feePayerAccount } },
283
+ })
284
+
285
+ const body = await relayRequest(app, {
286
+ method: 'eth_signRawTransaction',
287
+ params: [
288
+ await senderAccount.signTransaction({
289
+ chainId: 999_999,
290
+ feePayer: true,
291
+ gas: 100_000n,
292
+ maxFeePerGas: 1_000_000n,
293
+ maxPriorityFeePerGas: 0n,
294
+ nonce: 0,
295
+ to: Tempo.accounts[8]!.address,
296
+ value: 0n,
297
+ }),
298
+ ],
299
+ token: 'secret_sponsor',
300
+ })
301
+ expect(body.result).toBeUndefined()
302
+ expect(body.error?.code).toBe(-32602)
303
+ expect(await SponsoredTransactions.listPending(db)).toHaveLength(0)
304
+ })
305
+ })
306
+
307
+ describe.skipIf(runtime.mode !== 'localnet')('behavior: sponsorship (viem)', () => {
308
+ const alphaUsd = '0x20c0000000000000000000000000000000000001'
309
+ const feePayer = TempoAccount.fromSecp256k1(Secp256k1.randomPrivateKey())
310
+ const sender = TempoAccount.fromSecp256k1(Secp256k1.randomPrivateKey())
311
+ const relayClient = Relay.getClient()
312
+
313
+ let db: ReturnType<typeof TestApp.database>
314
+ let server: Relay.Server
315
+
316
+ function getClient(policy?: 'sign-and-broadcast' | 'sign-only') {
317
+ return createClient({
318
+ account: sender,
319
+ chain: Tempo.chain,
320
+ transport: withRelay(
321
+ Relay.http(),
322
+ http(`${server.url}/rpc/relay`, {
323
+ fetchOptions: { headers: { 'tempo-api-key': 'secret_sponsor' } },
324
+ }),
325
+ policy ? { policy } : {},
326
+ ),
327
+ })
328
+ }
329
+
330
+ beforeAll(async () => {
331
+ await Promise.all(
332
+ [feePayer, sender].map((account) =>
333
+ Actions.faucet.fundSync(relayClient, { account, timeout: 60_000 }),
334
+ ),
335
+ )
336
+ db = TestApp.database()
337
+ const app = TestApp.create({
338
+ auth: { keys },
339
+ db,
340
+ // Explicit fee token: exercises the consumer override of the pathUSD default.
341
+ relay: { feePayer: { account: feePayer, feeToken: alphaUsd } },
342
+ })
343
+ server = await Relay.createServer(RequestListener.fromFetchHandler((req) => app.fetch(req)))
344
+ }, 120_000)
345
+
346
+ afterAll(async () => {
347
+ await server.closeAsync()
348
+ })
349
+
350
+ test('behavior: transferSync sponsors end-to-end, recording a fill intent', async () => {
351
+ const { receipt } = await Actions.token.transferSync(getClient(), {
352
+ amount: 1n,
353
+ feePayer: true,
354
+ to: Tempo.accounts[8]!.address,
355
+ token: alphaUsd,
356
+ })
357
+
358
+ // Sponsored on-chain: the fee payer paid, the sender's transfer landed.
359
+ expect(receipt.status).toBe('success')
360
+ expect(receipt.feePayer?.toLowerCase()).toBe(feePayer.address.toLowerCase())
361
+
362
+ const intent = (await SponsoredTransactions.listPending(db)).find(
363
+ (row) => row.transactionHash === null,
364
+ )
365
+ expect(intent?.apiKeyId).toBe('key_sponsor')
366
+ expect(intent?.orgId).toBe('org_1')
367
+ expect(intent?.billable).toBe(false)
368
+ expect(intent?.feeToken?.toLowerCase()).toBe(alphaUsd)
369
+
370
+ const finalizer = Sponsorships.createFinalizer({
371
+ db,
372
+ defaultChainId: runtime.chainId,
373
+ feePayer: feePayer.address,
374
+ rpc: TestApp.rpc,
375
+ tidx: { baseUrl: runtime.tidxUrl! },
376
+ })
377
+ let finalized: Awaited<ReturnType<typeof SponsoredTransactions.get>>
378
+ for (let attempt = 0; attempt < 30; attempt++) {
379
+ await finalizer.tick()
380
+ finalized = await SponsoredTransactions.get(db, intent!.id)
381
+ if (finalized?.status === 'finalized') break
382
+ await new Promise((resolve) => setTimeout(resolve, 1_000))
383
+ }
384
+ expect(finalized?.status).toBe('finalized')
385
+ expect(finalized?.transactionHash).toBe(receipt.transactionHash)
386
+ expect(finalized?.feeAmount).toBe((receipt.gasUsed * receipt.effectiveGasPrice).toString())
387
+ }, 60_000)
388
+
389
+ test('behavior: sign-only sends record and finalize from the real receipt', async () => {
390
+ const request = await prepareTransactionRequest(relayClient, {
391
+ account: sender,
392
+ calls: [
393
+ Actions.token.transfer.call(relayClient, {
394
+ amount: 1n,
395
+ to: Tempo.accounts[8]!.address,
396
+ token: alphaUsd,
397
+ }),
398
+ ],
399
+ feePayer: true,
400
+ })
401
+ const signed = await signTransaction(relayClient, request)
402
+
403
+ const receipt = await sendRawTransactionSync(getClient(), {
404
+ serializedTransaction: signed,
405
+ })
406
+
407
+ const row = (await SponsoredTransactions.listPending(db)).find(
408
+ (row) => row.transactionHash === receipt.transactionHash,
409
+ )
410
+ expect(row?.apiKeyId).toBe('key_sponsor')
411
+ expect(row?.orgId).toBe('org_1')
412
+ expect(row?.transaction.startsWith('0x76')).toBe(true)
413
+
414
+ // The finalizer resolves the row against the real localnet receipt.
415
+ const result = await Sponsorships.finalize(db, { getClient: () => relayClient })
416
+ expect(result.failed).toBe(0)
417
+ expect(result.finalized).toBeGreaterThanOrEqual(1)
418
+ const finalized = await SponsoredTransactions.get(db, row!.id)
419
+ expect(finalized?.status).toBe('finalized')
420
+ expect(finalized?.feeAmount).toBe((receipt.gasUsed * receipt.effectiveGasPrice).toString())
421
+ }, 30_000)
422
+
423
+ test('behavior: sign-and-broadcast sends record through the relay', async () => {
424
+ const request = await prepareTransactionRequest(relayClient, {
425
+ account: sender,
426
+ calls: [
427
+ Actions.token.transfer.call(relayClient, {
428
+ amount: 2n,
429
+ to: Tempo.accounts[8]!.address,
430
+ token: alphaUsd,
431
+ }),
432
+ ],
433
+ feePayer: true,
434
+ })
435
+ const signed = await signTransaction(relayClient, request)
436
+
437
+ const receipt = await sendRawTransactionSync(getClient('sign-and-broadcast'), {
438
+ serializedTransaction: signed,
439
+ })
440
+
441
+ const rows = await SponsoredTransactions.listPending(db)
442
+ expect(rows.find((row) => row.transactionHash === receipt.transactionHash)).toBeDefined()
443
+ }, 30_000)
444
+ })
445
+
446
+ /**
447
+ * Signs a sponsorship-requesting Tempo transaction (fee-payer slot present but
448
+ * empty; the serializer strips `feeToken`, the sponsor picks it) entirely
449
+ * offline: `eth_signRawTransaction` never touches the chain, so the suite
450
+ * runs without a node.
451
+ */
452
+ async function signSponsorable() {
453
+ return await senderAccount.signTransaction({
454
+ chainId: runtime.chainId,
455
+ feePayer: true,
456
+ gas: 100_000n,
457
+ maxFeePerGas: 1_000_000n,
458
+ maxPriorityFeePerGas: 0n,
459
+ nonce: 0,
460
+ to: Tempo.accounts[8]!.address,
461
+ value: 0n,
462
+ })
463
+ }
464
+
465
+ /** Posts one JSON-RPC request to the composed app's relay mount. */
466
+ async function relayRequest(
467
+ app: ReturnType<typeof TestApp.create>,
468
+ options: { method: string; params: readonly unknown[]; token?: string | undefined },
469
+ ) {
470
+ const response = await app.fetch(
471
+ new Request('http://tempo-api.test/rpc/relay', {
472
+ body: JSON.stringify({ id: 1, jsonrpc: '2.0', method: options.method, params: options.params }), // prettier-ignore
473
+ headers: {
474
+ 'content-type': 'application/json',
475
+ ...(options.token ? { 'tempo-api-key': options.token } : {}),
476
+ },
477
+ method: 'POST',
478
+ }),
479
+ )
480
+ return (await response.json()) as {
481
+ error?: { code: number; message: string } | undefined
482
+ result?: `0x${string}` | undefined
483
+ }
484
+ }
@@ -0,0 +1,128 @@
1
+ import { Hono } from 'hono'
2
+ import { createMiddleware } from 'hono/factory'
3
+ import { Addresses } from 'viem/tempo'
4
+
5
+ import type * as App from '../../App.js'
6
+ import * as Db from '../../db/Db.js'
7
+ import * as SponsoredTransactions from '../../db/tables/sponsoredTransactions.js'
8
+ import * as Handler from '../../Handler.js'
9
+ import * as Auth from '../../internal/Auth.js'
10
+ import * as OpenApi from '../../internal/OpenApi.js'
11
+ import * as Path from '../../internal/Path.js'
12
+ import * as VerifiedTokens from '../../internal/VerifiedTokens.js'
13
+ import * as Viem from '../../internal/Viem.js'
14
+ import * as Scope from '../../Scope.js'
15
+
16
+ /**
17
+ * The relay route group: the wallet relay at `/rpc/relay`. Mount
18
+ * after `data()`, whose published chain clients and supported-chain set the
19
+ * middleware reads from request context.
20
+ *
21
+ * ```ts
22
+ * App.create(options).route('/', data()).route('/', relay())
23
+ * ```
24
+ */
25
+ export function relay(options: relay.Options = {}) {
26
+ const handler = middleware(options)
27
+ return new Hono<App.Environment>()
28
+ .use(
29
+ '/rpc/relay',
30
+ Auth.policy({ apiKey: { scopes: ['rpc-relay:read'] }, mpp: false, public: false }),
31
+ OpenApi.describeRoute({ hide: true, summary: 'Relay RPC' }),
32
+ )
33
+ .use(
34
+ '/rpc/relay/*',
35
+ Auth.policy({ apiKey: { scopes: ['rpc-relay:read'] }, mpp: false, public: false }),
36
+ OpenApi.describeRoute({ hide: true, summary: 'Relay RPC' }),
37
+ )
38
+ .all('/rpc/relay', handler)
39
+ .all('/rpc/relay/:chainId', handler)
40
+ }
41
+
42
+ export declare namespace relay {
43
+ /** Options for the relay route group. */
44
+ type Options = {
45
+ feePayer?:
46
+ | Pick<
47
+ NonNullable<Handler.relay.Options['feePayer']>,
48
+ 'account' | 'feeToken' | 'name' | 'url'
49
+ >
50
+ | undefined
51
+ }
52
+ }
53
+
54
+ // The wallet relay middleware: proxies wallet JSON-RPC (fills, sponsored
55
+ // sends) with wallet-aware enrichment. Built per request from context rather
56
+ // than closed over group locals; relay traffic is low-QPS and the viem
57
+ // clients are memoized upstream, so per-request handler construction is cheap.
58
+ function middleware(options: relay.Options = {}) {
59
+ return createMiddleware<App.Environment>(async (c) => {
60
+ const verifiedTokens = c.get('verifiedTokens')
61
+
62
+ const feePayer = (() => {
63
+ if (!options.feePayer) return undefined
64
+ const principal = Auth.getPrincipal(c)
65
+ const attribution =
66
+ principal?.type === 'api_key' && principal.projectId !== undefined
67
+ ? {
68
+ apiKeyId: principal.id,
69
+ environment: principal.environment,
70
+ orgId: principal.orgId,
71
+ projectId: principal.projectId,
72
+ }
73
+ : undefined
74
+ const sponsorable =
75
+ attribution !== undefined &&
76
+ principal?.type === 'api_key' &&
77
+ (principal.apiKey.scopes.includes('rpc-relay:sponsor') ||
78
+ principal.apiKey.scopes.includes(Scope.wildcard))
79
+ return {
80
+ ...options.feePayer,
81
+ feeToken: options.feePayer.feeToken ?? Addresses.pathUsd,
82
+ validate: ({ chainId }) => {
83
+ // Allowlist the chains this deployment serves rather than denylisting
84
+ // only mainnet: the relay resolves chainId from the request body, so
85
+ // the query-string chain guard never sees it. Mainnet stays closed
86
+ // until billing ships; nothing meters real fee-payer spend yet.
87
+ const id = Number(chainId)
88
+ return sponsorable && c.get('supportedChainIds').has(id) && !Viem.isMainnet(id)
89
+ },
90
+ onSponsored: async (event) => {
91
+ if (!attribution) return
92
+ await SponsoredTransactions.upsert(Db.get(c.get('db')), {
93
+ apiKeyId: attribution.apiKeyId,
94
+ billable: attribution.environment === 'production',
95
+ chainId: event.chainId,
96
+ environment: attribution.environment,
97
+ orgId: attribution.orgId,
98
+ projectId: attribution.projectId,
99
+ signPayload: event.signPayload,
100
+ transaction: event.transaction,
101
+ ...(event.feeToken ? { feeToken: event.feeToken } : {}),
102
+ ...(event.transactionHash ? { transactionHash: event.transactionHash } : {}),
103
+ })
104
+ },
105
+ } satisfies Handler.relay.Options['feePayer']
106
+ })()
107
+
108
+ // Dispatching a standalone Hono via `fetch(c.req.raw)` bypasses Hono's
109
+ // mount-path stripping, so its internal routes register at the request's
110
+ // full external path (`basePath` + `/rpc/relay`).
111
+ const handler = Handler.relay({
112
+ cache: c.get('store'),
113
+ features: 'all',
114
+ getClient: (chainId) => c.get('getClient')(chainId as Viem.ChainId | undefined),
115
+ path: Path.join(c.get('basePath'), 'rpc/relay'),
116
+ ...(feePayer ? { feePayer } : {}),
117
+ ...(verifiedTokens
118
+ ? {
119
+ resolveTokens: async (chainId: number) => {
120
+ const snapshot = await VerifiedTokens.read(Db.get(c.get('dbCached')), chainId)
121
+ return snapshot?.list.map((token) => token.address) ?? []
122
+ },
123
+ }
124
+ : {}),
125
+ })
126
+ return handler.fetch(c.req.raw)
127
+ })
128
+ }