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
@@ -0,0 +1,437 @@
1
+ import * as fs from 'node:fs'
2
+ import { Value as core_Value } from 'ox'
3
+ import { Schema } from 'tapimo'
4
+ import { FxOracle } from 'tapimo/apps'
5
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
6
+ import { Actions } from 'viem/tempo'
7
+
8
+ import * as TestApp from '../../../../test/App.js'
9
+ import * as Runtime from '../../../../test/runtime.js'
10
+ import * as TestViem from '../../../../test/Viem.js'
11
+ import * as Tokens from './tokens.js'
12
+ import * as Valuation from './valuation.js'
13
+
14
+ const runtime = Runtime.get()
15
+ const db = TestApp.database()
16
+ await TestApp.verifiedSeed(db, runtime.chainId)
17
+ const ecbXml = `<Envelope><Cube><Cube time="2026-01-01"><Cube currency="AUD" rate="1.6"/><Cube currency="USD" rate="1.25"/></Cube></Cube></Envelope>`
18
+ const ecb = FxOracle.ecb({
19
+ url: `data:application/xml,${encodeURIComponent(ecbXml)}`,
20
+ })
21
+ function app(options: TestApp.create.Options = {}) {
22
+ return TestApp.client({ db, fx: { oracle: ecb }, ...options })
23
+ }
24
+
25
+ // Verified snapshots cache per isolate and `verifiedSeed` primes that cache
26
+ // (read-your-write), so tests that depend on a specific list re-seed at their
27
+ // own start. `usdDb` restricts the list to pathUSD so every holding shares one
28
+ // currency, independent of which seed tokens exist on the dev chain.
29
+ const usdDb = TestApp.database()
30
+ const usdTokens = [
31
+ {
32
+ address: TestApp.tokenWithHolders,
33
+ currency: 'USD',
34
+ decimals: 6,
35
+ name: 'PathUSD',
36
+ symbol: 'pathUSD',
37
+ },
38
+ ]
39
+
40
+ // Curated seed backing `verifiedSeed`, used to recompute expected sums from
41
+ // chain state. Localnet reuses the Moderato testnet list (see `verifiedSeed`).
42
+ type SeedToken = { address: `0x${string}`; currency: string; decimals: number }
43
+ const seedChainId = runtime.chainId === 1337 ? 42431 : runtime.chainId
44
+ const seed: readonly SeedToken[] = JSON.parse(
45
+ fs.readFileSync(
46
+ new URL(`../../../../seeds/${seedChainId}/verified-tokens.json`, import.meta.url),
47
+ 'utf8',
48
+ ),
49
+ )
50
+
51
+ // Deterministic EUR-based rate set so conversion math is exact in assertions.
52
+ const fixed = FxOracle.from({
53
+ name: 'fixed',
54
+ rates: async () => ({
55
+ asOf: '2026-01-01T00:00:00.000Z',
56
+ base: 'EUR',
57
+ rates: { AUD: '1.6', USD: '1.0' },
58
+ }),
59
+ })
60
+
61
+ async function holderWithBalance(client: ReturnType<typeof app>) {
62
+ if (runtime.mode === 'localnet')
63
+ return runtime.fixtures!.fundedAccounts[0]!.toLowerCase() as `0x${string}`
64
+ const holdersResponse = await client.v1.tokens[':token'].holders.$get(
65
+ { param: { token: TestApp.tokenWithHolders }, query: { limit: '5' } },
66
+ TestApp.auth,
67
+ )
68
+ const holders = await TestApp.json(holdersResponse, Tokens.schema.getTokenHolders.Response)
69
+ expect(holdersResponse.status).toBe(200)
70
+ const holder = holders.data[0]?.address
71
+ if (!holder) throw new Error('expected at least one holder')
72
+ return holder
73
+ }
74
+
75
+ /** Fresh account address guaranteed to hold nothing. */
76
+ function emptyAccount() {
77
+ return privateKeyToAccount(generatePrivateKey()).address.toLowerCase() as `0x${string}`
78
+ }
79
+
80
+ /**
81
+ * Sums the holder's on-chain balances across curated tokens of one currency,
82
+ * in 6-dp base units. Unreadable tokens (undeployed or uninitialized on this
83
+ * chain) count as empty, matching the endpoint's declared scope.
84
+ */
85
+ async function chainSum(holder: `0x${string}`, currency: string) {
86
+ const rpc = TestViem.getClient()
87
+ const amounts = await Promise.all(
88
+ seed
89
+ .filter((token) => token.currency === currency)
90
+ .map((token) =>
91
+ Actions.token
92
+ .getBalance(rpc, { account: holder, decimals: token.decimals, token: token.address })
93
+ .catch(() => ({ amount: 0n })),
94
+ ),
95
+ )
96
+ return amounts.reduce((sum, { amount }) => sum + amount, 0n)
97
+ }
98
+
99
+ describe('GET /addresses/:address/valuation', () => {
100
+ test('requires a full pricing timestamp', () => {
101
+ const pricing = { asOf: '2026-01-01', basis: 'nominal', source: 'fixed' }
102
+ expect(Valuation.schema.Pricing.safeParse(pricing).success).toBe(false)
103
+ expect(
104
+ Valuation.schema.Pricing.safeParse({
105
+ ...pricing,
106
+ asOf: '2026-01-01T00:00:00.000Z',
107
+ }).success,
108
+ ).toBe(true)
109
+ })
110
+
111
+ test('normalizes the denomination', () => {
112
+ expect(
113
+ Valuation.schema.getAddressValuation.Query.parse({ denomination: 'aud' }).denomination,
114
+ ).toMatchInlineSnapshot(`"AUD"`)
115
+ expect(
116
+ Valuation.schema.getAddressValuation.Query.safeParse({ denomination: 'DOLLARS' }).success,
117
+ ).toBe(false)
118
+ })
119
+
120
+ test('values verified holdings in the default denomination', async () => {
121
+ await TestApp.verifiedSeed(db, runtime.chainId)
122
+ const client = app()
123
+ const holder = await holderWithBalance(client)
124
+
125
+ const response = await client.v1.addresses[':address'].valuation.$get(
126
+ { param: { address: holder }, query: {} },
127
+ TestApp.auth,
128
+ )
129
+ const body = await TestApp.json(response, Valuation.schema.getAddressValuation.Response)
130
+
131
+ expect(response.status).toBe(200)
132
+ expect(response.headers.get('server-timing')?.includes('valuation_balances;dur=')).toBe(true)
133
+ expect(body.address).toBe(holder)
134
+ expect(body.id).toBe(holder)
135
+ expect(body.currency).toBe('USD')
136
+ // The total is the exact on-chain sum of the curated USD holdings; every
137
+ // non-USD currency in the seed is unpriced by ECB, so none of it leaks in.
138
+ expect(body.amount).toBe(core_Value.format(await chainSum(holder, 'USD'), 6))
139
+ })
140
+
141
+ test('returns a zero valuation for an address with no holdings', async () => {
142
+ const account = emptyAccount()
143
+ const response = await app().v1.addresses[':address'].valuation.$get(
144
+ { param: { address: account }, query: {} },
145
+ TestApp.auth,
146
+ )
147
+ const body = await TestApp.json(response, Valuation.schema.getAddressValuation.Response)
148
+ const { address, id, ...stable } = body
149
+
150
+ expect(response.status).toBe(200)
151
+ expect(address).toBe(account)
152
+ expect(id).toBe(account)
153
+ expect(stable).toMatchInlineSnapshot(`
154
+ {
155
+ "amount": "0",
156
+ "currency": "USD",
157
+ "pricing": null,
158
+ "unpriced": [],
159
+ }
160
+ `)
161
+ })
162
+
163
+ test.skipIf(runtime.mode !== 'localnet')(
164
+ 'converts holdings into a requested denomination',
165
+ async () => {
166
+ await TestApp.verifiedSeed(usdDb, runtime.chainId, { tokens: usdTokens })
167
+ const client = app({ db: usdDb, fx: { oracle: fixed } })
168
+ const holder = await holderWithBalance(client)
169
+
170
+ const usdResponse = await client.v1.addresses[':address'].valuation.$get(
171
+ { param: { address: holder }, query: {} },
172
+ TestApp.auth,
173
+ )
174
+ const usd = await TestApp.json(usdResponse, Valuation.schema.getAddressValuation.Response)
175
+ // Denominations are case-insensitive.
176
+ const audResponse = await client.v1.addresses[':address'].valuation.$get(
177
+ { param: { address: holder }, query: { denomination: 'aud' } },
178
+ TestApp.auth,
179
+ )
180
+ const aud = await TestApp.json(audResponse, Valuation.schema.getAddressValuation.Response)
181
+
182
+ expect(usdResponse.status).toBe(200)
183
+ expect(audResponse.status).toBe(200)
184
+ // Every verified holding is USD here, so the USD valuation needs no rates.
185
+ expect(usd.pricing).toBeNull()
186
+ expect(Number(usd.amount)).toBeGreaterThan(0)
187
+
188
+ // USD -> AUD at the fixed 1.6 cross rate, floored to 6 dp.
189
+ const sum = core_Value.from(usd.amount, 6)
190
+ expect(aud.currency).toBe('AUD')
191
+ expect(aud.amount).toBe(core_Value.format((sum * 16n) / 10n, 6))
192
+ expect(aud.pricing).toMatchInlineSnapshot(`
193
+ {
194
+ "asOf": "2026-01-01T00:00:00.000Z",
195
+ "basis": "nominal",
196
+ "source": "fixed",
197
+ }
198
+ `)
199
+ },
200
+ )
201
+
202
+ test('converts via the ECB oracle', async () => {
203
+ await TestApp.verifiedSeed(db, runtime.chainId)
204
+ const client = app()
205
+ const holder = await holderWithBalance(client)
206
+
207
+ const response = await client.v1.addresses[':address'].valuation.$get(
208
+ { param: { address: holder }, query: { denomination: 'EUR' } },
209
+ TestApp.auth,
210
+ )
211
+ const body = await TestApp.json(response, Valuation.schema.getAddressValuation.Response)
212
+
213
+ expect(response.status).toBe(200)
214
+ expect(response.headers.get('server-timing')?.includes('valuation_rates;dur=')).toBe(true)
215
+ expect(body.currency).toBe('EUR')
216
+ expect(Number(body.amount)).toBeGreaterThan(0)
217
+ expect(body.pricing?.basis).toBe('nominal')
218
+ expect(body.pricing?.source).toBe('ecb')
219
+ expect(body.pricing?.asOf).toBe('2026-01-01T00:00:00.000Z')
220
+ })
221
+
222
+ test.skipIf(runtime.mode !== 'localnet')(
223
+ 'discloses holdings the oracle cannot price',
224
+ async () => {
225
+ // Publish a curated list where one genuinely held token carries a
226
+ // non-fiat display currency the oracle has no rate for.
227
+ const rpc = TestViem.getClient()
228
+ const holder = runtime.fixtures!.fundedAccounts[0]!.toLowerCase() as `0x${string}`
229
+ const held = await (async () => {
230
+ for (const token of runtime.fixtures!.transferTokenAddresses) {
231
+ if (token.toLowerCase() === TestApp.tokenWithHolders) continue
232
+ const { amount } = await Actions.token.getBalance(rpc, { account: holder, token })
233
+ if (amount > 0n) return token.toLowerCase() as `0x${string}`
234
+ }
235
+ throw new Error('expected a held fixture token')
236
+ })()
237
+
238
+ const unpricedDb = TestApp.database()
239
+ await TestApp.verifiedSeed(unpricedDb, runtime.chainId, {
240
+ tokens: [
241
+ {
242
+ address: TestApp.tokenWithHolders,
243
+ currency: 'USD',
244
+ decimals: 6,
245
+ name: 'PathUSD',
246
+ symbol: 'pathUSD',
247
+ },
248
+ {
249
+ address: held,
250
+ currency: 'sUSDe',
251
+ decimals: 6,
252
+ name: 'Staked USDe',
253
+ symbol: 'sUSDe',
254
+ },
255
+ ],
256
+ })
257
+ const client = app({ db: unpricedDb, fx: { oracle: fixed } })
258
+
259
+ const response = await client.v1.addresses[':address'].valuation.$get(
260
+ { param: { address: holder }, query: {} },
261
+ TestApp.auth,
262
+ )
263
+ const body = await TestApp.json(response, Valuation.schema.getAddressValuation.Response)
264
+
265
+ expect(response.status).toBe(200)
266
+ // The unpriced holding is excluded from the total and disclosed.
267
+ expect(body.unpriced).toMatchInlineSnapshot(`
268
+ [
269
+ "sUSDe",
270
+ ]
271
+ `)
272
+ expect(body.pricing?.source).toBe('fixed')
273
+ const { amount } = await Actions.token.getBalance(rpc, {
274
+ account: holder,
275
+ token: TestApp.tokenWithHolders,
276
+ })
277
+ expect(body.amount).toBe(core_Value.format(amount, 6))
278
+ },
279
+ )
280
+
281
+ test.skipIf(runtime.mode !== 'localnet')(
282
+ 'ignores the FX oracle when no conversion is needed',
283
+ async () => {
284
+ // Every verified holding is already USD, so an unreachable oracle must
285
+ // not affect the default valuation.
286
+ await TestApp.verifiedSeed(usdDb, runtime.chainId, { tokens: usdTokens })
287
+ const client = app({
288
+ db: usdDb,
289
+ fx: { oracle: FxOracle.ecb({ url: 'http://127.0.0.1:1' }) },
290
+ })
291
+ const holder = await holderWithBalance(client)
292
+
293
+ const response = await client.v1.addresses[':address'].valuation.$get(
294
+ { param: { address: holder }, query: {} },
295
+ TestApp.auth,
296
+ )
297
+ const body = await TestApp.json(response, Valuation.schema.getAddressValuation.Response)
298
+
299
+ expect(response.status).toBe(200)
300
+ expect(body.pricing).toBeNull()
301
+ },
302
+ )
303
+
304
+ test.skipIf(runtime.mode !== 'localnet')(
305
+ 'surfaces a 502 when rates are unavailable',
306
+ async () => {
307
+ const client = app({ fx: { oracle: FxOracle.ecb({ url: 'http://127.0.0.1:1' }) } })
308
+ const holder = await holderWithBalance(client)
309
+
310
+ const response = await client.v1.addresses[':address'].valuation.$get(
311
+ { param: { address: holder }, query: { denomination: 'AUD' } },
312
+ TestApp.auth,
313
+ )
314
+ const body = await TestApp.json(response, Schema.ErrorResponse)
315
+ const { requestId, error } = body
316
+ const { message, ...stableError } = error
317
+
318
+ // Rate failures report honestly rather than serving a partial total.
319
+ expect(response.status).toMatchInlineSnapshot(`502`)
320
+ expect(typeof requestId).toMatchInlineSnapshot(`"string"`)
321
+ expect(typeof message).toMatchInlineSnapshot(`"string"`)
322
+ expect(stableError).toMatchInlineSnapshot(`
323
+ {
324
+ "code": "upstream_error",
325
+ }
326
+ `)
327
+ },
328
+ )
329
+
330
+ test.skipIf(runtime.mode !== 'localnet')(
331
+ 'rejects denominations the oracle does not price',
332
+ async () => {
333
+ const client = app({ fx: { oracle: fixed } })
334
+ const holder = await holderWithBalance(client)
335
+
336
+ const response = await client.v1.addresses[':address'].valuation.$get(
337
+ { param: { address: holder }, query: { denomination: 'JPY' } },
338
+ TestApp.auth,
339
+ )
340
+ const body = await TestApp.json(response, Schema.ErrorResponse)
341
+ const { requestId, ...stable } = body
342
+
343
+ expect(response.status).toMatchInlineSnapshot(`400`)
344
+ expect(typeof requestId).toMatchInlineSnapshot(`"string"`)
345
+ expect(stable).toMatchInlineSnapshot(`
346
+ {
347
+ "error": {
348
+ "code": "query_invalid",
349
+ "message": "Denomination "JPY" is not priced by the "fixed" FX oracle",
350
+ },
351
+ }
352
+ `)
353
+ },
354
+ )
355
+
356
+ test('rejects unsupported denominations for an address with no holdings', async () => {
357
+ const response = await app({ fx: { oracle: fixed } }).v1.addresses[':address'].valuation.$get(
358
+ { param: { address: emptyAccount() }, query: { denomination: 'JPY' } },
359
+ TestApp.auth,
360
+ )
361
+ const body = await TestApp.json(response, Schema.ErrorResponse)
362
+ const { requestId, ...stable } = body
363
+
364
+ expect(response.status).toMatchInlineSnapshot(`400`)
365
+ expect(typeof requestId).toMatchInlineSnapshot(`"string"`)
366
+ expect(stable).toMatchInlineSnapshot(`
367
+ {
368
+ "error": {
369
+ "code": "query_invalid",
370
+ "message": "Denomination "JPY" is not priced by the "fixed" FX oracle",
371
+ },
372
+ }
373
+ `)
374
+ })
375
+
376
+ test('surfaces a 502 when balance reads are unavailable', async () => {
377
+ const client = app({ rpc: { url: () => 'http://127.0.0.1:1' } })
378
+ const response = await client.v1.addresses[':address'].valuation.$get(
379
+ { param: { address: emptyAccount() }, query: {} },
380
+ TestApp.auth,
381
+ )
382
+ const body = await TestApp.json(response, Schema.ErrorResponse)
383
+ const { requestId, error } = body
384
+ const { message, ...stableError } = error
385
+
386
+ expect(response.status).toMatchInlineSnapshot(`502`)
387
+ expect(typeof requestId).toMatchInlineSnapshot(`"string"`)
388
+ expect(typeof message).toMatchInlineSnapshot(`"string"`)
389
+ expect(stableError).toMatchInlineSnapshot(`
390
+ {
391
+ "code": "upstream_error",
392
+ }
393
+ `)
394
+ })
395
+
396
+ test('rejects invalid account addresses', async () => {
397
+ // The typed client requires `address: `Hex.Hex`` so an invalid literal
398
+ // cannot pass through it; exercise the validator via `app.request`.
399
+ const response = await TestApp.create().request('/v1/addresses/not-an-address/valuation', {
400
+ headers: { authorization: `Bearer ${TestApp.key.token}` },
401
+ })
402
+ const body = await TestApp.json(response, Schema.ErrorResponse)
403
+ const { requestId, ...stable } = body
404
+
405
+ expect(response.status).toMatchInlineSnapshot(`400`)
406
+ expect(typeof requestId).toMatchInlineSnapshot(`"string"`)
407
+ expect(stable).toMatchInlineSnapshot(`
408
+ {
409
+ "error": {
410
+ "code": "address_invalid",
411
+ "details": [
412
+ {
413
+ "message": "Invalid input",
414
+ "path": [
415
+ "address",
416
+ ],
417
+ },
418
+ ],
419
+ "message": "Invalid account address",
420
+ },
421
+ }
422
+ `)
423
+ })
424
+
425
+ test('rejects malformed denominations', async () => {
426
+ const response = await app().v1.addresses[':address'].valuation.$get(
427
+ { param: { address: emptyAccount() }, query: { denomination: 'DOLLARS' } },
428
+ TestApp.auth,
429
+ )
430
+ const body = await TestApp.json(response, Schema.ErrorResponse)
431
+ const { requestId, ...stable } = body
432
+
433
+ expect(response.status).toMatchInlineSnapshot(`400`)
434
+ expect(typeof requestId).toMatchInlineSnapshot(`"string"`)
435
+ expect(stable.error.code).toMatchInlineSnapshot(`"query_invalid"`)
436
+ })
437
+ })