tapimo 0.15.1 → 0.18.1

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 (709) hide show
  1. package/README.md +137 -0
  2. package/dist/ApiKey.d.ts +1 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +4 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +37 -11
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +163 -10
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +13085 -11974
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +46 -15
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +1 -1
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +1 -1
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +893 -191
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +5 -1
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +70 -70
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +8 -3
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/earn-vaults.d.ts +66 -27
  27. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  28. package/dist/admin/apps/earn-vaults.js +36 -7
  29. package/dist/admin/apps/earn-vaults.js.map +1 -1
  30. package/dist/admin/apps/organizations.d.ts +25 -25
  31. package/dist/admin/apps/organizations.d.ts.map +1 -1
  32. package/dist/admin/apps/organizations.js +5 -4
  33. package/dist/admin/apps/organizations.js.map +1 -1
  34. package/dist/admin/apps/route-policies.d.ts +632 -0
  35. package/dist/admin/apps/route-policies.d.ts.map +1 -0
  36. package/dist/admin/apps/route-policies.js +257 -0
  37. package/dist/admin/apps/route-policies.js.map +1 -0
  38. package/dist/admin/apps/routes-support.js +39 -3
  39. package/dist/admin/apps/routes-support.js.map +1 -1
  40. package/dist/admin/apps/routes.d.ts +529 -76
  41. package/dist/admin/apps/routes.d.ts.map +1 -1
  42. package/dist/admin/apps/routes.js +82 -1
  43. package/dist/admin/apps/routes.js.map +1 -1
  44. package/dist/admin/apps/verified-tokens.d.ts +157 -157
  45. package/dist/admin/index.d.ts +0 -1
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +0 -1
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/ui.generated.d.ts +1 -1
  50. package/dist/admin/ui.generated.d.ts.map +1 -1
  51. package/dist/admin/ui.generated.js +205 -201
  52. package/dist/admin/ui.generated.js.map +1 -1
  53. package/dist/analytics/Analytics.d.ts.map +1 -1
  54. package/dist/analytics/Analytics.js +65 -1
  55. package/dist/analytics/Analytics.js.map +1 -1
  56. package/dist/analytics/tables/requestEvents.d.ts +1 -1
  57. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  58. package/dist/analytics/tables/requestEvents.js +58 -59
  59. package/dist/analytics/tables/requestEvents.js.map +1 -1
  60. package/dist/apps/data/App.d.ts +2709 -2670
  61. package/dist/apps/data/App.d.ts.map +1 -1
  62. package/dist/apps/data/routes/activities.d.ts +357 -357
  63. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  64. package/dist/apps/data/routes/activities.js +50 -0
  65. package/dist/apps/data/routes/activities.js.map +1 -1
  66. package/dist/apps/data/routes/addresses.d.ts +248 -248
  67. package/dist/apps/data/routes/balances.d.ts +22 -22
  68. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  69. package/dist/apps/data/routes/balances.js +5 -7
  70. package/dist/apps/data/routes/balances.js.map +1 -1
  71. package/dist/apps/data/routes/blocks.d.ts +125 -125
  72. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  73. package/dist/apps/data/routes/earn.d.ts +103 -12
  74. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  75. package/dist/apps/data/routes/earn.js +456 -220
  76. package/dist/apps/data/routes/earn.js.map +1 -1
  77. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  78. package/dist/apps/data/routes/exchanges.js +267 -97
  79. package/dist/apps/data/routes/exchanges.js.map +1 -1
  80. package/dist/apps/data/routes/fee-amm.d.ts +109 -127
  81. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  82. package/dist/apps/data/routes/fee-amm.js +83 -54
  83. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  84. package/dist/apps/data/routes/indexer.d.ts +43 -43
  85. package/dist/apps/data/routes/receipts.d.ts +235 -235
  86. package/dist/apps/data/routes/rpc.d.ts +30 -30
  87. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  88. package/dist/apps/data/routes/tokens.js +11 -6
  89. package/dist/apps/data/routes/tokens.js.map +1 -1
  90. package/dist/apps/data/routes/transactions.d.ts +2 -0
  91. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  92. package/dist/apps/data/routes/transactions.js +30 -22
  93. package/dist/apps/data/routes/transactions.js.map +1 -1
  94. package/dist/apps/data/routes/transfers.d.ts +77 -77
  95. package/dist/apps/data/routes/valuation.d.ts +32 -32
  96. package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
  97. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  98. package/dist/apps/data/routes/webhooks.js +1 -1
  99. package/dist/apps/data/routes/webhooks.js.map +1 -1
  100. package/dist/apps/data/routes/zones.d.ts +31 -31
  101. package/dist/apps/management/App.d.ts +2909 -2064
  102. package/dist/apps/management/App.d.ts.map +1 -1
  103. package/dist/apps/management/App.js +2 -0
  104. package/dist/apps/management/App.js.map +1 -1
  105. package/dist/apps/management/Billing.d.ts +2 -4
  106. package/dist/apps/management/Billing.d.ts.map +1 -1
  107. package/dist/apps/management/Billing.js +65 -26
  108. package/dist/apps/management/Billing.js.map +1 -1
  109. package/dist/apps/management/routes/api-keys.d.ts +257 -245
  110. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  111. package/dist/apps/management/routes/api-keys.js +70 -11
  112. package/dist/apps/management/routes/api-keys.js.map +1 -1
  113. package/dist/apps/management/routes/billing.d.ts +84 -84
  114. package/dist/apps/management/routes/cli.d.ts +912 -0
  115. package/dist/apps/management/routes/cli.d.ts.map +1 -0
  116. package/dist/apps/management/routes/cli.js +416 -0
  117. package/dist/apps/management/routes/cli.js.map +1 -0
  118. package/dist/apps/management/routes/faucet.d.ts +8 -8
  119. package/dist/apps/management/routes/invitations.d.ts +138 -138
  120. package/dist/apps/management/routes/invite-links.d.ts +172 -172
  121. package/dist/apps/management/routes/members.d.ts +16 -16
  122. package/dist/apps/management/routes/orgs.d.ts +104 -104
  123. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  124. package/dist/apps/management/routes/orgs.js +8 -2
  125. package/dist/apps/management/routes/orgs.js.map +1 -1
  126. package/dist/apps/management/routes/projects.d.ts +125 -125
  127. package/dist/apps/management/routes/usage.d.ts +8 -8
  128. package/dist/apps/management/routes/verified-token-requests.d.ts +86 -86
  129. package/dist/apps/management/routes/webhooks.d.ts +485 -485
  130. package/dist/apps/mpp/App.d.ts +44 -44
  131. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  132. package/dist/apps/mpp/internal/Policy.js +4 -2
  133. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  134. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
  135. package/dist/apps/mpp/internal/Sponsorship.js +6 -4
  136. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
  137. package/dist/apps/relay/App.d.ts +8 -0
  138. package/dist/apps/relay/App.d.ts.map +1 -1
  139. package/dist/apps/relay/App.js +16 -4
  140. package/dist/apps/relay/App.js.map +1 -1
  141. package/dist/apps/relay/Sponsorships.d.ts +4 -6
  142. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  143. package/dist/apps/relay/Sponsorships.js +71 -60
  144. package/dist/apps/relay/Sponsorships.js.map +1 -1
  145. package/dist/apps/routes/Access.d.ts +53 -0
  146. package/dist/apps/routes/Access.d.ts.map +1 -1
  147. package/dist/apps/routes/Access.js +121 -0
  148. package/dist/apps/routes/Access.js.map +1 -1
  149. package/dist/apps/routes/App.d.ts +397 -158
  150. package/dist/apps/routes/App.d.ts.map +1 -1
  151. package/dist/apps/routes/App.js.map +1 -1
  152. package/dist/apps/routes/routes/chains.d.ts +25 -25
  153. package/dist/apps/routes/routes/deposit-addresses.d.ts +169 -61
  154. package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -1
  155. package/dist/apps/routes/routes/deposit-addresses.js +217 -32
  156. package/dist/apps/routes/routes/deposit-addresses.js.map +1 -1
  157. package/dist/apps/routes/routes/quotes.d.ts +171 -81
  158. package/dist/apps/routes/routes/quotes.d.ts.map +1 -1
  159. package/dist/apps/routes/routes/quotes.js +101 -27
  160. package/dist/apps/routes/routes/quotes.js.map +1 -1
  161. package/dist/apps/routes/routes/transfers.d.ts +532 -480
  162. package/dist/apps/routes/routes/transfers.d.ts.map +1 -1
  163. package/dist/apps/routes/routes/transfers.js +182 -37
  164. package/dist/apps/routes/routes/transfers.js.map +1 -1
  165. package/dist/cli/ApiKeys.d.ts +120 -0
  166. package/dist/cli/ApiKeys.d.ts.map +1 -0
  167. package/dist/cli/ApiKeys.js +138 -0
  168. package/dist/cli/ApiKeys.js.map +1 -0
  169. package/dist/cli/Cli.d.ts +92 -34
  170. package/dist/cli/Cli.d.ts.map +1 -1
  171. package/dist/cli/Cli.js +188 -11
  172. package/dist/cli/Cli.js.map +1 -1
  173. package/dist/cli/Credentials.d.ts +95 -0
  174. package/dist/cli/Credentials.d.ts.map +1 -0
  175. package/dist/cli/Credentials.js +110 -0
  176. package/dist/cli/Credentials.js.map +1 -0
  177. package/dist/cli/Spec.d.ts +59 -0
  178. package/dist/cli/Spec.d.ts.map +1 -0
  179. package/dist/cli/Spec.js +77 -0
  180. package/dist/cli/Spec.js.map +1 -0
  181. package/dist/cli/bin.js +5 -1
  182. package/dist/cli/bin.js.map +1 -1
  183. package/dist/cli/commands/admin.d.ts +5 -5
  184. package/dist/cli/commands/admin.d.ts.map +1 -1
  185. package/dist/cli/commands/auth.d.ts +73 -0
  186. package/dist/cli/commands/auth.d.ts.map +1 -0
  187. package/dist/cli/commands/auth.js +204 -0
  188. package/dist/cli/commands/auth.js.map +1 -0
  189. package/dist/cli/commands/keys.d.ts +17 -0
  190. package/dist/cli/commands/keys.d.ts.map +1 -0
  191. package/dist/cli/commands/keys.js +109 -0
  192. package/dist/cli/commands/keys.js.map +1 -0
  193. package/dist/cloudflare.d.ts +27 -2
  194. package/dist/cloudflare.d.ts.map +1 -1
  195. package/dist/cloudflare.js +144 -17
  196. package/dist/cloudflare.js.map +1 -1
  197. package/dist/db/Db.d.ts +23 -0
  198. package/dist/db/Db.d.ts.map +1 -1
  199. package/dist/db/Db.js +413 -1
  200. package/dist/db/Db.js.map +1 -1
  201. package/dist/db/Schema.d.ts +44 -1
  202. package/dist/db/Schema.d.ts.map +1 -1
  203. package/dist/db/Schema.js +56 -3
  204. package/dist/db/Schema.js.map +1 -1
  205. package/dist/db/tables/apiKeyAdmissions.d.ts +28 -2
  206. package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -1
  207. package/dist/db/tables/apiKeyAdmissions.js +65 -9
  208. package/dist/db/tables/apiKeyAdmissions.js.map +1 -1
  209. package/dist/db/tables/apiKeyOwnerTombstones.d.ts +2 -0
  210. package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -1
  211. package/dist/db/tables/apiKeyOwnerTombstones.js +2 -2
  212. package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -1
  213. package/dist/db/tables/authAccounts.d.ts.map +1 -1
  214. package/dist/db/tables/authAccounts.js +1 -0
  215. package/dist/db/tables/authAccounts.js.map +1 -1
  216. package/dist/db/tables/earnVaults.d.ts +5 -1
  217. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  218. package/dist/db/tables/earnVaults.js +12 -1
  219. package/dist/db/tables/earnVaults.js.map +1 -1
  220. package/dist/db/tables/organizations.d.ts +4 -2
  221. package/dist/db/tables/organizations.d.ts.map +1 -1
  222. package/dist/db/tables/organizations.js +8 -34
  223. package/dist/db/tables/organizations.js.map +1 -1
  224. package/dist/db/tables/requestUsage.d.ts +5 -1
  225. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  226. package/dist/db/tables/requestUsage.js +10 -2
  227. package/dist/db/tables/requestUsage.js.map +1 -1
  228. package/dist/db/tables/rewardEligibilityAssociations.d.ts +13 -0
  229. package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -1
  230. package/dist/db/tables/rewardEligibilityAssociations.js +11 -0
  231. package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -1
  232. package/dist/db/tables/rewardRuns.d.ts.map +1 -1
  233. package/dist/db/tables/rewardRuns.js +4 -0
  234. package/dist/db/tables/rewardRuns.js.map +1 -1
  235. package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -1
  236. package/dist/db/tables/rewardTransactionAttempts.js +2 -0
  237. package/dist/db/tables/rewardTransactionAttempts.js.map +1 -1
  238. package/dist/db/tables/routesDepositAddresses.d.ts +29 -0
  239. package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -1
  240. package/dist/db/tables/routesDepositAddresses.js +84 -31
  241. package/dist/db/tables/routesDepositAddresses.js.map +1 -1
  242. package/dist/db/tables/routesDeposits.d.ts.map +1 -1
  243. package/dist/db/tables/routesDeposits.js +31 -21
  244. package/dist/db/tables/routesDeposits.js.map +1 -1
  245. package/dist/db/tables/routesIdempotency.d.ts.map +1 -1
  246. package/dist/db/tables/routesIdempotency.js +2 -0
  247. package/dist/db/tables/routesIdempotency.js.map +1 -1
  248. package/dist/db/tables/routesPolicies.d.ts +58 -0
  249. package/dist/db/tables/routesPolicies.d.ts.map +1 -0
  250. package/dist/db/tables/routesPolicies.js +198 -0
  251. package/dist/db/tables/routesPolicies.js.map +1 -0
  252. package/dist/db/tables/routesTransferSubsidies.d.ts +22 -0
  253. package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -1
  254. package/dist/db/tables/routesTransferSubsidies.js +41 -0
  255. package/dist/db/tables/routesTransferSubsidies.js.map +1 -1
  256. package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -1
  257. package/dist/db/tables/routesTransferSubsidyNonces.js +12 -4
  258. package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -1
  259. package/dist/db/tables/routesTransfers.d.ts +26 -1
  260. package/dist/db/tables/routesTransfers.d.ts.map +1 -1
  261. package/dist/db/tables/routesTransfers.js +36 -6
  262. package/dist/db/tables/routesTransfers.js.map +1 -1
  263. package/dist/db/tables/sponsoredTransactions.d.ts +45 -13
  264. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  265. package/dist/db/tables/sponsoredTransactions.js +144 -33
  266. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  267. package/dist/db/tables/users.d.ts +2 -0
  268. package/dist/db/tables/users.d.ts.map +1 -1
  269. package/dist/db/tables/users.js +11 -0
  270. package/dist/db/tables/users.js.map +1 -1
  271. package/dist/handlers/internal/multisig.d.ts +1 -1
  272. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  273. package/dist/handlers/internal/multisig.js +3 -2
  274. package/dist/handlers/internal/multisig.js.map +1 -1
  275. package/dist/handlers/relay.d.ts +2 -0
  276. package/dist/handlers/relay.d.ts.map +1 -1
  277. package/dist/handlers/relay.js +34 -15
  278. package/dist/handlers/relay.js.map +1 -1
  279. package/dist/internal/Auth.d.ts +57 -6
  280. package/dist/internal/Auth.d.ts.map +1 -1
  281. package/dist/internal/Auth.js +182 -78
  282. package/dist/internal/Auth.js.map +1 -1
  283. package/dist/internal/BetterAuth.d.ts +22 -0
  284. package/dist/internal/BetterAuth.d.ts.map +1 -1
  285. package/dist/internal/BetterAuth.js +17 -14
  286. package/dist/internal/BetterAuth.js.map +1 -1
  287. package/dist/internal/Cache.d.ts +5 -0
  288. package/dist/internal/Cache.d.ts.map +1 -1
  289. package/dist/internal/Cache.js +3 -1
  290. package/dist/internal/Cache.js.map +1 -1
  291. package/dist/internal/CliAuth.d.ts +243 -0
  292. package/dist/internal/CliAuth.d.ts.map +1 -0
  293. package/dist/internal/CliAuth.js +249 -0
  294. package/dist/internal/CliAuth.js.map +1 -0
  295. package/dist/internal/EarnSharePrices.d.ts +1 -1
  296. package/dist/internal/EarnSharePrices.d.ts.map +1 -1
  297. package/dist/internal/EarnSharePrices.js +7 -3
  298. package/dist/internal/EarnSharePrices.js.map +1 -1
  299. package/dist/internal/EarnVaults.d.ts +47 -0
  300. package/dist/internal/EarnVaults.d.ts.map +1 -1
  301. package/dist/internal/EarnVaults.js +188 -4
  302. package/dist/internal/EarnVaults.js.map +1 -1
  303. package/dist/internal/EarnWithdrawals.d.ts +73 -0
  304. package/dist/internal/EarnWithdrawals.d.ts.map +1 -0
  305. package/dist/internal/EarnWithdrawals.js +189 -0
  306. package/dist/internal/EarnWithdrawals.js.map +1 -0
  307. package/dist/internal/ExecutionContext.d.ts +21 -0
  308. package/dist/internal/ExecutionContext.d.ts.map +1 -0
  309. package/dist/internal/ExecutionContext.js +16 -0
  310. package/dist/internal/ExecutionContext.js.map +1 -0
  311. package/dist/internal/Log.d.ts +7 -3
  312. package/dist/internal/Log.d.ts.map +1 -1
  313. package/dist/internal/Log.js +163 -130
  314. package/dist/internal/Log.js.map +1 -1
  315. package/dist/internal/MetricSink.d.ts.map +1 -1
  316. package/dist/internal/MetricSink.js +26 -1
  317. package/dist/internal/MetricSink.js.map +1 -1
  318. package/dist/internal/RateLimit.d.ts +67 -0
  319. package/dist/internal/RateLimit.d.ts.map +1 -1
  320. package/dist/internal/RateLimit.js +174 -27
  321. package/dist/internal/RateLimit.js.map +1 -1
  322. package/dist/internal/Store.d.ts +6 -0
  323. package/dist/internal/Store.d.ts.map +1 -1
  324. package/dist/internal/Store.js +4 -5
  325. package/dist/internal/Store.js.map +1 -1
  326. package/dist/internal/Timing.d.ts +6 -0
  327. package/dist/internal/Timing.d.ts.map +1 -1
  328. package/dist/internal/Timing.js +21 -1
  329. package/dist/internal/Timing.js.map +1 -1
  330. package/dist/internal/Tron.d.ts +124 -0
  331. package/dist/internal/Tron.d.ts.map +1 -0
  332. package/dist/internal/Tron.js +202 -0
  333. package/dist/internal/Tron.js.map +1 -0
  334. package/dist/internal/Viem.d.ts +4 -0
  335. package/dist/internal/Viem.d.ts.map +1 -1
  336. package/dist/internal/Viem.js +25 -6
  337. package/dist/internal/Viem.js.map +1 -1
  338. package/dist/internal/rewards/Read.d.ts +2 -2
  339. package/dist/internal/rewards/Read.d.ts.map +1 -1
  340. package/dist/internal/rewards/Read.js +11 -2
  341. package/dist/internal/rewards/Read.js.map +1 -1
  342. package/dist/internal/routes/Action.d.ts +27 -0
  343. package/dist/internal/routes/Action.d.ts.map +1 -1
  344. package/dist/internal/routes/Action.js +49 -1
  345. package/dist/internal/routes/Action.js.map +1 -1
  346. package/dist/internal/routes/Chain.d.ts +2 -0
  347. package/dist/internal/routes/Chain.d.ts.map +1 -1
  348. package/dist/internal/routes/Chain.js +4 -0
  349. package/dist/internal/routes/Chain.js.map +1 -1
  350. package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
  351. package/dist/internal/routes/DepositAddress.js +5 -0
  352. package/dist/internal/routes/DepositAddress.js.map +1 -1
  353. package/dist/internal/routes/Evidence.d.ts.map +1 -1
  354. package/dist/internal/routes/Evidence.js +6 -2
  355. package/dist/internal/routes/Evidence.js.map +1 -1
  356. package/dist/internal/routes/EvmTransferSettlement.d.ts +17 -0
  357. package/dist/internal/routes/EvmTransferSettlement.d.ts.map +1 -0
  358. package/dist/internal/routes/EvmTransferSettlement.js +196 -0
  359. package/dist/internal/routes/EvmTransferSettlement.js.map +1 -0
  360. package/dist/internal/routes/Policy.d.ts +161 -0
  361. package/dist/internal/routes/Policy.d.ts.map +1 -0
  362. package/dist/internal/routes/Policy.js +249 -0
  363. package/dist/internal/routes/Policy.js.map +1 -0
  364. package/dist/internal/routes/Provider.d.ts +66 -3
  365. package/dist/internal/routes/Provider.d.ts.map +1 -1
  366. package/dist/internal/routes/Provider.js +106 -27
  367. package/dist/internal/routes/Provider.js.map +1 -1
  368. package/dist/internal/routes/Quota.d.ts +57 -0
  369. package/dist/internal/routes/Quota.d.ts.map +1 -0
  370. package/dist/internal/routes/Quota.js +144 -0
  371. package/dist/internal/routes/Quota.js.map +1 -0
  372. package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
  373. package/dist/internal/routes/Reconciliation.js +163 -47
  374. package/dist/internal/routes/Reconciliation.js.map +1 -1
  375. package/dist/internal/routes/SolanaTransferSettlement.d.ts +12 -0
  376. package/dist/internal/routes/SolanaTransferSettlement.d.ts.map +1 -0
  377. package/dist/internal/routes/SolanaTransferSettlement.js +220 -0
  378. package/dist/internal/routes/SolanaTransferSettlement.js.map +1 -0
  379. package/dist/internal/routes/SolanaTransferSubsidy.d.ts +172 -0
  380. package/dist/internal/routes/SolanaTransferSubsidy.d.ts.map +1 -0
  381. package/dist/internal/routes/SolanaTransferSubsidy.js +564 -0
  382. package/dist/internal/routes/SolanaTransferSubsidy.js.map +1 -0
  383. package/dist/internal/routes/Subsidy.d.ts +2 -2
  384. package/dist/internal/routes/Subsidy.d.ts.map +1 -1
  385. package/dist/internal/routes/Subsidy.js +2 -2
  386. package/dist/internal/routes/Subsidy.js.map +1 -1
  387. package/dist/internal/routes/Transfer.d.ts +229 -1
  388. package/dist/internal/routes/Transfer.d.ts.map +1 -1
  389. package/dist/internal/routes/Transfer.js +644 -7
  390. package/dist/internal/routes/Transfer.js.map +1 -1
  391. package/dist/internal/routes/TransferReconciliation.d.ts +6 -0
  392. package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -1
  393. package/dist/internal/routes/TransferReconciliation.js +83 -159
  394. package/dist/internal/routes/TransferReconciliation.js.map +1 -1
  395. package/dist/internal/routes/TransferSettlement.d.ts +45 -0
  396. package/dist/internal/routes/TransferSettlement.d.ts.map +1 -0
  397. package/dist/internal/routes/TransferSettlement.js +2 -0
  398. package/dist/internal/routes/TransferSettlement.js.map +1 -0
  399. package/dist/internal/routes/TransferSubsidy.d.ts +23 -8
  400. package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -1
  401. package/dist/internal/routes/TransferSubsidy.js +64 -5
  402. package/dist/internal/routes/TransferSubsidy.js.map +1 -1
  403. package/dist/internal/routes/TronTransferSettlement.d.ts +12 -0
  404. package/dist/internal/routes/TronTransferSettlement.d.ts.map +1 -0
  405. package/dist/internal/routes/TronTransferSettlement.js +201 -0
  406. package/dist/internal/routes/TronTransferSettlement.js.map +1 -0
  407. package/dist/internal/routes/TronTransferSubsidy.d.ts +174 -0
  408. package/dist/internal/routes/TronTransferSubsidy.d.ts.map +1 -0
  409. package/dist/internal/routes/TronTransferSubsidy.js +439 -0
  410. package/dist/internal/routes/TronTransferSubsidy.js.map +1 -0
  411. package/dist/internal/routes/index.d.ts +3 -0
  412. package/dist/internal/routes/index.d.ts.map +1 -1
  413. package/dist/internal/routes/index.js +3 -0
  414. package/dist/internal/routes/index.js.map +1 -1
  415. package/dist/internal/routes/providers/across.d.ts +3 -0
  416. package/dist/internal/routes/providers/across.d.ts.map +1 -1
  417. package/dist/internal/routes/providers/across.js +11 -0
  418. package/dist/internal/routes/providers/across.js.map +1 -1
  419. package/dist/internal/routes/providers/legacyMesh.d.ts +29 -0
  420. package/dist/internal/routes/providers/legacyMesh.d.ts.map +1 -0
  421. package/dist/internal/routes/providers/legacyMesh.js +474 -0
  422. package/dist/internal/routes/providers/legacyMesh.js.map +1 -0
  423. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts +59 -0
  424. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts.map +1 -0
  425. package/dist/internal/routes/providers/legacyMeshDelivery.js +229 -0
  426. package/dist/internal/routes/providers/legacyMeshDelivery.js.map +1 -0
  427. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts +19 -0
  428. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts.map +1 -0
  429. package/dist/internal/routes/providers/legacyMeshOutbound.js +457 -0
  430. package/dist/internal/routes/providers/legacyMeshOutbound.js.map +1 -0
  431. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts +123 -0
  432. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts.map +1 -0
  433. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js +333 -0
  434. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js.map +1 -0
  435. package/dist/internal/routes/providers/propAmm.d.ts +70 -0
  436. package/dist/internal/routes/providers/propAmm.d.ts.map +1 -0
  437. package/dist/internal/routes/providers/propAmm.js +524 -0
  438. package/dist/internal/routes/providers/propAmm.js.map +1 -0
  439. package/dist/internal/routes/providers/relay.d.ts +3 -0
  440. package/dist/internal/routes/providers/relay.d.ts.map +1 -1
  441. package/dist/internal/routes/providers/relay.js +352 -41
  442. package/dist/internal/routes/providers/relay.js.map +1 -1
  443. package/dist/internal/routes/providers/rhino.d.ts +3 -0
  444. package/dist/internal/routes/providers/rhino.d.ts.map +1 -1
  445. package/dist/internal/routes/providers/rhino.js +11 -0
  446. package/dist/internal/routes/providers/rhino.js.map +1 -1
  447. package/dist/internal/routes/providers/squid.d.ts +3 -0
  448. package/dist/internal/routes/providers/squid.d.ts.map +1 -1
  449. package/dist/internal/routes/providers/squid.js +19 -0
  450. package/dist/internal/routes/providers/squid.js.map +1 -1
  451. package/dist/internal/routes/providers/stargate.d.ts.map +1 -1
  452. package/dist/internal/routes/providers/stargate.js +22 -9
  453. package/dist/internal/routes/providers/stargate.js.map +1 -1
  454. package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -1
  455. package/dist/internal/routes/providers/symbiosis.js +13 -17
  456. package/dist/internal/routes/providers/symbiosis.js.map +1 -1
  457. package/dist/providers/index.d.ts +14 -0
  458. package/dist/providers/index.d.ts.map +1 -1
  459. package/dist/providers/index.js +6 -0
  460. package/dist/providers/index.js.map +1 -1
  461. package/package.json +16 -6
  462. package/src/ApiKey.ts +7 -3
  463. package/src/ApiKeys.test.ts +652 -8
  464. package/src/ApiKeys.ts +191 -11
  465. package/src/App.test.ts +405 -18
  466. package/src/App.ts +51 -15
  467. package/src/Client.test-d.ts +157 -10
  468. package/src/Client.test.ts +4 -4
  469. package/src/Scope.ts +1 -2
  470. package/src/admin/App.ts +11 -5
  471. package/src/admin/apps/api-keys.test.ts +98 -2
  472. package/src/admin/apps/api-keys.ts +21 -12
  473. package/src/admin/apps/earn-vaults.test.ts +76 -7
  474. package/src/admin/apps/earn-vaults.ts +47 -8
  475. package/src/admin/apps/organizations.test.ts +147 -31
  476. package/src/admin/apps/organizations.ts +5 -4
  477. package/src/admin/apps/route-policies.test.ts +220 -0
  478. package/src/admin/apps/route-policies.ts +322 -0
  479. package/src/admin/apps/routes-support.test.ts +107 -2
  480. package/src/admin/apps/routes-support.ts +43 -3
  481. package/src/admin/apps/routes.test.ts +150 -0
  482. package/src/admin/apps/routes.ts +97 -1
  483. package/src/admin/apps/scopes.test.ts +1 -1
  484. package/src/admin/index.ts +0 -1
  485. package/src/admin/ui/plugin.ts +2 -1
  486. package/src/admin/ui/src/components/Dialog.tsx +1 -1
  487. package/src/admin/ui/src/components/EarnVaultForm.tsx +45 -0
  488. package/src/admin/ui/src/components/RoutePicker.tsx +79 -0
  489. package/src/admin/ui/src/lib/earn-vaults.ts +1 -1
  490. package/src/admin/ui/src/lib/route-policies.test.ts +452 -0
  491. package/src/admin/ui/src/lib/route-policies.ts +232 -0
  492. package/src/admin/ui/src/lib/routes.ts +34 -0
  493. package/src/admin/ui/src/routeTree.gen.ts +21 -0
  494. package/src/admin/ui/src/routes/api-keys.tsx +21 -2
  495. package/src/admin/ui/src/routes/early-access.tsx +1 -0
  496. package/src/admin/ui/src/routes/earn.vaults.tsx +1 -0
  497. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +22 -0
  498. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +10 -0
  499. package/src/admin/ui/src/routes/organizations.tsx +1 -0
  500. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +18 -3
  501. package/src/admin/ui/src/routes/route-policies.tsx +678 -0
  502. package/src/admin/ui/src/routes/routes.tsx +85 -2
  503. package/src/admin/ui/src/routes/routes_.support.tsx +6 -22
  504. package/src/admin/ui/src/routes/subsidies.tsx +1 -0
  505. package/src/admin/ui/src/routes/verified-tokens.tsx +1 -0
  506. package/src/admin/ui.generated.ts +258 -202
  507. package/src/analytics/Analytics.test.ts +4 -50
  508. package/src/analytics/Analytics.ts +65 -1
  509. package/src/analytics/tables/requestEvents.test.ts +402 -1
  510. package/src/analytics/tables/requestEvents.ts +62 -93
  511. package/src/apps/data/routes/activities.test.ts +315 -14
  512. package/src/apps/data/routes/activities.ts +60 -0
  513. package/src/apps/data/routes/balances.ts +5 -7
  514. package/src/apps/data/routes/earn.bench.ts +18 -0
  515. package/src/apps/data/routes/earn.local.test.ts +507 -0
  516. package/src/apps/data/routes/earn.test.ts +405 -127
  517. package/src/apps/data/routes/earn.ts +660 -270
  518. package/src/apps/data/routes/exchanges.bench.ts +3 -1
  519. package/src/apps/data/routes/exchanges.test.ts +166 -2
  520. package/src/apps/data/routes/exchanges.ts +308 -101
  521. package/src/apps/data/routes/fee-amm.test.ts +134 -2
  522. package/src/apps/data/routes/fee-amm.ts +122 -60
  523. package/src/apps/data/routes/receipts.test.ts +21 -18
  524. package/src/apps/data/routes/rpc.test.ts +2 -2
  525. package/src/apps/data/routes/tokens.provenance.test.ts +157 -0
  526. package/src/apps/data/routes/tokens.test.ts +4 -4
  527. package/src/apps/data/routes/tokens.ts +11 -6
  528. package/src/apps/data/routes/transactions.test.ts +29 -0
  529. package/src/apps/data/routes/transactions.ts +33 -22
  530. package/src/apps/data/routes/webhooks.test.ts +12 -3
  531. package/src/apps/data/routes/webhooks.ts +2 -1
  532. package/src/apps/management/App.ts +4 -0
  533. package/src/apps/management/Billing.test.ts +253 -27
  534. package/src/apps/management/Billing.ts +83 -29
  535. package/src/apps/management/routes/api-keys.test.ts +1 -1
  536. package/src/apps/management/routes/api-keys.ts +85 -11
  537. package/src/apps/management/routes/billing.test.ts +68 -4
  538. package/src/apps/management/routes/cli.test.ts +370 -0
  539. package/src/apps/management/routes/cli.ts +533 -0
  540. package/src/apps/management/routes/me.test.ts +14 -4
  541. package/src/apps/management/routes/orgs.test.ts +108 -4
  542. package/src/apps/management/routes/orgs.ts +7 -2
  543. package/src/apps/management/routes/usage.test.ts +2 -2
  544. package/src/apps/mpp/internal/Policy.test.ts +51 -4
  545. package/src/apps/mpp/internal/Policy.ts +6 -2
  546. package/src/apps/mpp/internal/Sponsorship.test.ts +29 -0
  547. package/src/apps/mpp/internal/Sponsorship.ts +6 -4
  548. package/src/apps/relay/App.test.ts +85 -1
  549. package/src/apps/relay/App.ts +28 -4
  550. package/src/apps/relay/Sponsorships.test.ts +97 -1
  551. package/src/apps/relay/Sponsorships.ts +77 -66
  552. package/src/apps/routes/Access.test.ts +319 -0
  553. package/src/apps/routes/Access.ts +147 -0
  554. package/src/apps/routes/App.ts +10 -0
  555. package/src/apps/routes/routes/chains.test.ts +3 -2
  556. package/src/apps/routes/routes/deposit-addresses.test.ts +978 -34
  557. package/src/apps/routes/routes/deposit-addresses.ts +243 -32
  558. package/src/apps/routes/routes/propAmm.local.test.ts +951 -0
  559. package/src/apps/routes/routes/quotes.test.ts +81 -8
  560. package/src/apps/routes/routes/quotes.ts +109 -27
  561. package/src/apps/routes/routes/transfers.test.ts +252 -15
  562. package/src/apps/routes/routes/transfers.ts +212 -33
  563. package/src/cli/ApiKeys.test.ts +265 -0
  564. package/src/cli/ApiKeys.ts +189 -0
  565. package/src/cli/Cli.test.ts +188 -0
  566. package/src/cli/Cli.ts +280 -12
  567. package/src/cli/Credentials.test.ts +122 -0
  568. package/src/cli/Credentials.ts +144 -0
  569. package/src/cli/Spec.test.ts +133 -0
  570. package/src/cli/Spec.ts +132 -0
  571. package/src/cli/bin.test.ts +49 -0
  572. package/src/cli/bin.ts +5 -1
  573. package/src/cli/commands/auth.test.ts +138 -0
  574. package/src/cli/commands/auth.ts +254 -0
  575. package/src/cli/commands/keys.test.ts +68 -0
  576. package/src/cli/commands/keys.ts +125 -0
  577. package/src/cloudflare.ts +184 -36
  578. package/src/db/Db.test.ts +877 -0
  579. package/src/db/Db.ts +498 -1
  580. package/src/db/Schema.ts +75 -4
  581. package/src/db/tables/apiKeyAdmissions.test.ts +57 -0
  582. package/src/db/tables/apiKeyAdmissions.ts +101 -11
  583. package/src/db/tables/apiKeyOwnerTombstones.ts +2 -2
  584. package/src/db/tables/authAccounts.test.ts +30 -0
  585. package/src/db/tables/authAccounts.ts +1 -0
  586. package/src/db/tables/earnVaults.test.ts +34 -0
  587. package/src/db/tables/earnVaults.ts +17 -2
  588. package/src/db/tables/organizations.test.ts +148 -84
  589. package/src/db/tables/organizations.ts +11 -43
  590. package/src/db/tables/requestUsage.ts +13 -2
  591. package/src/db/tables/rewardCampaigns.test.ts +163 -0
  592. package/src/db/tables/rewardEligibilityAssociations.test.ts +14 -0
  593. package/src/db/tables/rewardEligibilityAssociations.ts +24 -0
  594. package/src/db/tables/rewardRuns.ts +4 -0
  595. package/src/db/tables/rewardTransactionAttempts.ts +2 -0
  596. package/src/db/tables/routesDepositAddresses.test.ts +263 -0
  597. package/src/db/tables/routesDepositAddresses.ts +118 -34
  598. package/src/db/tables/routesDeposits.test.ts +66 -5
  599. package/src/db/tables/routesDeposits.ts +47 -26
  600. package/src/db/tables/routesIdempotency.test.ts +80 -0
  601. package/src/db/tables/routesIdempotency.ts +2 -0
  602. package/src/db/tables/routesPolicies.test.ts +143 -0
  603. package/src/db/tables/routesPolicies.ts +251 -0
  604. package/src/db/tables/routesTransferSubsidies.ts +64 -0
  605. package/src/db/tables/routesTransferSubsidyNonces.ts +16 -4
  606. package/src/db/tables/routesTransfers.test.ts +183 -2
  607. package/src/db/tables/routesTransfers.ts +65 -6
  608. package/src/db/tables/sponsoredTransactions.test.ts +351 -76
  609. package/src/db/tables/sponsoredTransactions.ts +182 -38
  610. package/src/db/tables/users.test.ts +51 -0
  611. package/src/db/tables/users.ts +12 -0
  612. package/src/handlers/internal/multisig.store.test.ts +120 -0
  613. package/src/handlers/internal/multisig.test.ts +389 -0
  614. package/src/handlers/internal/multisig.ts +13 -10
  615. package/src/handlers/relay.test.ts +259 -83
  616. package/src/handlers/relay.ts +36 -17
  617. package/src/internal/Auth.test.ts +291 -8
  618. package/src/internal/Auth.ts +227 -96
  619. package/src/internal/BetterAuth.test.ts +58 -22
  620. package/src/internal/BetterAuth.ts +23 -17
  621. package/src/internal/Cache.ts +3 -1
  622. package/src/internal/CliAuth.test.ts +279 -0
  623. package/src/internal/CliAuth.ts +319 -0
  624. package/src/internal/EarnSharePrices.test.ts +25 -0
  625. package/src/internal/EarnSharePrices.ts +9 -2
  626. package/src/internal/EarnVaults.test.ts +67 -0
  627. package/src/internal/EarnVaults.ts +299 -4
  628. package/src/internal/EarnWithdrawals.test.ts +315 -0
  629. package/src/internal/EarnWithdrawals.ts +266 -0
  630. package/src/internal/ExecutionContext.ts +31 -0
  631. package/src/internal/Log.test.ts +210 -0
  632. package/src/internal/Log.ts +180 -142
  633. package/src/internal/MetricSink.test.ts +190 -15
  634. package/src/internal/MetricSink.ts +27 -1
  635. package/src/internal/RateLimit.test.ts +144 -8
  636. package/src/internal/RateLimit.ts +254 -26
  637. package/src/internal/Store.ts +4 -5
  638. package/src/internal/Timing.test.ts +32 -0
  639. package/src/internal/Timing.ts +20 -1
  640. package/src/internal/Tron.test-d.ts +22 -0
  641. package/src/internal/Tron.test.ts +94 -0
  642. package/src/internal/Tron.ts +289 -0
  643. package/src/internal/Viem.rpc.test.ts +76 -0
  644. package/src/internal/Viem.ts +29 -6
  645. package/src/internal/rewards/Read.test.ts +109 -0
  646. package/src/internal/rewards/Read.ts +13 -4
  647. package/src/internal/routes/Action.test.ts +70 -0
  648. package/src/internal/routes/Action.ts +76 -1
  649. package/src/internal/routes/Chain.test.ts +18 -0
  650. package/src/internal/routes/Chain.ts +5 -0
  651. package/src/internal/routes/DepositAddress.ts +5 -0
  652. package/src/internal/routes/Evidence.test.ts +64 -0
  653. package/src/internal/routes/Evidence.ts +11 -3
  654. package/src/internal/routes/EvmTransferSettlement.ts +213 -0
  655. package/src/internal/routes/Policy.test.ts +316 -0
  656. package/src/internal/routes/Policy.ts +399 -0
  657. package/src/internal/routes/Provider.test.ts +103 -2
  658. package/src/internal/routes/Provider.ts +149 -27
  659. package/src/internal/routes/Quota.test.ts +149 -0
  660. package/src/internal/routes/Quota.ts +226 -0
  661. package/src/internal/routes/Reconciliation.local.test.ts +285 -0
  662. package/src/internal/routes/Reconciliation.test.ts +371 -13
  663. package/src/internal/routes/Reconciliation.ts +193 -42
  664. package/src/internal/routes/SolanaTransferSettlement.ts +232 -0
  665. package/src/internal/routes/SolanaTransferSubsidy.test.ts +471 -0
  666. package/src/internal/routes/SolanaTransferSubsidy.ts +760 -0
  667. package/src/internal/routes/SourceObservation.test.ts +221 -0
  668. package/src/internal/routes/Subsidy.local.test.ts +46 -0
  669. package/src/internal/routes/Subsidy.ts +4 -2
  670. package/src/internal/routes/Transfer.solana.test.ts +389 -0
  671. package/src/internal/routes/Transfer.test.ts +130 -1
  672. package/src/internal/routes/Transfer.tron.test.ts +172 -0
  673. package/src/internal/routes/Transfer.ts +866 -8
  674. package/src/internal/routes/TransferReconciliation.test.ts +26 -4
  675. package/src/internal/routes/TransferReconciliation.ts +91 -166
  676. package/src/internal/routes/TransferSettlement.ts +48 -0
  677. package/src/internal/routes/TransferSubsidy.local.test.ts +143 -0
  678. package/src/internal/routes/TransferSubsidy.test.ts +34 -4
  679. package/src/internal/routes/TransferSubsidy.ts +87 -12
  680. package/src/internal/routes/TronTransferSettlement.ts +212 -0
  681. package/src/internal/routes/TronTransferSubsidy.test.ts +109 -0
  682. package/src/internal/routes/TronTransferSubsidy.ts +619 -0
  683. package/src/internal/routes/index.test.ts +3 -0
  684. package/src/internal/routes/index.ts +3 -0
  685. package/src/internal/routes/providers/across.ts +13 -0
  686. package/src/internal/routes/providers/index.test.ts +141 -0
  687. package/src/internal/routes/providers/legacyMesh.test.ts +484 -0
  688. package/src/internal/routes/providers/legacyMesh.ts +633 -0
  689. package/src/internal/routes/providers/legacyMeshDelivery.test.ts +306 -0
  690. package/src/internal/routes/providers/legacyMeshDelivery.ts +320 -0
  691. package/src/internal/routes/providers/legacyMeshOutbound.test.ts +401 -0
  692. package/src/internal/routes/providers/legacyMeshOutbound.ts +566 -0
  693. package/src/internal/routes/providers/legacyMeshOutboundDelivery.ts +473 -0
  694. package/src/internal/routes/providers/propAmm.ts +640 -0
  695. package/src/internal/routes/providers/relay.test.ts +1263 -41
  696. package/src/internal/routes/providers/relay.ts +423 -38
  697. package/src/internal/routes/providers/rhino.ts +14 -1
  698. package/src/internal/routes/providers/squid.ts +21 -0
  699. package/src/internal/routes/providers/stargate.test.ts +105 -1
  700. package/src/internal/routes/providers/stargate.ts +22 -9
  701. package/src/internal/routes/providers/symbiosis.ts +13 -47
  702. package/src/providers/index.test.ts +2 -0
  703. package/src/providers/index.ts +18 -0
  704. package/dist/admin/Access.d.ts +0 -39
  705. package/dist/admin/Access.d.ts.map +0 -1
  706. package/dist/admin/Access.js +0 -73
  707. package/dist/admin/Access.js.map +0 -1
  708. package/src/admin/Access.test.ts +0 -130
  709. package/src/admin/Access.ts +0 -85
