tapimo 0.5.3 → 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 (376) hide show
  1. package/dist/App.d.ts +15830 -7220
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +9 -1
  4. package/dist/App.js.map +1 -1
  5. package/dist/Scope.d.ts +4 -0
  6. package/dist/Scope.d.ts.map +1 -1
  7. package/dist/Scope.js +5 -0
  8. package/dist/Scope.js.map +1 -1
  9. package/dist/admin/App.d.ts +1011 -412
  10. package/dist/admin/App.d.ts.map +1 -1
  11. package/dist/admin/App.js +4 -0
  12. package/dist/admin/App.js.map +1 -1
  13. package/dist/admin/apps/api-keys.d.ts +2 -1
  14. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  15. package/dist/admin/apps/early-access.d.ts +148 -0
  16. package/dist/admin/apps/early-access.d.ts.map +1 -0
  17. package/dist/admin/apps/early-access.js +133 -0
  18. package/dist/admin/apps/early-access.js.map +1 -0
  19. package/dist/admin/apps/organizations.d.ts +124 -1
  20. package/dist/admin/apps/organizations.d.ts.map +1 -1
  21. package/dist/admin/apps/organizations.js +97 -6
  22. package/dist/admin/apps/organizations.js.map +1 -1
  23. package/dist/admin/apps/verified-tokens.d.ts +526 -1
  24. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  25. package/dist/admin/apps/verified-tokens.js +214 -1
  26. package/dist/admin/apps/verified-tokens.js.map +1 -1
  27. package/dist/admin/ui.generated.d.ts +1 -1
  28. package/dist/admin/ui.generated.d.ts.map +1 -1
  29. package/dist/admin/ui.generated.js +95 -75
  30. package/dist/admin/ui.generated.js.map +1 -1
  31. package/dist/analytics/Analytics.d.ts.map +1 -1
  32. package/dist/analytics/Analytics.js +20 -0
  33. package/dist/analytics/Analytics.js.map +1 -1
  34. package/dist/analytics/tables/requestEvents.d.ts +18 -0
  35. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  36. package/dist/analytics/tables/requestEvents.js +36 -7
  37. package/dist/analytics/tables/requestEvents.js.map +1 -1
  38. package/dist/apps/data/App.d.ts +6260 -4924
  39. package/dist/apps/data/App.d.ts.map +1 -1
  40. package/dist/apps/data/App.js +11 -6
  41. package/dist/apps/data/App.js.map +1 -1
  42. package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
  43. package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
  44. package/dist/apps/data/FundingQuoteProviders.js +194 -16
  45. package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
  46. package/dist/apps/data/FxOracle.d.ts +71 -0
  47. package/dist/apps/data/FxOracle.d.ts.map +1 -0
  48. package/dist/apps/data/FxOracle.js +97 -0
  49. package/dist/apps/data/FxOracle.js.map +1 -0
  50. package/dist/apps/data/index.d.ts +1 -0
  51. package/dist/apps/data/index.d.ts.map +1 -1
  52. package/dist/apps/data/index.js +1 -0
  53. package/dist/apps/data/index.js.map +1 -1
  54. package/dist/apps/data/routes/activities.d.ts +3599 -1382
  55. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  56. package/dist/apps/data/routes/activities.js +250 -88
  57. package/dist/apps/data/routes/activities.js.map +1 -1
  58. package/dist/apps/data/routes/addresses.d.ts +872 -251
  59. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  60. package/dist/apps/data/routes/addresses.js +11 -9
  61. package/dist/apps/data/routes/addresses.js.map +1 -1
  62. package/dist/apps/data/routes/balances.d.ts +77 -26
  63. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  64. package/dist/apps/data/routes/balances.js +88 -45
  65. package/dist/apps/data/routes/balances.js.map +1 -1
  66. package/dist/apps/data/routes/blocks.d.ts +39 -39
  67. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  68. package/dist/apps/data/routes/exchanges.d.ts +856 -105
  69. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  70. package/dist/apps/data/routes/exchanges.js +518 -76
  71. package/dist/apps/data/routes/exchanges.js.map +1 -1
  72. package/dist/apps/data/routes/fee-amm.d.ts +81 -67
  73. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  74. package/dist/apps/data/routes/fee-amm.js +76 -91
  75. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  76. package/dist/apps/data/routes/funding.d.ts +80 -36
  77. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  78. package/dist/apps/data/routes/funding.js +65 -31
  79. package/dist/apps/data/routes/funding.js.map +1 -1
  80. package/dist/apps/data/routes/receipts.d.ts +392 -315
  81. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  82. package/dist/apps/data/routes/receipts.js +152 -77
  83. package/dist/apps/data/routes/receipts.js.map +1 -1
  84. package/dist/apps/data/routes/tokens.d.ts +167 -174
  85. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  86. package/dist/apps/data/routes/tokens.js +15 -13
  87. package/dist/apps/data/routes/tokens.js.map +1 -1
  88. package/dist/apps/data/routes/transactions.d.ts +277 -536
  89. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  90. package/dist/apps/data/routes/transactions.js +96 -77
  91. package/dist/apps/data/routes/transactions.js.map +1 -1
  92. package/dist/apps/data/routes/transfers.d.ts +157 -81
  93. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  94. package/dist/apps/data/routes/transfers.js +272 -130
  95. package/dist/apps/data/routes/transfers.js.map +1 -1
  96. package/dist/apps/data/routes/valuation.d.ts +307 -0
  97. package/dist/apps/data/routes/valuation.d.ts.map +1 -0
  98. package/dist/apps/data/routes/valuation.js +292 -0
  99. package/dist/apps/data/routes/valuation.js.map +1 -0
  100. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  101. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  102. package/dist/apps/data/routes/verified-tokens.js +7 -5
  103. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  104. package/dist/apps/data/routes/webhooks.d.ts +103 -123
  105. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  106. package/dist/apps/data/routes/webhooks.js +124 -25
  107. package/dist/apps/data/routes/webhooks.js.map +1 -1
  108. package/dist/apps/index.d.ts +2 -1
  109. package/dist/apps/index.d.ts.map +1 -1
  110. package/dist/apps/index.js +2 -1
  111. package/dist/apps/index.js.map +1 -1
  112. package/dist/apps/management/App.d.ts +8554 -1692
  113. package/dist/apps/management/App.d.ts.map +1 -1
  114. package/dist/apps/management/App.js +12 -1
  115. package/dist/apps/management/App.js.map +1 -1
  116. package/dist/apps/management/routes/api-keys.d.ts +7 -0
  117. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  118. package/dist/apps/management/routes/api-keys.js +17 -3
  119. package/dist/apps/management/routes/api-keys.js.map +1 -1
  120. package/dist/apps/management/routes/billing.d.ts +157 -162
  121. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  122. package/dist/apps/management/routes/billing.js +31 -23
  123. package/dist/apps/management/routes/billing.js.map +1 -1
  124. package/dist/apps/management/routes/faucet.d.ts +232 -0
  125. package/dist/apps/management/routes/faucet.d.ts.map +1 -0
  126. package/dist/apps/management/routes/faucet.js +154 -0
  127. package/dist/apps/management/routes/faucet.js.map +1 -0
  128. package/dist/apps/management/routes/invitations.d.ts +60 -60
  129. package/dist/apps/management/routes/invite-links.d.ts +49 -20
  130. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  131. package/dist/apps/management/routes/invite-links.js +26 -1
  132. package/dist/apps/management/routes/invite-links.js.map +1 -1
  133. package/dist/apps/management/routes/me.d.ts +6 -6
  134. package/dist/apps/management/routes/members.d.ts +6 -6
  135. package/dist/apps/management/routes/orgs.d.ts +42 -42
  136. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  137. package/dist/apps/management/routes/orgs.js +5 -0
  138. package/dist/apps/management/routes/orgs.js.map +1 -1
  139. package/dist/apps/management/routes/projects.d.ts +44 -44
  140. package/dist/apps/management/routes/usage.d.ts +3 -0
  141. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  142. package/dist/apps/management/routes/usage.js +4 -0
  143. package/dist/apps/management/routes/usage.js.map +1 -1
  144. package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
  145. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
  146. package/dist/apps/management/routes/verified-token-requests.js +271 -0
  147. package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
  148. package/dist/apps/management/routes/webhooks.d.ts +6977 -0
  149. package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
  150. package/dist/apps/management/routes/webhooks.js +573 -0
  151. package/dist/apps/management/routes/webhooks.js.map +1 -0
  152. package/dist/apps/mpp/App.d.ts +363 -0
  153. package/dist/apps/mpp/App.d.ts.map +1 -0
  154. package/dist/apps/mpp/App.js +72 -0
  155. package/dist/apps/mpp/App.js.map +1 -0
  156. package/dist/apps/mpp/Mpp.d.ts +178 -0
  157. package/dist/apps/mpp/Mpp.d.ts.map +1 -0
  158. package/dist/apps/mpp/Mpp.js +183 -0
  159. package/dist/apps/mpp/Mpp.js.map +1 -0
  160. package/dist/apps/mpp/index.d.ts +3 -0
  161. package/dist/apps/mpp/index.d.ts.map +1 -0
  162. package/dist/apps/mpp/index.js +3 -0
  163. package/dist/apps/mpp/index.js.map +1 -0
  164. package/dist/apps/relay/App.d.ts.map +1 -1
  165. package/dist/apps/relay/App.js +56 -9
  166. package/dist/apps/relay/App.js.map +1 -1
  167. package/dist/db/Db.d.ts +6 -0
  168. package/dist/db/Db.d.ts.map +1 -1
  169. package/dist/db/Db.js +110 -0
  170. package/dist/db/Db.js.map +1 -1
  171. package/dist/db/Schema.d.ts +53 -0
  172. package/dist/db/Schema.d.ts.map +1 -1
  173. package/dist/db/Schema.js +56 -0
  174. package/dist/db/Schema.js.map +1 -1
  175. package/dist/db/tables/earlyAccess.d.ts +50 -0
  176. package/dist/db/tables/earlyAccess.d.ts.map +1 -0
  177. package/dist/db/tables/earlyAccess.js +63 -0
  178. package/dist/db/tables/earlyAccess.js.map +1 -0
  179. package/dist/db/tables/enabledBillingSources.d.ts +73 -0
  180. package/dist/db/tables/enabledBillingSources.d.ts.map +1 -0
  181. package/dist/db/tables/enabledBillingSources.js +69 -0
  182. package/dist/db/tables/enabledBillingSources.js.map +1 -0
  183. package/dist/db/tables/invitations.d.ts.map +1 -1
  184. package/dist/db/tables/invitations.js +3 -0
  185. package/dist/db/tables/invitations.js.map +1 -1
  186. package/dist/db/tables/inviteLinks.d.ts +10 -2
  187. package/dist/db/tables/inviteLinks.d.ts.map +1 -1
  188. package/dist/db/tables/inviteLinks.js +10 -1
  189. package/dist/db/tables/inviteLinks.js.map +1 -1
  190. package/dist/db/tables/organizations.d.ts +5 -2
  191. package/dist/db/tables/organizations.d.ts.map +1 -1
  192. package/dist/db/tables/organizations.js +13 -2
  193. package/dist/db/tables/organizations.js.map +1 -1
  194. package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
  195. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  196. package/dist/db/tables/sponsoredTransactions.js +2 -0
  197. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  198. package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
  199. package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
  200. package/dist/db/tables/verifiedTokenRequests.js +120 -0
  201. package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
  202. package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
  203. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  204. package/dist/db/tables/webhookSubscriptions.js +16 -0
  205. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  206. package/dist/handlers/internal/utils.d.ts +1 -16
  207. package/dist/handlers/internal/utils.d.ts.map +1 -1
  208. package/dist/handlers/internal/utils.js +17 -6
  209. package/dist/handlers/internal/utils.js.map +1 -1
  210. package/dist/handlers/relay.d.ts.map +1 -1
  211. package/dist/handlers/relay.js +37 -5
  212. package/dist/handlers/relay.js.map +1 -1
  213. package/dist/internal/Auth.d.ts +11 -2
  214. package/dist/internal/Auth.d.ts.map +1 -1
  215. package/dist/internal/Auth.js +14 -47
  216. package/dist/internal/Auth.js.map +1 -1
  217. package/dist/internal/FundingQuotes.d.ts +147 -47
  218. package/dist/internal/FundingQuotes.d.ts.map +1 -1
  219. package/dist/internal/FundingQuotes.js +119 -33
  220. package/dist/internal/FundingQuotes.js.map +1 -1
  221. package/dist/internal/Log.d.ts +37 -5
  222. package/dist/internal/Log.d.ts.map +1 -1
  223. package/dist/internal/Log.js +52 -3
  224. package/dist/internal/Log.js.map +1 -1
  225. package/dist/internal/MetricSink.d.ts.map +1 -1
  226. package/dist/internal/MetricSink.js +24 -0
  227. package/dist/internal/MetricSink.js.map +1 -1
  228. package/dist/internal/OpenApi.d.ts +2 -2
  229. package/dist/internal/OpenApi.d.ts.map +1 -1
  230. package/dist/internal/OpenApi.js +3 -0
  231. package/dist/internal/OpenApi.js.map +1 -1
  232. package/dist/internal/Response.d.ts +2 -2
  233. package/dist/internal/Response.d.ts.map +1 -1
  234. package/dist/internal/Response.js +12 -4
  235. package/dist/internal/Response.js.map +1 -1
  236. package/dist/internal/Schema.d.ts +14 -5
  237. package/dist/internal/Schema.d.ts.map +1 -1
  238. package/dist/internal/Schema.js +23 -5
  239. package/dist/internal/Schema.js.map +1 -1
  240. package/dist/internal/Value.d.ts +18 -0
  241. package/dist/internal/Value.d.ts.map +1 -1
  242. package/dist/internal/Value.js +11 -1
  243. package/dist/internal/Value.js.map +1 -1
  244. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  245. package/dist/internal/VerifiedTokens.js +10 -1
  246. package/dist/internal/VerifiedTokens.js.map +1 -1
  247. package/dist/internal/Webhooks.d.ts +24 -3
  248. package/dist/internal/Webhooks.d.ts.map +1 -1
  249. package/dist/internal/Webhooks.js +34 -8
  250. package/dist/internal/Webhooks.js.map +1 -1
  251. package/package.json +7 -2
  252. package/src/App.test.ts +9 -4
  253. package/src/App.ts +23 -3
  254. package/src/Client.test-d.ts +733 -20
  255. package/src/Scope.ts +5 -0
  256. package/src/admin/App.test.ts +4 -0
  257. package/src/admin/App.ts +4 -0
  258. package/src/admin/apps/early-access.test.ts +125 -0
  259. package/src/admin/apps/early-access.ts +176 -0
  260. package/src/admin/apps/organizations.test.ts +86 -2
  261. package/src/admin/apps/organizations.ts +155 -31
  262. package/src/admin/apps/scopes.test.ts +5 -0
  263. package/src/admin/apps/verified-tokens.test.ts +201 -0
  264. package/src/admin/apps/verified-tokens.ts +532 -286
  265. package/src/admin/ui/plugin.ts +2 -1
  266. package/src/admin/ui/src/lib/early-access.ts +63 -0
  267. package/src/admin/ui/src/lib/organizations.test.ts +81 -1
  268. package/src/admin/ui/src/lib/organizations.ts +92 -0
  269. package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
  270. package/src/admin/ui/src/routeTree.gen.ts +33 -2
  271. package/src/admin/ui/src/routes/__root.tsx +2 -1
  272. package/src/admin/ui/src/routes/api-keys.tsx +1 -1
  273. package/src/admin/ui/src/routes/early-access.tsx +162 -0
  274. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
  275. package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
  276. package/src/admin/ui.generated.ts +95 -94
  277. package/src/analytics/Analytics.test.ts +83 -0
  278. package/src/analytics/Analytics.ts +20 -0
  279. package/src/analytics/tables/requestEvents.ts +60 -7
  280. package/src/apps/composition.test.ts +11 -2
  281. package/src/apps/data/App.test.ts +1 -1
  282. package/src/apps/data/App.ts +22 -14
  283. package/src/apps/data/FundingQuoteProviders.test.ts +297 -4
  284. package/src/apps/data/FundingQuoteProviders.ts +255 -29
  285. package/src/apps/data/FxOracle.test.ts +118 -0
  286. package/src/apps/data/FxOracle.ts +153 -0
  287. package/src/apps/data/index.ts +1 -0
  288. package/src/apps/data/routes/activities.test.ts +177 -3
  289. package/src/apps/data/routes/activities.ts +441 -132
  290. package/src/apps/data/routes/addresses.ts +19 -9
  291. package/src/apps/data/routes/balances.test.ts +148 -11
  292. package/src/apps/data/routes/balances.ts +140 -51
  293. package/src/apps/data/routes/exchanges.test.ts +544 -9
  294. package/src/apps/data/routes/exchanges.ts +690 -103
  295. package/src/apps/data/routes/fee-amm.test.ts +47 -23
  296. package/src/apps/data/routes/fee-amm.ts +98 -119
  297. package/src/apps/data/routes/funding.test.ts +113 -8
  298. package/src/apps/data/routes/funding.ts +77 -51
  299. package/src/apps/data/routes/receipts.test.ts +129 -23
  300. package/src/apps/data/routes/receipts.ts +205 -100
  301. package/src/apps/data/routes/tokens.test.ts +43 -0
  302. package/src/apps/data/routes/tokens.ts +28 -13
  303. package/src/apps/data/routes/transactions.test.ts +72 -19
  304. package/src/apps/data/routes/transactions.ts +162 -92
  305. package/src/apps/data/routes/transfers.test.ts +341 -31
  306. package/src/apps/data/routes/transfers.ts +358 -158
  307. package/src/apps/data/routes/valuation.test.ts +437 -0
  308. package/src/apps/data/routes/valuation.ts +423 -0
  309. package/src/apps/data/routes/verified-tokens.ts +14 -2
  310. package/src/apps/data/routes/webhooks.test.ts +56 -8
  311. package/src/apps/data/routes/webhooks.ts +144 -27
  312. package/src/apps/index.ts +2 -1
  313. package/src/apps/management/App.ts +13 -0
  314. package/src/apps/management/routes/api-keys.test.ts +14 -0
  315. package/src/apps/management/routes/api-keys.ts +27 -3
  316. package/src/apps/management/routes/billing.test.ts +152 -20
  317. package/src/apps/management/routes/billing.ts +34 -18
  318. package/src/apps/management/routes/faucet.test.ts +87 -0
  319. package/src/apps/management/routes/faucet.ts +201 -0
  320. package/src/apps/management/routes/invite-links.test.ts +117 -0
  321. package/src/apps/management/routes/invite-links.ts +43 -1
  322. package/src/apps/management/routes/me.test.ts +9 -99
  323. package/src/apps/management/routes/orgs.test.ts +45 -2
  324. package/src/apps/management/routes/orgs.ts +6 -0
  325. package/src/apps/management/routes/scopes.test.ts +1 -0
  326. package/src/apps/management/routes/usage.test.ts +6 -0
  327. package/src/apps/management/routes/usage.ts +7 -0
  328. package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
  329. package/src/apps/management/routes/verified-token-requests.ts +397 -0
  330. package/src/apps/management/routes/webhooks.test.ts +426 -0
  331. package/src/apps/management/routes/webhooks.ts +672 -0
  332. package/src/apps/mpp/App.ts +86 -0
  333. package/src/apps/mpp/Mpp.test.ts +193 -0
  334. package/src/apps/mpp/Mpp.ts +353 -0
  335. package/src/apps/mpp/index.ts +2 -0
  336. package/src/apps/mpp/internal/Adapter.ts +11 -0
  337. package/src/apps/mpp/internal/Error.ts +9 -0
  338. package/src/apps/mpp/internal/Idempotency.ts +7 -0
  339. package/src/apps/mpp/internal/Screening.ts +10 -0
  340. package/src/apps/relay/App.test.ts +88 -6
  341. package/src/apps/relay/App.ts +61 -9
  342. package/src/db/Db.test.ts +19 -0
  343. package/src/db/Db.ts +125 -0
  344. package/src/db/Schema.ts +68 -0
  345. package/src/db/tables/earlyAccess.ts +86 -0
  346. package/src/db/tables/enabledBillingSources.test.ts +303 -0
  347. package/src/db/tables/enabledBillingSources.ts +118 -0
  348. package/src/db/tables/invitations.ts +3 -0
  349. package/src/db/tables/inviteLinks.ts +22 -3
  350. package/src/db/tables/organizations.test.ts +103 -0
  351. package/src/db/tables/organizations.ts +18 -2
  352. package/src/db/tables/sponsoredTransactions.ts +4 -0
  353. package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
  354. package/src/db/tables/verifiedTokenRequests.ts +182 -0
  355. package/src/db/tables/webhookSubscriptions.ts +31 -0
  356. package/src/handlers/internal/utils.ts +22 -6
  357. package/src/handlers/relay.errors.test.ts +153 -0
  358. package/src/handlers/relay.ts +42 -7
  359. package/src/internal/Auth.test.ts +3 -3
  360. package/src/internal/Auth.ts +15 -47
  361. package/src/internal/FundingQuotes.test.ts +161 -6
  362. package/src/internal/FundingQuotes.ts +141 -39
  363. package/src/internal/Log.test-d.ts +21 -0
  364. package/src/internal/Log.test.ts +141 -0
  365. package/src/internal/Log.ts +93 -6
  366. package/src/internal/MetricSink.test.ts +215 -0
  367. package/src/internal/MetricSink.ts +24 -0
  368. package/src/internal/OpenApi.ts +3 -0
  369. package/src/internal/Response.test.ts +28 -0
  370. package/src/internal/Response.ts +12 -4
  371. package/src/internal/Schema.ts +50 -5
  372. package/src/internal/Value.test.ts +20 -0
  373. package/src/internal/Value.ts +24 -1
  374. package/src/internal/VerifiedTokens.ts +9 -1
  375. package/src/internal/Webhooks.test.ts +140 -0
  376. package/src/internal/Webhooks.ts +53 -9
