tapimo 0.12.0 → 0.14.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 (398) hide show
  1. package/dist/App.d.ts +11333 -9563
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +39 -3
  4. package/dist/App.js.map +1 -1
  5. package/dist/Scope.d.ts +2 -0
  6. package/dist/Scope.d.ts.map +1 -1
  7. package/dist/Scope.js +17 -0
  8. package/dist/Scope.js.map +1 -1
  9. package/dist/Webhooks.js +2 -2
  10. package/dist/Webhooks.js.map +1 -1
  11. package/dist/admin/App.d.ts +1064 -924
  12. package/dist/admin/App.d.ts.map +1 -1
  13. package/dist/admin/apps/api-keys.d.ts +80 -0
  14. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  15. package/dist/admin/apps/api-keys.js +54 -0
  16. package/dist/admin/apps/api-keys.js.map +1 -1
  17. package/dist/admin/apps/earn-vaults.d.ts +63 -15
  18. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  19. package/dist/admin/apps/earn-vaults.js +2 -1
  20. package/dist/admin/apps/earn-vaults.js.map +1 -1
  21. package/dist/admin/apps/organizations.d.ts +92 -3
  22. package/dist/admin/apps/organizations.d.ts.map +1 -1
  23. package/dist/admin/apps/organizations.js +69 -7
  24. package/dist/admin/apps/organizations.js.map +1 -1
  25. package/dist/admin/apps/verified-tokens.d.ts +7 -7
  26. package/dist/admin/ui.generated.d.ts +1 -1
  27. package/dist/admin/ui.generated.d.ts.map +1 -1
  28. package/dist/admin/ui.generated.js +151 -151
  29. package/dist/admin/ui.generated.js.map +1 -1
  30. package/dist/apps/Zones.d.ts +28 -28
  31. package/dist/apps/Zones.js +7 -7
  32. package/dist/apps/data/App.d.ts +2909 -2523
  33. package/dist/apps/data/App.d.ts.map +1 -1
  34. package/dist/apps/data/App.js +26 -21
  35. package/dist/apps/data/App.js.map +1 -1
  36. package/dist/apps/data/ZoneSelection.d.ts +8 -8
  37. package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
  38. package/dist/apps/data/ZoneSelection.js +1 -1
  39. package/dist/apps/data/ZoneSelection.js.map +1 -1
  40. package/dist/apps/data/routes/activities.d.ts +588 -584
  41. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  42. package/dist/apps/data/routes/activities.js +1561 -1239
  43. package/dist/apps/data/routes/activities.js.map +1 -1
  44. package/dist/apps/data/routes/addresses.d.ts +22 -22
  45. package/dist/apps/data/routes/balances.d.ts +26 -26
  46. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  47. package/dist/apps/data/routes/balances.js +43 -16
  48. package/dist/apps/data/routes/balances.js.map +1 -1
  49. package/dist/apps/data/routes/blocks.d.ts +44 -44
  50. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  51. package/dist/apps/data/routes/blocks.js +21 -11
  52. package/dist/apps/data/routes/blocks.js.map +1 -1
  53. package/dist/apps/data/routes/coingecko.d.ts +3 -3
  54. package/dist/apps/data/routes/earn.d.ts +201 -25
  55. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  56. package/dist/apps/data/routes/earn.js +434 -75
  57. package/dist/apps/data/routes/earn.js.map +1 -1
  58. package/dist/apps/data/routes/exchanges.d.ts +160 -145
  59. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  60. package/dist/apps/data/routes/exchanges.js +180 -114
  61. package/dist/apps/data/routes/exchanges.js.map +1 -1
  62. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  63. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  64. package/dist/apps/data/routes/fee-amm.js +18 -19
  65. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  66. package/dist/apps/data/routes/receipts.d.ts +155 -55
  67. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  68. package/dist/apps/data/routes/receipts.js +28 -10
  69. package/dist/apps/data/routes/receipts.js.map +1 -1
  70. package/dist/apps/data/routes/tokenlist.d.ts +13 -13
  71. package/dist/apps/data/routes/tokens.d.ts +5 -5
  72. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  73. package/dist/apps/data/routes/tokens.js +51 -20
  74. package/dist/apps/data/routes/tokens.js.map +1 -1
  75. package/dist/apps/data/routes/transactions.d.ts +7 -2
  76. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  77. package/dist/apps/data/routes/transactions.js +37 -17
  78. package/dist/apps/data/routes/transactions.js.map +1 -1
  79. package/dist/apps/data/routes/transfers.d.ts +13 -13
  80. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  81. package/dist/apps/data/routes/transfers.js +18 -12
  82. package/dist/apps/data/routes/transfers.js.map +1 -1
  83. package/dist/apps/data/routes/valuation.d.ts +31 -31
  84. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  85. package/dist/apps/data/routes/valuation.js +12 -7
  86. package/dist/apps/data/routes/valuation.js.map +1 -1
  87. package/dist/apps/data/routes/verified-tokens.d.ts +8 -8
  88. package/dist/apps/data/routes/webhooks.d.ts +816 -113
  89. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  90. package/dist/apps/data/routes/webhooks.js +47 -5
  91. package/dist/apps/data/routes/webhooks.js.map +1 -1
  92. package/dist/apps/data/routes/zones.d.ts +14 -14
  93. package/dist/apps/data/routes/zones.js +1 -1
  94. package/dist/apps/funding/App.d.ts +466 -44
  95. package/dist/apps/funding/App.d.ts.map +1 -1
  96. package/dist/apps/funding/App.js +1 -1
  97. package/dist/apps/funding/App.js.map +1 -1
  98. package/dist/apps/funding/routes/deposit-addresses.d.ts +17 -17
  99. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  100. package/dist/apps/funding/routes/deposit-addresses.js +17 -12
  101. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  102. package/dist/apps/funding/routes/transfers.d.ts +650 -57
  103. package/dist/apps/funding/routes/transfers.d.ts.map +1 -1
  104. package/dist/apps/funding/routes/transfers.js +238 -24
  105. package/dist/apps/funding/routes/transfers.js.map +1 -1
  106. package/dist/apps/management/App.d.ts +5120 -4152
  107. package/dist/apps/management/App.d.ts.map +1 -1
  108. package/dist/apps/management/Billing.d.ts +1 -1
  109. package/dist/apps/management/Billing.d.ts.map +1 -1
  110. package/dist/apps/management/Billing.js +17 -1
  111. package/dist/apps/management/Billing.js.map +1 -1
  112. package/dist/apps/management/routes/api-keys.d.ts +632 -81
  113. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  114. package/dist/apps/management/routes/api-keys.js +236 -4
  115. package/dist/apps/management/routes/api-keys.js.map +1 -1
  116. package/dist/apps/management/routes/billing.d.ts +76 -76
  117. package/dist/apps/management/routes/faucet.d.ts +6 -6
  118. package/dist/apps/management/routes/invitations.d.ts +24 -24
  119. package/dist/apps/management/routes/invite-links.d.ts +4 -4
  120. package/dist/apps/management/routes/members.d.ts +16 -16
  121. package/dist/apps/management/routes/orgs.d.ts +20 -20
  122. package/dist/apps/management/routes/projects.d.ts +4 -4
  123. package/dist/apps/management/routes/usage.d.ts +8 -8
  124. package/dist/apps/management/routes/verified-token-requests.d.ts +17 -17
  125. package/dist/apps/management/routes/webhooks.d.ts +675 -25
  126. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  127. package/dist/apps/management/routes/webhooks.js +21 -21
  128. package/dist/apps/management/routes/webhooks.js.map +1 -1
  129. package/dist/apps/relay/App.d.ts.map +1 -1
  130. package/dist/apps/relay/App.js +115 -23
  131. package/dist/apps/relay/App.js.map +1 -1
  132. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  133. package/dist/apps/relay/Sponsorships.js +27 -1
  134. package/dist/apps/relay/Sponsorships.js.map +1 -1
  135. package/dist/db/Db.d.ts.map +1 -1
  136. package/dist/db/Db.js +34 -1
  137. package/dist/db/Db.js.map +1 -1
  138. package/dist/db/Schema.d.ts +11 -5
  139. package/dist/db/Schema.d.ts.map +1 -1
  140. package/dist/db/Schema.js +21 -3
  141. package/dist/db/Schema.js.map +1 -1
  142. package/dist/db/tables/fundingCatalog.d.ts +4 -2
  143. package/dist/db/tables/fundingCatalog.d.ts.map +1 -1
  144. package/dist/db/tables/fundingCatalog.js +5 -1
  145. package/dist/db/tables/fundingCatalog.js.map +1 -1
  146. package/dist/db/tables/fundingTransferTransactions.d.ts +38 -0
  147. package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -1
  148. package/dist/db/tables/fundingTransferTransactions.js +44 -3
  149. package/dist/db/tables/fundingTransferTransactions.js.map +1 -1
  150. package/dist/db/tables/fundingTransfers.d.ts +17 -0
  151. package/dist/db/tables/fundingTransfers.d.ts.map +1 -1
  152. package/dist/db/tables/fundingTransfers.js +21 -0
  153. package/dist/db/tables/fundingTransfers.js.map +1 -1
  154. package/dist/db/tables/organizations.d.ts +24 -0
  155. package/dist/db/tables/organizations.d.ts.map +1 -1
  156. package/dist/db/tables/organizations.js +27 -0
  157. package/dist/db/tables/organizations.js.map +1 -1
  158. package/dist/db/tables/projects.d.ts +25 -1
  159. package/dist/db/tables/projects.d.ts.map +1 -1
  160. package/dist/db/tables/projects.js +26 -0
  161. package/dist/db/tables/projects.js.map +1 -1
  162. package/dist/db/tables/sponsoredTransactions.d.ts +44 -0
  163. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  164. package/dist/db/tables/sponsoredTransactions.js +146 -13
  165. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  166. package/dist/db/tables/webhookSubscriptions.d.ts +10 -6
  167. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  168. package/dist/db/tables/webhookSubscriptions.js +9 -6
  169. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  170. package/dist/handlers/internal/utils.d.ts.map +1 -1
  171. package/dist/handlers/internal/utils.js +9 -0
  172. package/dist/handlers/internal/utils.js.map +1 -1
  173. package/dist/internal/Auth.d.ts +3 -1
  174. package/dist/internal/Auth.d.ts.map +1 -1
  175. package/dist/internal/Auth.js +6 -3
  176. package/dist/internal/Auth.js.map +1 -1
  177. package/dist/internal/EarnVaults.d.ts +3 -3
  178. package/dist/internal/EarnVaults.js +5 -5
  179. package/dist/internal/EarnVaults.js.map +1 -1
  180. package/dist/internal/Fetch.d.ts +23 -0
  181. package/dist/internal/Fetch.d.ts.map +1 -0
  182. package/dist/internal/Fetch.js +26 -0
  183. package/dist/internal/Fetch.js.map +1 -0
  184. package/dist/internal/Log.d.ts +4 -2
  185. package/dist/internal/Log.d.ts.map +1 -1
  186. package/dist/internal/Log.js +16 -3
  187. package/dist/internal/Log.js.map +1 -1
  188. package/dist/internal/OpenApi.d.ts +5 -3
  189. package/dist/internal/OpenApi.d.ts.map +1 -1
  190. package/dist/internal/OpenApi.js +13 -3
  191. package/dist/internal/OpenApi.js.map +1 -1
  192. package/dist/internal/Response.d.ts +1 -1
  193. package/dist/internal/Response.d.ts.map +1 -1
  194. package/dist/internal/Schema.d.ts +6 -3
  195. package/dist/internal/Schema.d.ts.map +1 -1
  196. package/dist/internal/Schema.js +8 -2
  197. package/dist/internal/Schema.js.map +1 -1
  198. package/dist/internal/Store.d.ts +16 -3
  199. package/dist/internal/Store.d.ts.map +1 -1
  200. package/dist/internal/Store.js +82 -16
  201. package/dist/internal/Store.js.map +1 -1
  202. package/dist/internal/Tidx.d.ts.map +1 -1
  203. package/dist/internal/Tidx.js +7 -2
  204. package/dist/internal/Tidx.js.map +1 -1
  205. package/dist/internal/Timeout.d.ts +36 -0
  206. package/dist/internal/Timeout.d.ts.map +1 -0
  207. package/dist/internal/Timeout.js +37 -0
  208. package/dist/internal/Timeout.js.map +1 -0
  209. package/dist/internal/Timing.d.ts +9 -0
  210. package/dist/internal/Timing.d.ts.map +1 -1
  211. package/dist/internal/Timing.js +7 -0
  212. package/dist/internal/Timing.js.map +1 -1
  213. package/dist/internal/Viem.d.ts +16 -1
  214. package/dist/internal/Viem.d.ts.map +1 -1
  215. package/dist/internal/Viem.js +12 -2
  216. package/dist/internal/Viem.js.map +1 -1
  217. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  218. package/dist/internal/WebhookDestination.js +3 -0
  219. package/dist/internal/WebhookDestination.js.map +1 -1
  220. package/dist/internal/funding/Action.d.ts +9 -0
  221. package/dist/internal/funding/Action.d.ts.map +1 -1
  222. package/dist/internal/funding/Action.js +16 -8
  223. package/dist/internal/funding/Action.js.map +1 -1
  224. package/dist/internal/funding/Catalog.d.ts +9 -2
  225. package/dist/internal/funding/Catalog.d.ts.map +1 -1
  226. package/dist/internal/funding/Catalog.js +19 -8
  227. package/dist/internal/funding/Catalog.js.map +1 -1
  228. package/dist/internal/funding/DepositWebhook.d.ts.map +1 -1
  229. package/dist/internal/funding/DepositWebhook.js +2 -1
  230. package/dist/internal/funding/DepositWebhook.js.map +1 -1
  231. package/dist/internal/funding/Evidence.d.ts.map +1 -1
  232. package/dist/internal/funding/Evidence.js +2 -10
  233. package/dist/internal/funding/Evidence.js.map +1 -1
  234. package/dist/internal/funding/Provider.d.ts +108 -13
  235. package/dist/internal/funding/Provider.d.ts.map +1 -1
  236. package/dist/internal/funding/Provider.js +34 -8
  237. package/dist/internal/funding/Provider.js.map +1 -1
  238. package/dist/internal/funding/SourceObservation.d.ts.map +1 -1
  239. package/dist/internal/funding/SourceObservation.js +5 -7
  240. package/dist/internal/funding/SourceObservation.js.map +1 -1
  241. package/dist/internal/funding/Transfer.d.ts +114 -18
  242. package/dist/internal/funding/Transfer.d.ts.map +1 -1
  243. package/dist/internal/funding/Transfer.js +185 -55
  244. package/dist/internal/funding/Transfer.js.map +1 -1
  245. package/dist/internal/funding/TransferReconciliation.d.ts +52 -0
  246. package/dist/internal/funding/TransferReconciliation.d.ts.map +1 -0
  247. package/dist/internal/funding/TransferReconciliation.js +192 -0
  248. package/dist/internal/funding/TransferReconciliation.js.map +1 -0
  249. package/dist/internal/funding/TransferWebhook.d.ts +21 -0
  250. package/dist/internal/funding/TransferWebhook.d.ts.map +1 -0
  251. package/dist/internal/funding/TransferWebhook.js +43 -0
  252. package/dist/internal/funding/TransferWebhook.js.map +1 -0
  253. package/dist/internal/funding/index.d.ts +1 -0
  254. package/dist/internal/funding/index.d.ts.map +1 -1
  255. package/dist/internal/funding/index.js +1 -0
  256. package/dist/internal/funding/index.js.map +1 -1
  257. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  258. package/dist/internal/funding/providers/relay.js +3 -12
  259. package/dist/internal/funding/providers/relay.js.map +1 -1
  260. package/dist/internal/funding/providers/stargate.d.ts +127 -9
  261. package/dist/internal/funding/providers/stargate.d.ts.map +1 -1
  262. package/dist/internal/funding/providers/stargate.js +548 -112
  263. package/dist/internal/funding/providers/stargate.js.map +1 -1
  264. package/dist/internal/index.d.ts +1 -0
  265. package/dist/internal/index.d.ts.map +1 -1
  266. package/dist/internal/index.js +1 -0
  267. package/dist/internal/index.js.map +1 -1
  268. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
  269. package/dist/internal/webhookDestinations/slack.js +16 -0
  270. package/dist/internal/webhookDestinations/slack.js.map +1 -1
  271. package/package.json +2 -2
  272. package/src/App.test.ts +100 -0
  273. package/src/App.ts +43 -3
  274. package/src/Client.test-d.ts +129 -2
  275. package/src/Scope.test.ts +20 -0
  276. package/src/Scope.ts +16 -0
  277. package/src/Webhooks.ts +2 -2
  278. package/src/admin/apps/api-keys.test.ts +75 -0
  279. package/src/admin/apps/api-keys.ts +64 -0
  280. package/src/admin/apps/earn-vaults.test.ts +1 -1
  281. package/src/admin/apps/earn-vaults.ts +2 -1
  282. package/src/admin/apps/organizations.test.ts +53 -1
  283. package/src/admin/apps/organizations.ts +90 -5
  284. package/src/admin/ui/src/lib/api-keys.ts +19 -0
  285. package/src/admin/ui/src/lib/organizations.test.ts +112 -1
  286. package/src/admin/ui/src/lib/organizations.ts +55 -0
  287. package/src/admin/ui/src/routes/api-keys.tsx +89 -2
  288. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +116 -0
  289. package/src/admin/ui.generated.ts +189 -151
  290. package/src/apps/Zones.test.ts +7 -7
  291. package/src/apps/Zones.ts +7 -7
  292. package/src/apps/composition.test.ts +2 -1
  293. package/src/apps/data/App.test.ts +41 -0
  294. package/src/apps/data/App.ts +30 -21
  295. package/src/apps/data/ZoneSelection.test.ts +2 -2
  296. package/src/apps/data/ZoneSelection.ts +8 -8
  297. package/src/apps/data/routes/activities.test.ts +1526 -12
  298. package/src/apps/data/routes/activities.ts +1774 -1356
  299. package/src/apps/data/routes/balances.ts +133 -97
  300. package/src/apps/data/routes/blocks.test.ts +533 -0
  301. package/src/apps/data/routes/blocks.ts +35 -16
  302. package/src/apps/data/routes/earn.test.ts +373 -16
  303. package/src/apps/data/routes/earn.ts +548 -79
  304. package/src/apps/data/routes/earn.zone-access.test.ts +6 -6
  305. package/src/apps/data/routes/exchanges.test.ts +740 -15
  306. package/src/apps/data/routes/exchanges.ts +954 -753
  307. package/src/apps/data/routes/fee-amm.ts +17 -18
  308. package/src/apps/data/routes/receipts.ts +47 -16
  309. package/src/apps/data/routes/tokens.test.ts +578 -0
  310. package/src/apps/data/routes/tokens.ts +283 -225
  311. package/src/apps/data/routes/transactions.ts +68 -29
  312. package/src/apps/data/routes/transfers.test.ts +421 -0
  313. package/src/apps/data/routes/transfers.ts +45 -27
  314. package/src/apps/data/routes/valuation.ts +94 -78
  315. package/src/apps/data/routes/webhooks.test.ts +21 -5
  316. package/src/apps/data/routes/webhooks.ts +63 -8
  317. package/src/apps/data/routes/zones.test.ts +2 -2
  318. package/src/apps/data/routes/zones.ts +1 -1
  319. package/src/apps/funding/App.ts +12 -2
  320. package/src/apps/funding/routes/deposit-addresses.test.ts +29 -7
  321. package/src/apps/funding/routes/deposit-addresses.ts +19 -14
  322. package/src/apps/funding/routes/quotes.test.ts +5 -9
  323. package/src/apps/funding/routes/transfers.test.ts +901 -23
  324. package/src/apps/funding/routes/transfers.ts +347 -64
  325. package/src/apps/management/Billing.ts +18 -5
  326. package/src/apps/management/routes/api-keys.test.ts +220 -0
  327. package/src/apps/management/routes/api-keys.ts +280 -3
  328. package/src/apps/management/routes/webhooks.test.ts +3 -3
  329. package/src/apps/management/routes/webhooks.ts +24 -25
  330. package/src/apps/relay/App.test.ts +212 -1
  331. package/src/apps/relay/App.ts +158 -29
  332. package/src/apps/relay/Sponsorships.ts +24 -1
  333. package/src/db/Db.ts +48 -1
  334. package/src/db/Schema.ts +22 -4
  335. package/src/db/tables/earnVaults.test.ts +9 -9
  336. package/src/db/tables/fundingCatalog.test.ts +16 -2
  337. package/src/db/tables/fundingCatalog.ts +9 -3
  338. package/src/db/tables/fundingTransferTransactions.test.ts +43 -0
  339. package/src/db/tables/fundingTransferTransactions.ts +79 -3
  340. package/src/db/tables/fundingTransfers.test.ts +26 -0
  341. package/src/db/tables/fundingTransfers.ts +36 -0
  342. package/src/db/tables/organizations.test.ts +41 -0
  343. package/src/db/tables/organizations.ts +49 -0
  344. package/src/db/tables/projects.test.ts +55 -0
  345. package/src/db/tables/projects.ts +46 -1
  346. package/src/db/tables/sponsoredTransactions.test.ts +338 -0
  347. package/src/db/tables/sponsoredTransactions.ts +197 -13
  348. package/src/db/tables/webhookSubscriptions.ts +18 -11
  349. package/src/handlers/internal/utils.test.ts +53 -0
  350. package/src/handlers/internal/utils.ts +15 -0
  351. package/src/internal/Auth.ts +12 -4
  352. package/src/internal/EarnVaults.capabilities.test.ts +2 -2
  353. package/src/internal/EarnVaults.test.ts +1 -1
  354. package/src/internal/EarnVaults.ts +5 -5
  355. package/src/internal/Fetch.test.ts +46 -0
  356. package/src/internal/Fetch.ts +56 -0
  357. package/src/internal/Log.test-d.ts +2 -0
  358. package/src/internal/Log.test.ts +21 -0
  359. package/src/internal/Log.ts +22 -5
  360. package/src/internal/OpenApi.ts +14 -4
  361. package/src/internal/Response.ts +1 -1
  362. package/src/internal/Schema.test.ts +2 -0
  363. package/src/internal/Schema.ts +12 -2
  364. package/src/internal/Store.test.ts +178 -0
  365. package/src/internal/Store.ts +104 -18
  366. package/src/internal/Tidx.test.ts +2 -1
  367. package/src/internal/Tidx.ts +7 -2
  368. package/src/internal/Timeout.test.ts +35 -0
  369. package/src/internal/Timeout.ts +73 -0
  370. package/src/internal/Timing.ts +16 -0
  371. package/src/internal/Viem.ts +39 -3
  372. package/src/internal/WebhookDestination.ts +3 -0
  373. package/src/internal/Webhooks.test.ts +45 -0
  374. package/src/internal/funding/Action.test.ts +41 -1
  375. package/src/internal/funding/Action.ts +69 -41
  376. package/src/internal/funding/Catalog.test.ts +34 -0
  377. package/src/internal/funding/Catalog.ts +28 -11
  378. package/src/internal/funding/DepositWebhook.ts +2 -1
  379. package/src/internal/funding/Evidence.ts +2 -13
  380. package/src/internal/funding/Provider.test.ts +73 -0
  381. package/src/internal/funding/Provider.ts +125 -28
  382. package/src/internal/funding/SourceObservation.ts +5 -9
  383. package/src/internal/funding/Transfer.test.ts +155 -0
  384. package/src/internal/funding/Transfer.ts +387 -147
  385. package/src/internal/funding/TransferReconciliation.test.ts +147 -0
  386. package/src/internal/funding/TransferReconciliation.ts +264 -0
  387. package/src/internal/funding/TransferWebhook.test.ts +128 -0
  388. package/src/internal/funding/TransferWebhook.ts +67 -0
  389. package/src/internal/funding/index.test.ts +1 -0
  390. package/src/internal/funding/index.ts +1 -0
  391. package/src/internal/funding/providers/index.test.ts +4 -167
  392. package/src/internal/funding/providers/relay.test.ts +2 -2
  393. package/src/internal/funding/providers/relay.ts +3 -15
  394. package/src/internal/funding/providers/stargate.test.ts +328 -0
  395. package/src/internal/funding/providers/stargate.ts +807 -135
  396. package/src/internal/index.test.ts +1 -0
  397. package/src/internal/index.ts +1 -0
  398. package/src/internal/webhookDestinations/slack.ts +15 -0