@@ -1,4 +1,5 @@
1
1
  import { Hono } from 'hono'
2
+ import { sql } from 'kysely'
2
3
  import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
3
4
 
4
5
  import * as TestApp from '../../../../test/App.js'
@@ -11,6 +12,8 @@ import * as EarlyAccess from '../../../db/tables/earlyAccess.js'
11
12
  import * as EnabledBillingSources from '../../../db/tables/enabledBillingSources.js'
12
13
  import * as Organizations from '../../../db/tables/organizations.js'
13
14
  import * as Projects from '../../../db/tables/projects.js'
15
+ import * as SponsoredTransactions from '../../../db/tables/sponsoredTransactions.js'
16
+ import * as StripeCustomers from '../../../db/tables/stripeCustomers.js'
14
17
  import * as Users from '../../../db/tables/users.js'
15
18
  import type * as Log from '../../../internal/Log.js'
16
19
  import * as RoutesDepositAddress from '../../../internal/routes/DepositAddress.js'
@@ -568,7 +571,39 @@ describe('PATCH /orgs/:orgId', () => {
568
571
  })
569
572
 
570
573
  describe('DELETE /orgs/:orgId', () => {
571
- test('rejects a legacy key after deletion when KV cleanup fails', async () => {
574
+ test('keeps a timed-out Zone sponsorship billable when its owner requests deletion', async () => {
575
+ const db = TestApp.database()
576
+ const app = createApp(db)
577
+ const cookie = await session(app)
578
+ const created = await app.request('/v1/orgs', json('POST', cookie, { name: 'Acme' }))
579
+ const org = await TestApp.json(created, Orgs.schema.Organization)
580
+ await StripeCustomers.create(db, { orgId: org.id, stripeCustomerId: 'cus_zone' })
581
+ const row = await SponsoredTransactions.upsert(db, {
582
+ apiKeyId: 'key_zone',
583
+ billable: true,
584
+ chainId: 421700001,
585
+ environment: 'production',
586
+ orgId: org.id,
587
+ signPayload: `0x${'bb'.repeat(32)}`,
588
+ transaction: `0x76${'cc'.repeat(16)}`,
589
+ transactionHash: `0x${'aa'.repeat(32)}`,
590
+ })
591
+ await SponsoredTransactions.fail(db, row.id, '2026-01-01T00:00:00.000Z')
592
+
593
+ const response = await app.request(`/v1/orgs/${org.id}`, {
594
+ headers: { cookie },
595
+ method: 'DELETE',
596
+ })
597
+
598
+ expect(response.status).toMatchInlineSnapshot(`409`)
599
+ expect((await response.json()).error.code).toMatchInlineSnapshot(`"sponsorships_unreported"`)
600
+ expect((await StripeCustomers.get(db, org.id))?.stripeCustomerId).toMatchInlineSnapshot(
601
+ `"cus_zone"`,
602
+ )
603
+ expect(await Organizations.get(db, org.id)).toBeDefined()
604
+ })
605
+
606
+ test('rolls back organization deletion when its KV fence cannot be written', async () => {
572
607
  const db = TestApp.database()
573
608
  const org = await Organizations.create(db, { name: 'Legacy owner' })
574
609
  const legacy = {
@@ -597,11 +632,80 @@ describe('DELETE /orgs/:orgId', () => {
597
632
  ...as(secret),
598
633
  method: 'DELETE',
599
634
  })
600
- expect(deleted.status).toBe(200)
635
+ expect(deleted.status).toBe(502)
636
+ expect(await Organizations.get(db, legacy.id)).toBeDefined()
637
+
638
+ const retained = await app.request(`/v1/orgs/${legacy.id}`, as(legacy.token))
639
+ expect(retained.status).toBe(200)
640
+
641
+ failWrites = false
642
+ const retried = await app.request(`/v1/orgs/${legacy.id}`, {
643
+ ...as(secret),
644
+ method: 'DELETE',
645
+ })
646
+ expect(retried.status).toBe(200)
601
647
  expect(await Organizations.get(db, legacy.id)).toBeUndefined()
648
+ expect((await app.request(`/v1/orgs/${legacy.id}`, as(legacy.token))).status).toBe(401)
649
+ })
650
+
651
+ test('restores key access when deletion fails after publishing its KV fence', async () => {
652
+ const db = TestApp.database()
653
+ const org = await Organizations.create(db, { name: 'Retained owner' })
654
+ const legacy = {
655
+ id: org.id,
656
+ orgId: org.id,
657
+ scopes: ['management:read'],
658
+ token: 'secret_retained_owner',
659
+ } satisfies TestApp.kvStore.Key
660
+ const store = TestApp.kvStore({ keys: [legacy] })
661
+ const app = createApp(db, { kv: { store } })
662
+ await sql`
663
+ CREATE FUNCTION reject_owner_deletion() RETURNS trigger LANGUAGE plpgsql AS $$
664
+ BEGIN RAISE EXCEPTION 'deletion commit rejected'; END $$;
665
+ CREATE CONSTRAINT TRIGGER reject_owner_deletion AFTER DELETE ON organizations
666
+ DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION reject_owner_deletion();
667
+ `.execute(db.kysely)
668
+
669
+ const deleted = await app.request(`/v1/orgs/${org.id}`, { ...as(secret), method: 'DELETE' })
602
670
 
603
- const rejected = await app.request(`/v1/orgs/${legacy.id}`, as(legacy.token))
604
- expect(rejected.status).toBe(401)
671
+ expect(deleted.status).toBe(502)
672
+ expect(await Organizations.get(db, org.id)).toBeDefined()
673
+ expect(await ApiKeys.isOwnerDeleted(store, { orgId: org.id })).toBe(false)
674
+ expect((await app.request(`/v1/orgs/${org.id}`, as(legacy.token))).status).toBe(200)
675
+ await expect(
676
+ ApiKeys.mint(store, { orgId: org.id, scopes: ['data:read'] }),
677
+ ).resolves.toBeDefined()
678
+
679
+ await sql`DROP TRIGGER reject_owner_deletion ON organizations`.execute(db.kysely)
680
+ const retried = await app.request(`/v1/orgs/${org.id}`, { ...as(secret), method: 'DELETE' })
681
+ expect(retried.status).toBe(200)
682
+ expect(await ApiKeys.isOwnerDeleted(store, { orgId: org.id })).toBe(true)
683
+ })
684
+
685
+ test('rejects a cached key after deletion even when KV record cleanup fails', async () => {
686
+ const db = TestApp.database()
687
+ const org = await Organizations.create(db, { name: 'Retained KV record' })
688
+ const backing = Store.memory()
689
+ const { token } = await ApiKeys.mint(backing, {
690
+ orgId: org.id,
691
+ scopes: ['data:read'],
692
+ })
693
+ const store = Store.from({
694
+ ...backing,
695
+ async delete() {
696
+ throw new Error('KV cleanup unavailable')
697
+ },
698
+ })
699
+ const app = createApp(db, { kv: { store } })
700
+ expect((await app.request('/v1/tokens/not-an-address', as(token))).status).toBe(400)
701
+
702
+ const deleted = await app.request(`/v1/orgs/${org.id}`, {
703
+ ...as(secret),
704
+ method: 'DELETE',
705
+ })
706
+ expect(deleted.status).toBe(200)
707
+ expect(await Organizations.get(db, org.id)).toBeUndefined()
708
+ expect((await app.request('/v1/tokens/not-an-address', as(token))).status).toBe(401)
605
709
  })
606
710
 
607
711
  test('deletes an owned organization and cascades its projects', async () => {
@@ -389,17 +389,22 @@ export function orgs() {
389
389
  return subsidizedDepositAddressesActive(c)
390
390
  if (await RoutesDepositAddresses.hasSubsidizedRelayAddress(db, Auth.org(c).id))
391
391
  return subsidizedDepositAddressesActive(c)
392
+ const kv = c.get('kv')
392
393
  const deleted = await Organizations.deleteOrganization(db, Auth.org(c).id, {
394
+ beforeCommit: kv
395
+ ? () => ApiKeys.markOwnerDeleting(kv.store, { orgId: Auth.org(c).id })
396
+ : undefined,
393
397
  onDepositAddressesDeactivated(transitions) {
394
398
  for (const transition of transitions)
395
399
  RoutesObservability.recordDepositAddress(c.get('metrics'), transition)
396
400
  },
401
+ }).catch(async (cause) => {
402
+ if (kv) await ApiKeys.reconcileOwnerDeletion(db, kv.store, { orgId: Auth.org(c).id })
403
+ throw cause
397
404
  })
398
405
  if (!deleted) return organizationNotFound(c)
399
- const kv = c.get('kv')
400
406
  if (kv)
401
407
  try {
402
- await ApiKeys.markOwnerDeleting(kv.store, { orgId: Auth.org(c).id })
403
408
  for (const record of await ApiKeys.listByOrg(kv.store, Auth.org(c).id, {
404
409
  scopeCatalog: c.get('scopeCatalog'),
405
410
  }))
@@ -273,8 +273,8 @@ describe('GET /orgs/:orgId/usage/requests', () => {
273
273
 
274
274
  expect(response.status).toBe(200)
275
275
  expect(await TestApp.json(response, Usage.schema.getRequestUsage.Response)).toEqual(emptyUsage)
276
- // Series, totals, byKey, byRoute, and byStatus each issue one query.
277
- expect(query).toHaveBeenCalledTimes(5)
276
+ // All usage breakdowns share one query.
277
+ expect(query).toHaveBeenCalledTimes(1)
278
278
  const sql = query.mock.calls[0]![0]
279
279
  expect(sql).toContain(`org_id = '${org.id}'`)
280
280
  expect(sql).toContain(`project_id = '${project.id}'`)
@@ -43,8 +43,19 @@ describe('chainId', () => {
43
43
  })
44
44
 
45
45
  describe('requiresFeePayer', () => {
46
- test('requires both a fee-payer method detail and an enabled request', () => {
47
- expect(Policy.requiresFeePayer(input)).toBe(true)
46
+ test.each([
47
+ ['canonical', { methodDetails: { feePayer: true } }],
48
+ ['pre-normalized', { feePayer: true }],
49
+ ])('recognizes %s sponsorship', (_, request) => {
50
+ expect(
51
+ Policy.requiresFeePayer({
52
+ ...input,
53
+ challenge: { ...input.challenge, request },
54
+ }),
55
+ ).toBe(true)
56
+ })
57
+
58
+ test('lets an explicit top-level value disable sponsorship', () => {
48
59
  expect(
49
60
  Policy.requiresFeePayer({
50
61
  ...input,
@@ -84,6 +95,42 @@ describe('assertChainAccess', () => {
84
95
  })
85
96
 
86
97
  describe('authorizeFeePayer', () => {
98
+ test('rejects pre-normalized sandbox sponsorship on mainnet', async () => {
99
+ await expect(
100
+ Policy.authorizeFeePayer({
101
+ chainId: 4217,
102
+ db: TestApp.database(),
103
+ feePayer,
104
+ input: {
105
+ ...input,
106
+ challenge: { ...input.challenge, request: { feePayer: true } },
107
+ },
108
+ principal: { ...principal, environment: 'sandbox' },
109
+ zones,
110
+ }),
111
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
112
+ `[Mpp.Policy.PolicyDeniedError: Mainnet fee sponsorship requires a production API key.]`,
113
+ )
114
+ })
115
+
116
+ test('requires active billing for pre-normalized mainnet sponsorship', async () => {
117
+ await expect(
118
+ Policy.authorizeFeePayer({
119
+ chainId: 4217,
120
+ db: TestApp.database(),
121
+ feePayer,
122
+ input: {
123
+ ...input,
124
+ challenge: { ...input.challenge, request: { feePayer: true } },
125
+ },
126
+ principal: principal_projectless,
127
+ zones,
128
+ }),
129
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
130
+ `[Mpp.Policy.PolicyDeniedError: Active billing is required for mainnet fee sponsorship.]`,
131
+ )
132
+ })
133
+
87
134
  test.each([4217, Zones.zoneMainnetInternal.id, Zones.zoneDeel.id])(
88
135
  'rejects sandbox sponsorship on chain %s',
89
136
  async (chainId) => {
@@ -165,7 +212,7 @@ describe('authorizeFeePayer', () => {
165
212
  },
166
213
  )
167
214
 
168
- test('does not require billing when the credential pays its own fee', async () => {
215
+ test('withholds the managed fee payer from self-funded credentials', async () => {
169
216
  await expect(
170
217
  Policy.authorizeFeePayer({
171
218
  chainId: 4217,
@@ -178,6 +225,6 @@ describe('authorizeFeePayer', () => {
178
225
  principal,
179
226
  zones,
180
227
  }),
181
- ).resolves.toBe(feePayer)
228
+ ).resolves.toBeUndefined()
182
229
  })
183
230
  })
@@ -18,7 +18,11 @@ export function chainId(input: Mpp.RelayInput): number | undefined {
18
18
  /** Whether a Tempo charge credential requests platform fee sponsorship. */
19
19
  export function requiresFeePayer(input: Mpp.RelayInput) {
20
20
  const request = input.challenge.request
21
- return record(request['methodDetails'])?.['feePayer'] === true && request['feePayer'] !== false
21
+ const details = record(request['methodDetails'])
22
+ return (
23
+ (details?.['feePayer'] === true || request['feePayer'] === true) &&
24
+ request['feePayer'] !== false
25
+ )
22
26
  }
23
27
 
24
28
  /** Refuses a sponsored transaction that the current fee market cannot admit. */
@@ -80,7 +84,7 @@ export async function authorizeFeePayer(
80
84
  options: authorizeFeePayer.Options,
81
85
  ): Promise<LocalAccount | undefined> {
82
86
  const { chainId, db, feePayer, input, principal, zones } = options
83
- if (!feePayer || !requiresFeePayer(input)) return feePayer
87
+ if (!feePayer || !requiresFeePayer(input)) return undefined
84
88
  if (principal?.type !== 'api_key')
85
89
  throw new PolicyDeniedError('Fee sponsorship requires an API key.')
86
90
  if (!Viem.isMainnet(zones.get(chainId)?.sourceId ?? chainId)) return feePayer
@@ -3,6 +3,7 @@ import { SignatureEnvelope, TxEnvelopeTempo } from 'ox/tempo'
3
3
 
4
4
  import * as TestApp from '../../../../test/App.js'
5
5
  import * as Tempo from '../../../../test/Tempo.js'
6
+ import * as ApiKeyOwnerTombstones from '../../../db/tables/apiKeyOwnerTombstones.js'
6
7
  import * as BillingSettings from '../../../db/tables/billingSettings.js'
7
8
  import * as SponsoredTransactions from '../../../db/tables/sponsoredTransactions.js'
8
9
  import type * as Auth from '../../../internal/Auth.js'
@@ -35,6 +36,34 @@ const token = {
35
36
  }
36
37
 
37
38
  describe('record', () => {
39
+ test.each([undefined, '1.00'])(
40
+ 'rejects a deleted owner with spend limit %s',
41
+ async (spendLimit) => {
42
+ const db = TestApp.database()
43
+ const chainId = Zones.zoneDeel.id
44
+ await VerifiedTokens.replace(db, chainId, [token])
45
+ if (spendLimit !== undefined)
46
+ await BillingSettings.upsert(db, { orgId: principal.orgId, spendLimit })
47
+ await db.transaction((tx) =>
48
+ ApiKeyOwnerTombstones.markDeleted(tx, { orgId: principal.orgId }),
49
+ )
50
+
51
+ await expect(
52
+ Sponsorship.record({
53
+ db,
54
+ dbCached: db,
55
+ principal,
56
+ serializedTransaction: await transaction({ chainId }),
57
+ txFeeLimit: 1_000_000n,
58
+ zones,
59
+ }),
60
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
61
+ `[Mpp.Policy.PolicyDeniedError: Organization no longer exists.]`,
62
+ )
63
+ expect(await SponsoredTransactions.listPending(db)).toMatchInlineSnapshot(`[]`)
64
+ },
65
+ )
66
+
38
67
  test.each(mainnetChainIds)(
39
68
  'records chain %s as billable and eligible for metering',
40
69
  async (chainId) => {
@@ -114,17 +114,19 @@ export async function record(options: record.Options): Promise<void> {
114
114
  transaction: serializedTransaction,
115
115
  transactionHash: Hash.keccak256(serializedTransaction),
116
116
  }
117
- if (settings?.spendLimit == null) {
118
- await SponsoredTransactions.upsert(db, input)
119
- return
120
- }
121
117
  try {
118
+ if (settings?.spendLimit == null) {
119
+ await SponsoredTransactions.upsert(db, input)
120
+ return
121
+ }
122
122
  await SponsoredTransactions.reserve(db, input, {
123
123
  chainIds: Zones.chainIds({ sourceId: Viem.chainId.mainnet, zones: zones.values() }),
124
124
  max: Billing.toBaseUnits(settings.spendLimit),
125
125
  since: Billing.periodStart(settings.period),
126
126
  })
127
127
  } catch (cause) {
128
+ if (cause instanceof SponsoredTransactions.OrganizationDeletedError)
129
+ throw new Policy.PolicyDeniedError('Organization no longer exists.')
128
130
  if (cause instanceof SponsoredTransactions.PeriodSpendLimitError)
129
131
  throw new Policy.PolicyDeniedError('Spend limit exceeded.')
130
132
  throw cause
@@ -5,7 +5,7 @@ import { Hash, Hex, Secp256k1 } from 'ox'
5
5
  import { ZoneRpcAuthentication } from 'ox/tempo'
6
6
  import { createClient, http } from 'viem'
7
7
  import { prepareTransactionRequest, sendRawTransactionSync, signTransaction } from 'viem/actions'
8
- import { Account as TempoAccount, Actions, Transaction, withRelay } from 'viem/tempo'
8
+ import { Account as TempoAccount, Actions, Addresses, Transaction, withRelay } from 'viem/tempo'
9
9
 
10
10
  import * as TestApp from '../../../test/App.js'
11
11
  import * as Containers from '../../../test/containers.js'
@@ -25,6 +25,7 @@ import * as SponsoredTransactions from '../../db/tables/sponsoredTransactions.js
25
25
  import * as StripeCustomers from '../../db/tables/stripeCustomers.js'
26
26
  import * as core_Billing from '../management/Billing.js'
27
27
  import * as RequestListener from '../../handlers/internal/requestListener.js'
28
+ import * as Store from '../../internal/Store.js'
28
29
  import * as Tidx from '../../internal/Tidx.js'
29
30
  import * as Viem from '../../internal/Viem.js'
30
31
  import * as Sponsorships from './Sponsorships.js'
@@ -125,6 +126,36 @@ const keys = [
125
126
  },
126
127
  ] as const satisfies readonly TestApp.kvStore.Key[]
127
128
 
129
+ describe('behavior: multisig coordination', () => {
130
+ test('uses configured state and reports coordinator failures', async () => {
131
+ const entries: Log.Entry[] = []
132
+ const store = Store.memory()
133
+ const app = TestApp.create({
134
+ auth: { keys },
135
+ logger: (entry) => void entries.push(entry),
136
+ relay: { multisig: { store } },
137
+ })
138
+ const hash = Hex.random(32)
139
+ const request = async () => {
140
+ const response = await app.request('/rpc/relay', {
141
+ body: JSON.stringify({
142
+ id: 1,
143
+ jsonrpc: '2.0',
144
+ method: 'multisig_getOperation',
145
+ params: [hash],
146
+ }),
147
+ headers: { 'content-type': 'application/json', 'tempo-api-key': 'secret_unscoped' },
148
+ method: 'POST',
149
+ })
150
+ return response.json()
151
+ }
152
+ expect(await request()).toMatchObject({ result: null })
153
+ await store.put(`multisig:v2:multisig:operation:${hash}`, 'invalid')
154
+ expect(await request()).toMatchObject({ error: { code: -32603 } })
155
+ expect(entries.at(-1)?.rpc).toMatchObject({ serverErrors: 1 })
156
+ })
157
+ })
158
+
128
159
  describe('behavior: Zone chain routing', () => {
129
160
  const zoneSelectors = [
130
161
  ['relay', 'path'],
@@ -712,6 +743,8 @@ describe.skipIf(runtime.mode !== 'localnet')('behavior: sponsorship', () => {
712
743
  "finalizationAttemptedAt": null,
713
744
  "finalizedAt": null,
714
745
  "id": "<id>",
746
+ "meterEventFirstAttemptedAt": null,
747
+ "meterReportAttemptedAt": null,
715
748
  "meterReportedAt": null,
716
749
  "orgId": "org_1",
717
750
  "projectId": "prj_1",
@@ -720,6 +753,7 @@ describe.skipIf(runtime.mode !== 'localnet')('behavior: sponsorship', () => {
720
753
  "status": "pending",
721
754
  "transaction": "<hex>",
722
755
  "transactionHash": "<hash>",
756
+ "transactionHashReconciled": false,
723
757
  }
724
758
  `)
725
759
  })
@@ -1239,6 +1273,56 @@ describe('behavior: mainnet billing gate', () => {
1239
1273
  await TestApp.verifiedSeed(db, Viem.chainId.mainnet)
1240
1274
  }
1241
1275
 
1276
+ test('behavior: uses the same sponsor fee token for each authenticated organization', async () => {
1277
+ const db = TestApp.database()
1278
+ const ousd = '0x20c0000000000000000000006a37DA5C996874BE'
1279
+ await activate(db, 'org_1')
1280
+ await activate(db, 'org_2')
1281
+ await TestApp.verifiedSeed(db, Viem.chainId.mainnet, {
1282
+ tokens: [Addresses.pathUsd, ousd].map((address) => ({
1283
+ address,
1284
+ currency: 'USD',
1285
+ decimals: 6,
1286
+ name: address === ousd ? 'OUSD' : 'pathUSD',
1287
+ symbol: address === ousd ? 'OUSD' : 'pathUSD',
1288
+ })),
1289
+ })
1290
+ const app = TestApp.create({
1291
+ auth: { keys },
1292
+ db,
1293
+ relay: {
1294
+ feePayer: {
1295
+ account: feePayerAccount,
1296
+ resolveFeeToken: ({ chainId }) => {
1297
+ expect(chainId).toBe(Viem.chainId.mainnet)
1298
+ return ousd
1299
+ },
1300
+ },
1301
+ },
1302
+ supportedChainIds: [Viem.chainId.mainnet],
1303
+ })
1304
+
1305
+ for (const [nonce, { orgId, token }] of [
1306
+ { orgId: 'org_1', token: 'secret_sponsor_prod' },
1307
+ { orgId: 'org_2', token: 'secret_wildcard_prod' },
1308
+ { orgId: 'org_1', token: 'secret_sponsor_prod' },
1309
+ ].entries()) {
1310
+ const body = await relayRequest(app, {
1311
+ method: 'eth_signRawTransaction',
1312
+ params: [await signSponsorable({ chainId: Viem.chainId.mainnet, nonce })],
1313
+ token,
1314
+ })
1315
+ expect(body.error).toBeUndefined()
1316
+ const signed = Transaction.deserialize(body.result as `0x76${string}`)
1317
+ expect(signed.feeToken?.toString().toLowerCase()).toBe(ousd.toLowerCase())
1318
+ const row = (await SponsoredTransactions.listPending(db)).find(
1319
+ (row) => row.transactionHash === Hash.keccak256(body.result!),
1320
+ )
1321
+ expect(row?.orgId).toBe(orgId)
1322
+ expect(row?.feeToken?.toLowerCase()).toBe(ousd.toLowerCase())
1323
+ }
1324
+ })
1325
+
1242
1326
  /** Configures one attributed project for Tempo-funded sponsorship. */
1243
1327
  async function configureSubsidy(db: ReturnType<typeof TestApp.database>) {
1244
1328
  await Organizations.create(db, { id: 'org_1', name: 'Privy' })
@@ -2,6 +2,7 @@ import { Hono } from 'hono'
2
2
  import { createMiddleware } from 'hono/factory'
3
3
  import { Hash, Hex, RpcResponse } from 'ox'
4
4
  import { ZoneRpcAuthentication } from 'ox/tempo'
5
+ import type { Address } from 'viem'
5
6
  import { Addresses, TokenId, Transaction } from 'viem/tempo'
6
7
 
7
8
  import type * as App from '../../App.js'
@@ -75,10 +76,19 @@ export declare namespace relay {
75
76
  NonNullable<Handler.relay.Options['feePayer']>,
76
77
  'account' | 'feeToken' | 'name' | 'url'
77
78
  > & {
79
+ /** Resolves the sponsor's fee token using the transaction chain. */
80
+ resolveFeeToken?:
81
+ | ((options: {
82
+ /** Transaction chain id. */
83
+ chainId: number
84
+ }) => Address | undefined)
85
+ | undefined
78
86
  /** Per-transaction fee cap (decimal USD string); orgs tighten it, never loosen. @default '1.00' */
79
87
  txFeeLimit?: string | undefined
80
88
  })
81
89
  | undefined
90
+ /** Native multisig coordination backed by authoritative atomic storage. */
91
+ multisig?: Handler.relay.Options['multisig'] | undefined
82
92
  }
83
93
  }
84
94
 
@@ -151,11 +161,18 @@ function middleware(options: middleware.Options) {
151
161
  principal?.type === 'api_key' &&
152
162
  (principal.apiKey.scopes.includes('rpc-relay:sponsor') ||
153
163
  principal.apiKey.scopes.includes(Scope.wildcard))
154
- // Lifted so validation and the sponsored-token default read one value.
155
- const feeToken_sponsor = options.feePayer.feeToken ?? Addresses.pathUsd
164
+ // Resolve against the transaction chain because one app serves mainnet,
165
+ // testnet, and hosted Zones concurrently.
166
+ const feeToken_sponsor = (chainId: number) => {
167
+ return (
168
+ options.feePayer?.resolveFeeToken?.({ chainId }) ??
169
+ options.feePayer?.feeToken ??
170
+ Addresses.pathUsd
171
+ )
172
+ }
156
173
  return {
157
174
  ...options.feePayer,
158
- feeToken: feeToken_sponsor,
175
+ resolveFeeToken: feeToken_sponsor,
159
176
  validate: async (transaction) => {
160
177
  // Allowlist the chains this deployment serves rather than denylisting
161
178
  // only mainnet: the relay resolves chainId from the request body, so
@@ -230,7 +247,7 @@ function middleware(options: middleware.Options) {
230
247
  }
231
248
  const feeToken = (() => {
232
249
  try {
233
- return TokenId.toAddress(transaction.feeToken ?? feeToken_sponsor)
250
+ return TokenId.toAddress(transaction.feeToken ?? feeToken_sponsor(id))
234
251
  } catch {
235
252
  return undefined
236
253
  }
@@ -388,6 +405,12 @@ function middleware(options: middleware.Options) {
388
405
  : await SponsoredTransactions.reserve(db, input, billingLimit)
389
406
  return { subsidized: !record.billable }
390
407
  } catch (error) {
408
+ if (error instanceof SponsoredTransactions.OrganizationDeletedError)
409
+ rejectSponsorship({
410
+ chainId: event.chainId,
411
+ message: 'Organization no longer exists.',
412
+ reason: 'billing_required',
413
+ })
391
414
  if (error instanceof SponsoredTransactions.AttributionConflictError)
392
415
  rejectSponsorship({
393
416
  chainId: event.chainId,
@@ -466,6 +489,7 @@ function middleware(options: middleware.Options) {
466
489
  cache: c.get('store'),
467
490
  ...(options.features ? { features: options.features } : {}),
468
491
  getClient,
492
+ ...(options.multisig ? { multisig: options.multisig } : {}),
469
493
  onRequest: async (request) => {
470
494
  const method = sponsorshipMethod(request.method)
471
495
  const params = 'params' in request && Array.isArray(request.params) ? request.params : []
@@ -339,6 +339,29 @@ describe('reconcile', () => {
339
339
  await db.close()
340
340
  })
341
341
 
342
+ test('behavior: replaces an unresolved recorded hash by sign payload', async () => {
343
+ const db = create()
344
+ await db.migrate()
345
+ const sponsorship = await SponsoredTransactions.upsert(db, {
346
+ ...input,
347
+ signPayload,
348
+ transactionHash: `0x${'cc'.repeat(32)}`,
349
+ })
350
+
351
+ const result = await Sponsorships.reconcile(db, {
352
+ feePayer: '0xFee0000000000000000000000000000000000000',
353
+ getClient: () => rpc,
354
+ getTidx: () => tidx([{ from: sender, hash: minedHash }]),
355
+ })
356
+
357
+ expect(result).toMatchObject({ matched: 1 })
358
+ expect(await SponsoredTransactions.get(db, sponsorship.id)).toMatchObject({
359
+ status: 'pending',
360
+ transactionHash: minedHash,
361
+ })
362
+ await db.close()
363
+ })
364
+
342
365
  test('behavior: recovers recently failed intents by sign payload', async () => {
343
366
  const db = create()
344
367
  await db.migrate()
@@ -373,6 +396,44 @@ describe('reconcile', () => {
373
396
  await db.close()
374
397
  })
375
398
 
399
+ test('behavior: recovers a failed recorded hash by sign payload without duplicating spend', async () => {
400
+ const db = create()
401
+ await db.migrate()
402
+ await Organizations.create(db, { id: 'org_1', name: 'One' })
403
+ const recordedHash = `0x${'cc'.repeat(32)}`
404
+ const sponsorship = await SponsoredTransactions.upsert(db, {
405
+ ...input,
406
+ signPayload,
407
+ transactionHash: recordedHash,
408
+ })
409
+ await SponsoredTransactions.fail(db, sponsorship.id, '2026-01-01T00:00:00.000Z')
410
+
411
+ vi.useFakeTimers({ now: new Date('2026-01-01T00:01:00.000Z') })
412
+ try {
413
+ const options = {
414
+ feePayer: '0xFee0000000000000000000000000000000000000' as const,
415
+ getClient: () => rpc,
416
+ getTidx: () => tidx([{ block_num: 1, from: sender, hash: minedHash, idx: 0 }]),
417
+ }
418
+ expect(await Sponsorships.reconcile(db, options)).toMatchObject({ matched: 1 })
419
+ expect(
420
+ await Sponsorships.finalize(db, {
421
+ getClient: () => client({ [minedHash]: { effectiveGasPrice: '0x3', gasUsed: '0x5208' } }),
422
+ }),
423
+ ).toMatchObject({ finalized: 1 })
424
+ expect(await Sponsorships.reconcile(db, options)).toMatchObject({ matched: 0 })
425
+ } finally {
426
+ vi.useRealTimers()
427
+ }
428
+
429
+ expect(await SponsoredTransactions.get(db, sponsorship.id)).toMatchObject({
430
+ status: 'finalized',
431
+ transactionHash: minedHash,
432
+ })
433
+ expect(await SponsoredTransactions.list(db, { limit: 10 })).toHaveLength(1)
434
+ await db.close()
435
+ })
436
+
376
437
  test('behavior: spend-limit refusals are not operational errors', async () => {
377
438
  const db = create()
378
439
  await db.migrate()
@@ -460,6 +521,41 @@ describe('reconcile', () => {
460
521
  await db.close()
461
522
  })
462
523
 
524
+ test('behavior: scans fill intents and submitted hashes from independent windows', async () => {
525
+ const db = create()
526
+ await db.migrate()
527
+ vi.useFakeTimers({ now: new Date('2026-01-01T00:00:00.000Z') })
528
+ try {
529
+ await SponsoredTransactions.upsert(db, {
530
+ ...input,
531
+ signPayload: `0x${'ee'.repeat(32)}`,
532
+ })
533
+ vi.setSystemTime(new Date('2026-01-01T01:00:00.000Z'))
534
+ const { transactionHash: _, ...intent } = input
535
+ await SponsoredTransactions.upsert(db, { ...intent, signPayload })
536
+ const queries: string[] = []
537
+
538
+ await Sponsorships.reconcile(db, {
539
+ feePayer: '0xFee0000000000000000000000000000000000000',
540
+ getClient: () => rpc,
541
+ getTidx: () =>
542
+ ({
543
+ fetch: async (options: { query: string }) => {
544
+ queries.push(options.query)
545
+ return { rows: [] }
546
+ },
547
+ }) as never,
548
+ })
549
+
550
+ expect(queries).toHaveLength(2)
551
+ expect(queries[0]).toContain("block_timestamp >= '2026-01-01 00:58:00'")
552
+ expect(queries[1]).toContain("block_timestamp >= '2025-12-31 23:58:00'")
553
+ } finally {
554
+ vi.useRealTimers()
555
+ await db.close()
556
+ }
557
+ })
558
+
463
559
  test('behavior: an indexer error leaves intents for the next pass', async () => {
464
560
  const db = create()
465
561
  await db.migrate()
@@ -483,7 +579,7 @@ describe('reconcile', () => {
483
579
  "scanned": 0,
484
580
  }
485
581
  `)
486
- expect(await SponsoredTransactions.listIntents(db)).toHaveLength(1)
582
+ expect(await SponsoredTransactions.listReconciliationCandidates(db)).toHaveLength(1)
487
583
  await db.close()
488
584
  })
489
585
  })