@@ -1,12 +1,81 @@
1
1
  import type * as z from 'zod/mini'
2
- import { Schema } from 'tapimo'
2
+ import { Value as core_Value } from 'ox'
3
+ import { Db, Schema } from 'tapimo'
4
+ import { FxOracle } from 'tapimo/apps'
3
5
 
4
6
  import * as TestApp from '../../../../test/App.js'
5
7
  import * as Runtime from '../../../../test/runtime.js'
6
8
  import * as Transfers from './transfers.js'
7
9
 
10
+ // Deterministic EUR-based rate set so conversion math is exact in assertions.
11
+ const fixed = FxOracle.from({
12
+ name: 'fixed',
13
+ rates: async () => ({
14
+ asOf: '2026-01-01T00:00:00.000Z',
15
+ base: 'EUR',
16
+ rates: { AUD: '1.6', USD: '1.0' },
17
+ }),
18
+ })
19
+
8
20
  describe('GET /transfers', () => {
9
- test('returns an unscoped transfer page, embedding tokens on demand', async () => {
21
+ test('parses granular token includes', () => {
22
+ expect(
23
+ Transfers.schema.getTransfers.Query.parse({
24
+ include: 'token.logoUri,token.verified',
25
+ }).include,
26
+ ).toMatchInlineSnapshot(`
27
+ [
28
+ "token.logoUri",
29
+ "token.verified",
30
+ ]
31
+ `)
32
+ expect(Transfers.schema.getTransfers.Query.safeParse({ include: 'token' }).success).toBe(false)
33
+ })
34
+
35
+ test('degrades unavailable verification data to null valuations', async () => {
36
+ const db = () =>
37
+ Db.postgres({
38
+ connectionString: 'postgresql://postgres:postgres@127.0.0.1:1/none',
39
+ })
40
+ const client = TestApp.client({ db, fx: { oracle: fixed } })
41
+
42
+ const response = await client.v1.transfers.$get(
43
+ { query: { limit: '5', token: TestApp.tokenWithHolders } },
44
+ TestApp.auth,
45
+ )
46
+ const body = await TestApp.json(response, Transfers.schema.getTransfers.Response)
47
+
48
+ expect(response.status).toBe(200)
49
+ expect(body.data.length).toBeGreaterThan(0)
50
+ for (const entry of body.data) expect(entry.sourceAmount.valuation).toBeNull()
51
+
52
+ const emptyResponse = await client.v1.transfers.$get(
53
+ { query: { limit: '5', token: `0x${'11'.repeat(20)}` } },
54
+ TestApp.auth,
55
+ )
56
+ const empty = await TestApp.json(emptyResponse, Transfers.schema.getTransfers.Response)
57
+ expect(emptyResponse.status).toBe(200)
58
+ expect(empty.data).toMatchInlineSnapshot(`[]`)
59
+ expect(emptyResponse.headers.get('server-timing')?.includes('verified_tokens;dur=')).not.toBe(
60
+ true,
61
+ )
62
+
63
+ const unsupportedResponse = await client.v1.transfers.$get(
64
+ {
65
+ query: {
66
+ denomination: 'JPY',
67
+ limit: '5',
68
+ token: TestApp.tokenWithHolders,
69
+ },
70
+ },
71
+ TestApp.auth,
72
+ )
73
+ const unsupported = await TestApp.json(unsupportedResponse, Schema.ErrorResponse)
74
+ expect(unsupportedResponse.status).toBe(400)
75
+ expect(unsupported.error.code).toBe('query_invalid')
76
+ })
77
+
78
+ test('returns an unscoped transfer page with token metadata', async () => {
10
79
  const client = TestApp.client()
11
80
  const baseResponse = await client.v1.transfers.$get({ query: { limit: '5' } }, TestApp.auth)
12
81
  const base = await TestApp.json(baseResponse, Transfers.schema.getTransfers.Response)
@@ -23,7 +92,14 @@ describe('GET /transfers', () => {
23
92
  base.data.every(
24
93
  (entry) =>
25
94
  /^0x[0-9a-f]{40}$/.test(entry.sourceToken.address) &&
26
- /^\d+$/.test(entry.sourceToken.amount) &&
95
+ /^\d+$/.test(entry.sourceAmount.baseUnits) &&
96
+ typeof entry.sourceAmount.currency === 'string' &&
97
+ Number.isInteger(entry.sourceAmount.decimals) &&
98
+ typeof entry.sourceAmount.formatted === 'string' &&
99
+ typeof entry.sourceToken.currency === 'string' &&
100
+ Number.isInteger(entry.sourceToken.decimals) &&
101
+ typeof entry.sourceToken.name === 'string' &&
102
+ typeof entry.sourceToken.symbol === 'string' &&
27
103
  Number.isInteger(entry.blockNumber) &&
28
104
  /^0x[0-9a-f]{40}$/.test(entry.sender) &&
29
105
  /^0x[0-9a-f]{40}$/.test(entry.recipient) &&
@@ -34,28 +110,35 @@ describe('GET /transfers', () => {
34
110
  // Transfers default to newest-first (descending block number).
35
111
  const blocks = base.data.map((entry) => entry.blockNumber)
36
112
  expect(blocks.every((block, index) => index === 0 || blocks[index - 1]! >= block)).toBe(true)
37
- // Token metadata is opt-in: the base page's `sourceToken` carries only
38
- // `address`/`amount`, with no metadata fields spread in.
39
- expect(base.data.every((entry) => entry.sourceToken.symbol === undefined)).toBe(true)
113
+ // Quantities live beside the token reference; curated fields remain opt-in.
114
+ expect(
115
+ base.data.every(
116
+ (entry) =>
117
+ !('amount' in entry.sourceToken) &&
118
+ !('valuation' in entry.sourceToken) &&
119
+ entry.sourceToken.logoUri === undefined &&
120
+ entry.sourceToken.verified === undefined,
121
+ ),
122
+ ).toBe(true)
40
123
 
41
124
  const includedResponse = await client.v1.transfers.$get(
42
- { query: { limit: '5', include: 'token' } },
125
+ { query: { limit: '5', include: 'token.logoUri,token.verified' } },
43
126
  TestApp.auth,
44
127
  )
45
128
  const included = await TestApp.json(includedResponse, Transfers.schema.getTransfers.Response)
46
129
 
47
130
  expect(includedResponse.status).toBe(200)
48
- // Each `sourceToken` keeps its `address`/`amount`; when metadata resolves
49
- // it is spread alongside. Resolution is best-effort, so a row whose
50
- // metadata is unavailable simply omits the metadata fields.
131
+ // Curated fields remain optional without moving quantities back into the token.
51
132
  expect(
52
133
  included.data.every(
53
134
  (entry) =>
54
135
  /^0x[0-9a-f]{40}$/.test(entry.sourceToken.address) &&
55
- /^\d+$/.test(entry.sourceToken.amount) &&
56
- (entry.sourceToken.symbol === undefined ||
57
- (typeof entry.sourceToken.symbol === 'string' &&
58
- Number.isInteger(entry.sourceToken.decimals))),
136
+ /^\d+$/.test(entry.sourceAmount.baseUnits) &&
137
+ !('amount' in entry.sourceToken) &&
138
+ !('valuation' in entry.sourceToken) &&
139
+ typeof entry.sourceToken.symbol === 'string' &&
140
+ Number.isInteger(entry.sourceToken.decimals) &&
141
+ typeof entry.sourceToken.verified === 'boolean',
59
142
  ),
60
143
  ).toBe(true)
61
144
  })
@@ -74,24 +157,156 @@ describe('GET /transfers', () => {
74
157
 
75
158
  test('narrows transfers by address (either side)', async () => {
76
159
  const client = TestApp.client()
77
- // Seed a real account from a recent transfer.
78
- const seedResponse = await client.v1.transfers.$get({ query: { limit: '5' } }, TestApp.auth)
79
- const seed = await TestApp.json(seedResponse, Transfers.schema.getTransfers.Response)
80
- expect(seedResponse.status).toBe(200)
81
- const account = seed.data[0]!.sender
82
- expect(account).toMatch(/^0x[0-9a-f]{40}$/)
83
-
84
- const filteredResponse = await client.v1.transfers.$get(
85
- { query: { limit: '5', address: account } },
160
+ const runtime = Runtime.get()
161
+ const address = Schema.Address.parse(
162
+ runtime.mode === 'testnet'
163
+ ? '0xb1f382bd6deed37895528a6387bae4cd9569ac3c'
164
+ : runtime.fixtures!.fundedAccounts[0]!,
165
+ )
166
+ const response = await client.v1.transfers.$get(
167
+ { query: { address, include: 'totalCount', limit: '10' } },
86
168
  TestApp.auth,
87
169
  )
88
- const filtered = await TestApp.json(filteredResponse, Transfers.schema.getTransfers.Response)
89
- expect(filteredResponse.status).toBe(200)
170
+ const body = await TestApp.json(response, Transfers.schema.getTransfers.Response)
171
+
172
+ expect(response.status).toBe(200)
90
173
  expect(
91
- filtered.data.every((entry) => entry.sender === account || entry.recipient === account),
174
+ body.data.every((entry) => entry.sender === address || entry.recipient === address),
92
175
  ).toBe(true)
176
+ expect(body.meta!.totalCount).toBeGreaterThanOrEqual(body.data.length)
177
+ expect(body.meta!.totalCountCapped).toBe(body.meta!.totalCount! >= Schema.countCap)
93
178
  })
94
179
 
180
+ test.runIf(Runtime.get().mode === 'testnet')(
181
+ 'merges both address sides before paginating',
182
+ async () => {
183
+ const client = TestApp.client()
184
+ const address = '0xabb0023644c54a20d0fe92becfa764dacaf59ba9'
185
+ const toBlock = '27608730'
186
+ const [senderResponse, recipientResponse, addressResponse] = await Promise.all([
187
+ client.v1.transfers.$get(
188
+ {
189
+ query: { 'blockNumber.to': toBlock, limit: '10', order: 'desc', sender: address },
190
+ },
191
+ TestApp.auth,
192
+ ),
193
+ client.v1.transfers.$get(
194
+ {
195
+ query: { 'blockNumber.to': toBlock, limit: '10', order: 'desc', recipient: address },
196
+ },
197
+ TestApp.auth,
198
+ ),
199
+ client.v1.transfers.$get(
200
+ {
201
+ query: { address, 'blockNumber.to': toBlock, limit: '10', order: 'desc' },
202
+ },
203
+ TestApp.auth,
204
+ ),
205
+ ])
206
+ const sender = await TestApp.json(senderResponse, Transfers.schema.getTransfers.Response)
207
+ const recipient = await TestApp.json(
208
+ recipientResponse,
209
+ Transfers.schema.getTransfers.Response,
210
+ )
211
+ const combined = await TestApp.json(addressResponse, Transfers.schema.getTransfers.Response)
212
+
213
+ expect([senderResponse.status, recipientResponse.status, addressResponse.status]).toEqual([
214
+ 200, 200, 200,
215
+ ])
216
+ const seen = new Set<string>()
217
+ const expected = [...sender.data, ...recipient.data]
218
+ .sort((a, b) => b.blockNumber - a.blockNumber || b.logIndex - a.logIndex)
219
+ .filter((entry) => {
220
+ if (seen.has(entry.id)) return false
221
+ seen.add(entry.id)
222
+ return true
223
+ })
224
+ .slice(0, 10)
225
+ expect(expected).toHaveLength(10)
226
+ expect(combined.data.map(({ id }) => id)).toEqual(expected.map(({ id }) => id))
227
+
228
+ const firstResponse = await client.v1.transfers.$get(
229
+ {
230
+ query: { address, 'blockNumber.to': toBlock, limit: '5', order: 'desc' },
231
+ },
232
+ TestApp.auth,
233
+ )
234
+ const first = await TestApp.json(firstResponse, Transfers.schema.getTransfers.Response)
235
+ expect(firstResponse.status).toBe(200)
236
+ expect(first.nextCursor).not.toBeNull()
237
+ if (!first.nextCursor) return
238
+
239
+ const [cursorResponse, positionalResponse] = await Promise.all([
240
+ client.v1.transfers.$get(
241
+ {
242
+ query: {
243
+ address,
244
+ 'blockNumber.to': toBlock,
245
+ cursor: first.nextCursor,
246
+ limit: '5',
247
+ order: 'desc',
248
+ },
249
+ },
250
+ TestApp.auth,
251
+ ),
252
+ client.v1.transfers.$get(
253
+ {
254
+ query: {
255
+ address,
256
+ 'blockNumber.to': toBlock,
257
+ limit: '5',
258
+ order: 'desc',
259
+ page: '2',
260
+ },
261
+ },
262
+ TestApp.auth,
263
+ ),
264
+ ])
265
+ const cursor = await TestApp.json(cursorResponse, Transfers.schema.getTransfers.Response)
266
+ const positional = await TestApp.json(
267
+ positionalResponse,
268
+ Transfers.schema.getTransfers.Response,
269
+ )
270
+ const expectedSecondPage = expected.slice(5, 10).map(({ id }) => id)
271
+
272
+ expect([cursorResponse.status, positionalResponse.status]).toEqual([200, 200])
273
+ expect([...first.data, ...cursor.data].map(({ id }) => id)).toEqual(
274
+ expected.map(({ id }) => id),
275
+ )
276
+ expect(positional.data.map(({ id }) => id)).toEqual(expectedSecondPage)
277
+ },
278
+ )
279
+
280
+ test.runIf(Runtime.get().mode === 'testnet')(
281
+ 'deduplicates self-transfers in address pages and counts',
282
+ async () => {
283
+ const client = TestApp.client()
284
+ const address = '0xabb0023644c54a20d0fe92becfa764dacaf59ba9'
285
+ const transactionHash = '0x915a11bcf4b5e667c631f9fb09ac8729f3b436f24eb0b552e54ec13a490ef57f'
286
+ const response = await client.v1.transfers.$get(
287
+ {
288
+ query: {
289
+ address,
290
+ 'blockNumber.from': '27608730',
291
+ 'blockNumber.to': '27608730',
292
+ include: 'totalCount',
293
+ limit: '50',
294
+ token: '0x20c0000000000000000000000000000000000003',
295
+ },
296
+ },
297
+ TestApp.auth,
298
+ )
299
+ const body = await TestApp.json(response, Transfers.schema.getTransfers.Response)
300
+
301
+ expect(response.status).toBe(200)
302
+ expect(body.data.filter(({ id }) => id === `${transactionHash}-233`)).toHaveLength(1)
303
+ expect(body.meta).toMatchObject({
304
+ totalCount: body.data.length,
305
+ totalCountCapped: false,
306
+ })
307
+ },
308
+ )
309
+
95
310
  test('narrows transfers by sender and recipient independently', async () => {
96
311
  const client = TestApp.client()
97
312
  const seedResponse = await client.v1.transfers.$get({ query: { limit: '5' } }, TestApp.auth)
@@ -147,6 +362,9 @@ describe('GET /transfers', () => {
147
362
  const second = await TestApp.json(secondResponse, Transfers.schema.getTransfers.Response)
148
363
 
149
364
  expect(secondResponse.status).toBe(200)
365
+ expect(secondResponse.headers.get('cache-control')).toMatchInlineSnapshot(
366
+ `"private, max-age=60, stale-while-revalidate=300"`,
367
+ )
150
368
  expect(second.data.length).toBeGreaterThan(0)
151
369
  // Each row's identity on the unscoped feed is `(blockNumber, txHash,
152
370
  // sourceToken, sender, recipient, amount)` — a single transaction can
@@ -154,7 +372,7 @@ describe('GET /transfers', () => {
154
372
  // `(txHash, blockNumber)` shortcut is not unique here.
155
373
  type Entry = z.output<typeof Transfers.schema.getTransfers.Transfer>
156
374
  const keyOf = (entry: Entry) =>
157
- `${entry.blockNumber}:${entry.transactionHash}:${entry.sourceToken.address}:${entry.sender}:${entry.recipient}:${entry.sourceToken.amount}`
375
+ `${entry.blockNumber}:${entry.transactionHash}:${entry.sourceToken.address}:${entry.sender}:${entry.recipient}:${entry.sourceAmount.baseUnits}`
158
376
  const firstKeys = new Set(first.data.map(keyOf))
159
377
  expect(second.data.every((entry) => !firstKeys.has(keyOf(entry)))).toBe(true)
160
378
  })
@@ -202,7 +420,7 @@ describe('GET /transfers', () => {
202
420
 
203
421
  type Entry = z.output<typeof Transfers.schema.getTransfers.Transfer>
204
422
  const keyOf = (entry: Entry) =>
205
- `${entry.blockNumber}:${entry.transactionHash}:${entry.sourceToken.address}:${entry.sender}:${entry.recipient}:${entry.sourceToken.amount}`
423
+ `${entry.blockNumber}:${entry.transactionHash}:${entry.sourceToken.address}:${entry.sender}:${entry.recipient}:${entry.sourceAmount.baseUnits}`
206
424
  expect(page.data.map(keyOf)).toEqual(head.data.slice(5, 10).map(keyOf))
207
425
  // Offset pages still return a keyset cursor so clients can switch to deep
208
426
  // cursor traversal from a positional jump.
@@ -285,7 +503,7 @@ describe('GET /transfers', () => {
285
503
  expect(Number.isInteger(body.meta?.totalCount)).toBe(true)
286
504
  expect(body.meta!.totalCount).toBeGreaterThanOrEqual(body.data.length)
287
505
  expect(body.meta!.totalCount).toBeLessThanOrEqual(Schema.countCap)
288
- expect(body.meta!.totalCountCapped).toBe(body.meta!.totalCount >= Schema.countCap)
506
+ expect(body.meta!.totalCountCapped).toBe(body.meta!.totalCount! >= Schema.countCap)
289
507
  })
290
508
 
291
509
  test('embeds a capped token-scoped total count on demand', async () => {
@@ -309,7 +527,7 @@ describe('GET /transfers', () => {
309
527
  expect(typeof body.meta?.totalCountCapped).toBe('boolean')
310
528
  // The count never exceeds the cap; `totalCountCapped` is set iff the cap was hit.
311
529
  expect(body.meta!.totalCount).toBeLessThanOrEqual(Schema.countCap)
312
- expect(body.meta!.totalCountCapped).toBe(body.meta!.totalCount >= Schema.countCap)
530
+ expect(body.meta!.totalCountCapped).toBe(body.meta!.totalCount! >= Schema.countCap)
313
531
 
314
532
  // Without `include=totalCount`, the same page omits `meta` entirely and
315
533
  // does not run the count query.
@@ -319,7 +537,10 @@ describe('GET /transfers', () => {
319
537
  )
320
538
  const bare = await TestApp.json(bareResponse, Transfers.schema.getTransfers.Response)
321
539
  expect(bareResponse.status).toBe(200)
322
- expect(bare.meta).toBeUndefined()
540
+ // Without the include, counts are omitted (`meta` carries at most rate
541
+ // provenance).
542
+ expect(bare.meta?.totalCount).toBeUndefined()
543
+ expect(bare.meta?.totalCountCapped).toBeUndefined()
323
544
  expect(bareResponse.headers.get('server-timing')?.includes('transfers_count;dur=')).toBe(false)
324
545
  })
325
546
 
@@ -351,6 +572,10 @@ describe('GET /transfers', () => {
351
572
  expect(transfer.recipient).toBe(crossToken.recipient)
352
573
  expect(transfer.sourceToken.address).toBe(crossToken.sourceToken)
353
574
  expect(transfer.destinationToken?.address).toBe(crossToken.destinationToken)
575
+ expect(transfer.sourceAmount.baseUnits).toMatch(/^\d+$/)
576
+ expect(transfer.destinationAmount?.baseUnits).toMatch(/^\d+$/)
577
+ expect('amount' in transfer.sourceToken).toBe(false)
578
+ expect('amount' in transfer.destinationToken!).toBe(false)
354
579
 
355
580
  // Without `include=crossToken`, the transaction stays as its raw per-log
356
581
  // legs (more than one row) and no row carries `destinationToken`.
@@ -422,6 +647,91 @@ describe('GET /transfers', () => {
422
647
  },
423
648
  )
424
649
 
650
+ test('values verified transfer legs in the default denomination', async () => {
651
+ const db = TestApp.database()
652
+ await TestApp.verifiedSeed(db, Runtime.get().chainId)
653
+ const client = TestApp.client({ db })
654
+
655
+ // pathUSD is curated USD, so its legs value at identity with no rates.
656
+ const response = await client.v1.transfers.$get(
657
+ { query: { limit: '5', token: TestApp.tokenWithHolders } },
658
+ TestApp.auth,
659
+ )
660
+ const body = await TestApp.json(response, Transfers.schema.getTransfers.Response)
661
+
662
+ expect(response.status).toBe(200)
663
+ expect(body.data.length).toBeGreaterThan(0)
664
+ for (const entry of body.data)
665
+ expect(entry.sourceAmount.valuation).toEqual({
666
+ amount: core_Value.format(BigInt(entry.sourceAmount.baseUnits), 6),
667
+ currency: 'USD',
668
+ })
669
+ expect(body.meta?.pricing).toBeUndefined()
670
+ })
671
+
672
+ test('values transfer legs in a requested denomination', async () => {
673
+ const db = TestApp.database()
674
+ await TestApp.verifiedSeed(db, Runtime.get().chainId)
675
+ const client = TestApp.client({ db, fx: { oracle: fixed } })
676
+
677
+ // Denominations are case-insensitive.
678
+ const response = await client.v1.transfers.$get(
679
+ { query: { denomination: 'aud', limit: '5', token: TestApp.tokenWithHolders } },
680
+ TestApp.auth,
681
+ )
682
+ const body = await TestApp.json(response, Transfers.schema.getTransfers.Response)
683
+
684
+ expect(response.status).toBe(200)
685
+ expect(body.data.length).toBeGreaterThan(0)
686
+ // USD -> AUD at the fixed 1.6 cross rate, floored to 6 dp.
687
+ for (const entry of body.data)
688
+ expect(entry.sourceAmount.valuation).toEqual({
689
+ amount: core_Value.format((BigInt(entry.sourceAmount.baseUnits) * 16n) / 10n, 6),
690
+ currency: 'AUD',
691
+ })
692
+ expect(body.meta?.pricing).toMatchInlineSnapshot(`
693
+ {
694
+ "asOf": "2026-01-01T00:00:00.000Z",
695
+ "basis": "nominal",
696
+ "source": "fixed",
697
+ }
698
+ `)
699
+ })
700
+
701
+ test.skipIf(Runtime.get().mode !== 'localnet')(
702
+ 'nulls leg values for unverified tokens',
703
+ async () => {
704
+ // Curate only pathUSD so the faucet token queried below is unverified
705
+ // for this app, and its legs never value.
706
+ const db = TestApp.database()
707
+ await TestApp.verifiedSeed(db, Runtime.get().chainId, {
708
+ tokens: [
709
+ {
710
+ address: TestApp.tokenWithHolders,
711
+ currency: 'USD',
712
+ decimals: 6,
713
+ name: 'PathUSD',
714
+ symbol: 'pathUSD',
715
+ },
716
+ ],
717
+ })
718
+ const client = TestApp.client({ db })
719
+
720
+ const token = Runtime.get().fixtures!.transferTokenAddresses.find(
721
+ (address) => address.toLowerCase() !== TestApp.tokenWithHolders,
722
+ )!
723
+ const response = await client.v1.transfers.$get(
724
+ { query: { limit: '5', token } },
725
+ TestApp.auth,
726
+ )
727
+ const body = await TestApp.json(response, Transfers.schema.getTransfers.Response)
728
+
729
+ expect(response.status).toBe(200)
730
+ expect(body.data.length).toBeGreaterThan(0)
731
+ for (const entry of body.data) expect(entry.sourceAmount.valuation).toBeNull()
732
+ },
733
+ )
734
+
425
735
  test('surfaces a 502 when transfer data is unavailable', async () => {
426
736
  // Point at an unreachable indexer so the upstream query fails deterministically.
427
737
  const client = TestApp.client({ tidx: { baseUrl: 'http://127.0.0.1:1' } })