@@ -1,5 +1,7 @@
1
1
  import { Webhooks } from 'tapimo'
2
+ import { sql } from 'kysely'
2
3
  import * as TestApp from '../../test/App.js'
4
+ import * as WebhookSubscriptions from '../db/tables/webhookSubscriptions.js'
3
5
  import * as Metrics from '../Metrics.js'
4
6
  import * as Cursor from './Cursor.js'
5
7
 
@@ -170,6 +172,49 @@ describe('createSubscription', () => {
170
172
  })
171
173
  })
172
174
 
175
+ describe('listActiveForFundingEvent', () => {
176
+ test('keeps selected subscriptions until the caller transaction commits', async () => {
177
+ const getDb = TestApp.databaseFactory()
178
+ const owner = { orgId: 'org_funding_subscription_lock', type: 'api_key' } as const
179
+ const subscription = await Webhooks.createSubscription(
180
+ getDb(),
181
+ createInput({
182
+ environment: 'production',
183
+ eventType: 'funding:transfer.updated',
184
+ owner,
185
+ }),
186
+ )
187
+ const locked = Promise.withResolvers<void>()
188
+ const release = Promise.withResolvers<void>()
189
+ const read = getDb().transaction(async (tx) => {
190
+ const subscriptions = await WebhookSubscriptions.listActiveForFundingEvent(tx, {
191
+ chainId: 4217,
192
+ environment: 'production',
193
+ eventType: 'funding:transfer.updated',
194
+ now: new Date().toISOString(),
195
+ orgId: owner.orgId,
196
+ })
197
+ locked.resolve()
198
+ await release.promise
199
+ return subscriptions
200
+ })
201
+ await locked.promise
202
+
203
+ const deletion = await getDb()
204
+ .transaction(async (tx) => {
205
+ await sql`select set_config('lock_timeout', '100ms', true)`.execute(tx.kysely)
206
+ return Webhooks.deleteSubscription(tx, owner, subscription.id)
207
+ })
208
+ .catch((cause: unknown) => cause)
209
+ release.resolve()
210
+
211
+ await expect(read).resolves.toEqual([subscription])
212
+ expect(deletion).toBeInstanceOf(Error)
213
+ expect(String(deletion)).toContain('lock timeout')
214
+ await expect(Webhooks.deleteSubscription(getDb(), owner, subscription.id)).resolves.toBe(true)
215
+ })
216
+ })
217
+
173
218
  describe('owner isolation', () => {
174
219
  test('an owner cannot read or list another owner subscriptions', async () => {
175
220
  const db = TestApp.database()
@@ -132,7 +132,47 @@ describe('validateEvmCalls', () => {
132
132
  sourceTokenAddress: sourceToken,
133
133
  }),
134
134
  ).toThrowErrorMatchingInlineSnapshot(
135
- `[Funding.Action.InvalidActionError: Stablecoin funding calls must not carry native value.]`,
135
+ `[Funding.Action.InvalidActionError: Native value must match a validated provider fee.]`,
136
136
  )
137
137
  })
138
+
139
+ test('accepts an exact provider-validated native value', () => {
140
+ Action.validateEvmCalls({
141
+ action: {
142
+ calls: [approveCall(1_000_000n), { ...depositCall, value: '0x10' }],
143
+ type: 'evm:calls',
144
+ },
145
+ nativeValues: [{ to: spender, value: '0x10' }],
146
+ sourceAmount: '1000000',
147
+ sourceTokenAddress: sourceToken,
148
+ })
149
+ })
150
+
151
+ test('rejects malformed native value allowances', () => {
152
+ expect(() =>
153
+ Action.validateEvmCalls({
154
+ action: { calls: [approveCall(1_000_000n), depositCall], type: 'evm:calls' },
155
+ nativeValues: [{ to: spender, value: '10' }],
156
+ sourceAmount: '1000000',
157
+ sourceTokenAddress: sourceToken,
158
+ }),
159
+ ).toThrowErrorMatchingInlineSnapshot(
160
+ `[Funding.Action.InvalidActionError: Malformed native value allowance.]`,
161
+ )
162
+ })
163
+
164
+ test('rejects native values outside the exact provider allowance', () => {
165
+ for (const call of [
166
+ { ...depositCall, to: `0x${'99'.repeat(20)}`, value: '0x10' },
167
+ { ...depositCall, value: '0x11' },
168
+ ])
169
+ expect(() =>
170
+ Action.validateEvmCalls({
171
+ action: { calls: [approveCall(1_000_000n), call], type: 'evm:calls' },
172
+ nativeValues: [{ to: spender, value: '0x10' }],
173
+ sourceAmount: '1000000',
174
+ sourceTokenAddress: sourceToken,
175
+ }),
176
+ ).toThrow(Action.InvalidActionError)
177
+ })
138
178
  })
@@ -1,6 +1,8 @@
1
1
  import { AbiFunction, Address, type Hex, Solidity } from 'ox'
2
2
  import * as z from 'zod/mini'
3
3
 
4
+ import * as OpenApi from '../OpenApi.js'
5
+
4
6
  /**
5
7
  * Executable source-chain actions returned by funding transfer creation. A
6
8
  * strict discriminated union: transfer reads never include an action.
@@ -12,49 +14,58 @@ const approveSelector = AbiFunction.getSelector(approve)
12
14
  /** Zod schemas owned by funding actions. */
13
15
  export namespace schema {
14
16
  /** One unsigned EVM call, in the exchange quote API's call shape. */
15
- export const Call = z
16
- .object({
17
- data: z
18
- .string()
19
- .check(
20
- z.regex(/^0x(?:[0-9a-fA-F]{2})*$/),
21
- z.describe('ABI-encoded calldata.'),
22
- z.meta({ examples: ['0x095ea7b3'] }),
23
- ),
24
- to: z
25
- .string()
26
- .check(
27
- z.regex(/^0x[0-9a-fA-F]{40}$/),
28
- z.describe('Contract the call targets.'),
29
- z.meta({ examples: [`0x${'44'.repeat(20)}`] }),
30
- ),
31
- value: z
32
- .string()
33
- .check(
34
- z.regex(/^0x[0-9a-fA-F]+$/),
35
- z.describe('Native value to send, as hex.'),
36
- z.meta({ examples: ['0x0'] }),
37
- ),
38
- })
39
- .check(z.describe('One unsigned EVM call.'))
17
+ export const Call = OpenApi.component(
18
+ z
19
+ .object({
20
+ data: z
21
+ .string()
22
+ .check(
23
+ z.regex(/^0x(?:[0-9a-fA-F]{2})*$/),
24
+ z.describe('ABI-encoded calldata.'),
25
+ z.meta({ examples: ['0x095ea7b3'] }),
26
+ ),
27
+ to: z
28
+ .string()
29
+ .check(
30
+ z.regex(/^0x[0-9a-fA-F]{40}$/),
31
+ z.describe('Contract the call targets.'),
32
+ z.meta({ examples: [`0x${'44'.repeat(20)}`] }),
33
+ ),
34
+ value: z
35
+ .string()
36
+ .check(
37
+ z.regex(/^0x[0-9a-fA-F]+$/),
38
+ z.describe('Native value to send, as hex.'),
39
+ z.meta({ examples: ['0x0'] }),
40
+ ),
41
+ })
42
+ .check(z.describe('One unsigned EVM call.')),
43
+ 'FundingActionCall',
44
+ )
40
45
 
41
46
  /** Ordered unsigned EVM calls the caller signs and submits on the source chain. */
42
- export const EvmCalls = z
43
- .object({
44
- calls: z
45
- .array(Call)
46
- .check(
47
- z.minLength(1),
48
- z.describe('Calls in submission order; they may require separate transactions.'),
49
- ),
50
- type: z.literal('evm:calls').check(z.describe('Action kind.')),
51
- })
52
- .check(z.describe('Ordered unsigned EVM calls to sign and submit on the source chain.'))
47
+ export const EvmCalls = OpenApi.component(
48
+ z
49
+ .object({
50
+ calls: z
51
+ .array(Call)
52
+ .check(
53
+ z.minLength(1),
54
+ z.describe('Calls in submission order; they may require separate transactions.'),
55
+ ),
56
+ type: z.literal('evm:calls').check(z.describe('Action kind.')),
57
+ })
58
+ .check(z.describe('Ordered unsigned EVM calls to sign and submit on the source chain.')),
59
+ 'FundingEvmCallsAction',
60
+ )
53
61
 
54
62
  /** Executable source-chain action attached to a creation response. */
55
- export const Action = z
56
- .discriminatedUnion('type', [EvmCalls])
57
- .check(z.describe('Executable source-chain action. Never returned by transfer reads.'))
63
+ export const Action = OpenApi.component(
64
+ z
65
+ .discriminatedUnion('type', [EvmCalls])
66
+ .check(z.describe('Executable source-chain action. Never returned by transfer reads.')),
67
+ 'FundingAction',
68
+ )
58
69
  }
59
70
 
60
71
  /** One unsigned EVM call (see {@link schema.Call}). */
@@ -66,6 +77,14 @@ export type EvmCalls = z.output<typeof schema.EvmCalls>
66
77
  /** Executable source-chain action (see {@link schema.Action}). */
67
78
  export type Action = z.output<typeof schema.Action>
68
79
 
80
+ /** One exact native-value allowance established by provider-specific validation. */
81
+ export type NativeValue = {
82
+ /** Contract that may receive the native value. */
83
+ to: string
84
+ /** Exact native value allowed, as a JSON-RPC quantity. */
85
+ value: string
86
+ }
87
+
69
88
  /**
70
89
  * Validates prepared EVM calls before persistence. Token calls, approval
71
90
  * targets, spenders, amounts, selectors, and native value must match the route.
@@ -73,9 +92,16 @@ export type Action = z.output<typeof schema.Action>
73
92
  export function validateEvmCalls(options: validateEvmCalls.Options): void {
74
93
  const action = schema.EvmCalls.safeParse(options.action)
75
94
  if (!action.success) throw new InvalidActionError('Malformed EVM calls.')
95
+ const nativeValues = new Set<string>()
96
+ for (const { to, value } of options.nativeValues ?? []) {
97
+ if (!Address.validate(to, { strict: false }) || !/^0x[0-9a-fA-F]+$/.test(value))
98
+ throw new InvalidActionError('Malformed native value allowance.')
99
+ nativeValues.add(`${to.toLowerCase()}:${BigInt(value).toString()}`)
100
+ }
76
101
  for (const [index, call] of action.data.calls.entries()) {
77
- if (BigInt(call.value) !== 0n)
78
- throw new InvalidActionError('Stablecoin funding calls must not carry native value.')
102
+ const callValue = BigInt(call.value)
103
+ if (callValue > 0n && !nativeValues.has(`${call.to.toLowerCase()}:${callValue.toString()}`))
104
+ throw new InvalidActionError('Native value must match a validated provider fee.')
79
105
  const targetsSourceToken = Address.isEqual(
80
106
  call.to as Address.Address,
81
107
  options.sourceTokenAddress as Address.Address,
@@ -104,6 +130,8 @@ export declare namespace validateEvmCalls {
104
130
  type Options = {
105
131
  /** The prepared action to validate. */
106
132
  action: EvmCalls
133
+ /** Exact native values established by provider-specific validation. */
134
+ nativeValues?: readonly NativeValue[] | undefined
107
135
  /** Source amount in base units. */
108
136
  sourceAmount: string
109
137
  /** Source token contract address. */
@@ -309,3 +309,37 @@ describe('route capabilities', () => {
309
309
  ).toThrow()
310
310
  })
311
311
  })
312
+
313
+ describe('route configuration', () => {
314
+ const configuration = { poolAddress: `0x${'11'.repeat(20)}` }
315
+
316
+ test('carries configuration into hydrated provider routes', () => {
317
+ const snapshot = Catalog.compile(rows({ routes: [{ ...data.routes[0]!, configuration }] }))
318
+ expect(snapshot.routes[0]?.configuration).toStrictEqual(configuration)
319
+ expect(snapshot.routesByProvider.get('relay')?.[0]?.configuration).toStrictEqual(configuration)
320
+ })
321
+
322
+ test('omits configuration when it is absent or null', () => {
323
+ const absent = Catalog.compile(rows())
324
+ const nulled = Catalog.compile(rows({ routes: [{ ...data.routes[0]!, configuration: null }] }))
325
+ expect('configuration' in absent.routes[0]!).toBe(false)
326
+ expect('configuration' in nulled.routes[0]!).toBe(false)
327
+ })
328
+
329
+ test('publishes configuration through the write boundary', async () => {
330
+ const db = TestApp.database()
331
+ const snapshot = await Catalog.publish(db, {
332
+ ...data,
333
+ routes: [{ ...data.routes[0]!, configuration }],
334
+ })
335
+ expect(snapshot.routes[0]?.configuration).toStrictEqual(configuration)
336
+ })
337
+
338
+ test('rejects non-object configuration', () => {
339
+ expect(() =>
340
+ Catalog.compile(
341
+ rows({ routes: [{ ...data.routes[0]!, configuration: 'invalid' as never }] }),
342
+ ),
343
+ ).toThrow()
344
+ })
345
+ })
@@ -55,10 +55,16 @@ export namespace schema {
55
55
  z.describe('Funding capabilities enabled on one provider route.'),
56
56
  )
57
57
 
58
- // Absent or null `capabilities` keeps a route quote-only, so transfer and
59
- // deposit-address support enable through reviewed seed edits.
58
+ /** Provider-specific configuration for one funding route. */
59
+ export const Configuration = z
60
+ .record(z.string(), z.unknown())
61
+ .check(z.describe('Provider-specific configuration for one funding route.'))
62
+
63
+ // Absent or null `capabilities` keeps a route quote-only. Absent or null
64
+ // `configuration` lets providers decide whether a route is configured.
60
65
  const Route = z.extend(db_Schema.FundingRoute, {
61
66
  capabilities: z.optional(z.nullable(Capabilities)),
67
+ configuration: z.optional(z.nullable(Configuration)),
62
68
  })
63
69
 
64
70
  /** Complete funding catalog content accepted by the publish boundary. */
@@ -77,10 +83,15 @@ export namespace schema {
77
83
  /** Funding capabilities enabled on one provider route. */
78
84
  export type Capabilities = z.output<typeof schema.Capabilities>
79
85
 
86
+ /** Provider-specific configuration for one funding route. */
87
+ export type Configuration = z.output<typeof schema.Configuration>
88
+
80
89
  /** One hydrated provider route in a funding catalog snapshot. */
81
90
  export type ProviderRoute = {
82
91
  /** Funding capabilities; absent means the route is quote-only. */
83
92
  capabilities?: Capabilities | undefined
93
+ /** Provider-specific route configuration. */
94
+ configuration?: Configuration | undefined
84
95
  /** Funding provider that supports the route. */
85
96
  providerId: string
86
97
  /** Hydrated source-to-destination funding route. */
@@ -93,8 +104,8 @@ export type Snapshot = {
93
104
  chainsByKey: ReadonlyMap<string, Chain.Chain>
94
105
  /** Hydrated provider routes in stable catalog order. */
95
106
  routes: readonly ProviderRoute[]
96
- /** Hydrated routes grouped by provider id. */
97
- routesByProvider: ReadonlyMap<string, readonly Route.Route[]>
107
+ /** Hydrated provider routes grouped by provider id. */
108
+ routesByProvider: ReadonlyMap<string, readonly ProviderRoute[]>
98
109
  /** Canonical funding tokens indexed by stable id. */
99
110
  tokensById: ReadonlyMap<string, Token.Token>
100
111
  /** ISO timestamp of the catalog's last publish. */
@@ -176,7 +187,7 @@ export function compile(rows: core_Catalog.Rows): Snapshot {
176
187
  }
177
188
 
178
189
  const routes: ProviderRoute[] = []
179
- const routesByProvider = new Map<string, Route.Route[]>()
190
+ const routesByProvider = new Map<string, ProviderRoute[]>()
180
191
  for (const row of data.routes) {
181
192
  const route = {
182
193
  destination: resolvePlacement(
@@ -187,14 +198,16 @@ export function compile(rows: core_Catalog.Rows): Snapshot {
187
198
  ),
188
199
  source: resolvePlacement(chainsById, tokensById, row.sourceChainId, row.sourceTokenId),
189
200
  }
190
- routes.push({
201
+ const entry = {
191
202
  ...(row.capabilities ? { capabilities: row.capabilities } : {}),
203
+ ...(row.configuration ? { configuration: row.configuration } : {}),
192
204
  providerId: row.providerId,
193
205
  route,
194
- })
206
+ }
207
+ routes.push(entry)
195
208
  const providerRoutes = routesByProvider.get(row.providerId)
196
- if (providerRoutes) providerRoutes.push(route)
197
- else routesByProvider.set(row.providerId, [route])
209
+ if (providerRoutes) providerRoutes.push(entry)
210
+ else routesByProvider.set(row.providerId, [entry])
198
211
  }
199
212
 
200
213
  return {
@@ -219,10 +232,14 @@ export async function publish(db: Db.Db, input: publish.Input): Promise<Snapshot
219
232
  catalog: { id: 'default', updatedAt: emptyUpdatedAt, version: 'validation' },
220
233
  ...data,
221
234
  })
222
- // Absent `capabilities` persists as null; both mean indicative-only.
235
+ // Optional route data persists as null so every stored row has one shape.
223
236
  await core_Catalog.publish(db, {
224
237
  ...data,
225
- routes: data.routes.map((route) => ({ ...route, capabilities: route.capabilities ?? null })),
238
+ routes: data.routes.map((route) => ({
239
+ ...route,
240
+ capabilities: route.capabilities ?? null,
241
+ configuration: route.configuration ?? null,
242
+ })),
226
243
  })
227
244
  return prime(db, await read(db))
228
245
  }
@@ -37,9 +37,10 @@ export async function stage(
37
37
  for (const record of unique(options.records)) {
38
38
  const chainId = destinationChainId(record)
39
39
  if (chainId === undefined) continue
40
- const subscriptions = await WebhookSubscriptions.listActiveForFundingDeposit(db, {
40
+ const subscriptions = await WebhookSubscriptions.listActiveForFundingEvent(db, {
41
41
  chainId,
42
42
  environment: record.environment,
43
+ eventType: 'funding:deposit.updated',
43
44
  now,
44
45
  orgId: record.orgId,
45
46
  ...(record.projectId === null ? {} : { projectId: record.projectId }),
@@ -1,5 +1,5 @@
1
1
  import { AbiEvent, Address, Base58, Bytes, Hash, Hex, RpcSchema, RpcTransport } from 'ox'
2
- import { createClient, custom, fallback, TransactionReceiptNotFoundError } from 'viem'
2
+ import { TransactionReceiptNotFoundError } from 'viem'
3
3
  import { getBlockNumber, getTransactionReceipt } from 'viem/actions'
4
4
  import * as z from 'zod/mini'
5
5
 
@@ -195,7 +195,7 @@ async function verifyEvm(
195
195
  parameters: Reconciliation.VerifyTransfers.Parameters,
196
196
  options: FetchOptions & { confirmations: number },
197
197
  ): Promise<readonly Reconciliation.TransferEvidence[]> {
198
- const client = jsonRpcClient(options)
198
+ const client = Viem.createEvmClient(options)
199
199
  const [receipt, head] = await Promise.all([
200
200
  getTransactionReceipt(client, { hash: parameters.transactionHash as Hex.Hex }).catch(
201
201
  (cause) => {
@@ -334,17 +334,6 @@ async function verifyTron(
334
334
  })
335
335
  }
336
336
 
337
- function jsonRpcClient(options: FetchOptions) {
338
- return createClient({
339
- transport: fallback(
340
- options.urls.map((url) => {
341
- const transport = RpcTransport.fromHttp(url, { fetchFn: options.fetch })
342
- return custom(transport, { retryCount: 0 })
343
- }),
344
- ),
345
- })
346
- }
347
-
348
337
  async function requestSolana(
349
338
  options: FetchOptions,
350
339
  request: SolanaRpcSchema['Request'],
@@ -5,6 +5,7 @@ import * as Across from './providers/across.js'
5
5
  import * as Relay from './providers/relay.js'
6
6
  import * as Rhino from './providers/rhino.js'
7
7
  import * as Squid from './providers/squid.js'
8
+ import * as Stargate from './providers/stargate.js'
8
9
  import * as Symbiosis from './providers/symbiosis.js'
9
10
 
10
11
  const providers = [
@@ -19,6 +20,7 @@ const providers = [
19
20
  integratorId: 'squid-integrator-id',
20
21
  userAddress: '0x1111111111111111111111111111111111111111',
21
22
  }),
23
+ Stargate.stargate(),
22
24
  Symbiosis.symbiosis({ userAddress: '0x1111111111111111111111111111111111111111' }),
23
25
  ] as const
24
26
 
@@ -831,9 +833,63 @@ describe('prepareTransfer', () => {
831
833
  { operation: 'prepareTransfer', outcome: 'unavailable', provider: 'relay' },
832
834
  ])
833
835
  })
836
+
837
+ test('accepts preparations without correlation', async () => {
838
+ const { correlation: _correlation, ...result } = preparedResult()
839
+ const spender = `0x${'44'.repeat(20)}`
840
+ const selected = FundingProvider.prepareTransfer({
841
+ ...prepareOptions,
842
+ providers: [
843
+ withPrepareTransfer('relay', async () => {
844
+ return {
845
+ ...result,
846
+ action: {
847
+ calls: [
848
+ {
849
+ data: `0x095ea7b3${spender.slice(2).padStart(64, '0')}${(1_000_000).toString(16).padStart(64, '0')}`,
850
+ to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
851
+ value: '0x0',
852
+ },
853
+ { data: '0xe8017952', to: spender, value: '0x0' },
854
+ ],
855
+ type: 'evm:calls',
856
+ },
857
+ }
858
+ }),
859
+ ],
860
+ })
861
+
862
+ expect((await selected)?.result.correlation).toBeUndefined()
863
+ })
834
864
  })
835
865
 
836
866
  describe('getPrepareCandidates', () => {
867
+ test('restricts candidates to the requested provider', () => {
868
+ const relay = withPrepareTransfer('relay', async () => preparedResult())
869
+ const stargate = withPrepareTransfer('stargate', async () => preparedResult())
870
+ const route = TestFunding.data.routes.find(
871
+ (entry) => entry.providerId === 'relay' && entry.capabilities?.transfer,
872
+ )!
873
+ const catalog = FundingCatalog.compile({
874
+ catalog: {
875
+ id: 'default',
876
+ updatedAt: '2026-01-01T00:00:00.000Z',
877
+ version: 'test',
878
+ },
879
+ ...TestFunding.data,
880
+ routes: [...TestFunding.data.routes, { ...route, providerId: 'stargate' }],
881
+ })
882
+
883
+ expect(
884
+ FundingProvider.getPrepareCandidates({
885
+ ...prepareOptions,
886
+ catalog,
887
+ provider: 'stargate',
888
+ providers: [relay, stargate],
889
+ }).map(({ provider }) => provider.id),
890
+ ).toEqual(['stargate'])
891
+ })
892
+
837
893
  test('restricts candidates to the selected destination chain', () => {
838
894
  const provider = withPrepareTransfer('relay', async () => preparedResult())
839
895
  expect(
@@ -1110,6 +1166,19 @@ describe('getQuoteCandidates', () => {
1110
1166
  expect(candidate?.sourceAmount).toEqual({ amount: '1250000', formatted: '1.25' })
1111
1167
  })
1112
1168
 
1169
+ test('carries provider route configuration without duplicating token metadata', () => {
1170
+ const [candidate] = FundingProvider.getQuoteCandidates({
1171
+ ...baseUsdcRequest,
1172
+ provider: 'stargate',
1173
+ providers,
1174
+ })
1175
+
1176
+ expect(candidate?.configuration).toEqual({
1177
+ poolAddress: '0x27a16dc786820B16E5c9028b75B99F6f604b5d26',
1178
+ })
1179
+ expect(candidate?.sourceToken.address).toBe('0x833589fcd6edb6e08f4c7c32d4f71b54bda02913')
1180
+ })
1181
+
1113
1182
  test('resolves normalized catalog aliases', () => {
1114
1183
  const catalog = FundingCatalog.compile({
1115
1184
  catalog: {
@@ -1341,6 +1410,10 @@ describe('getProviders', () => {
1341
1410
  "id": "squid",
1342
1411
  "name": "Squid",
1343
1412
  },
1413
+ {
1414
+ "id": "stargate",
1415
+ "name": "Stargate",
1416
+ },
1344
1417
  {
1345
1418
  "id": "symbiosis",
1346
1419
  "name": "Symbiosis",