tapimo 0.0.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. package/README.md +38 -16
  2. package/dist/ApiKey.d.ts +14 -11
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +11 -12
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +207 -0
  7. package/dist/ApiKeys.d.ts.map +1 -0
  8. package/dist/ApiKeys.js +282 -0
  9. package/dist/ApiKeys.js.map +1 -0
  10. package/dist/App.d.ts +6771 -3819
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +145 -317
  13. package/dist/App.js.map +1 -1
  14. package/dist/Handler.d.ts +86 -0
  15. package/dist/Handler.d.ts.map +1 -0
  16. package/dist/Handler.js +83 -0
  17. package/dist/Handler.js.map +1 -0
  18. package/dist/Scope.d.ts +14 -4
  19. package/dist/Scope.d.ts.map +1 -1
  20. package/dist/Scope.js +16 -4
  21. package/dist/Scope.js.map +1 -1
  22. package/dist/Webhooks.d.ts +5 -7
  23. package/dist/Webhooks.d.ts.map +1 -1
  24. package/dist/Webhooks.js +11 -4
  25. package/dist/Webhooks.js.map +1 -1
  26. package/dist/admin/Access.d.ts +1 -3
  27. package/dist/admin/Access.d.ts.map +1 -1
  28. package/dist/admin/Access.js +1 -3
  29. package/dist/admin/Access.js.map +1 -1
  30. package/dist/admin/App.d.ts +167 -205
  31. package/dist/admin/App.d.ts.map +1 -1
  32. package/dist/admin/App.js +2 -4
  33. package/dist/admin/App.js.map +1 -1
  34. package/dist/admin/apps/api-keys.d.ts +105 -5
  35. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  36. package/dist/admin/apps/api-keys.js +75 -9
  37. package/dist/admin/apps/api-keys.js.map +1 -1
  38. package/dist/admin/apps/scopes.d.ts +6 -0
  39. package/dist/admin/apps/scopes.d.ts.map +1 -1
  40. package/dist/admin/apps/verified-tokens.d.ts +35 -149
  41. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  42. package/dist/admin/apps/verified-tokens.js +18 -39
  43. package/dist/admin/apps/verified-tokens.js.map +1 -1
  44. package/dist/admin/ui.generated.d.ts +1 -1
  45. package/dist/admin/ui.generated.js +1 -1
  46. package/dist/apps/data/App.d.ts +19176 -0
  47. package/dist/apps/data/App.d.ts.map +1 -0
  48. package/dist/apps/data/App.js +236 -0
  49. package/dist/apps/data/App.js.map +1 -0
  50. package/dist/apps/data/index.d.ts +3 -0
  51. package/dist/apps/data/index.d.ts.map +1 -0
  52. package/dist/apps/data/index.js +3 -0
  53. package/dist/apps/data/index.js.map +1 -0
  54. package/dist/apps/{activities.d.ts → data/routes/activities.d.ts} +32 -32
  55. package/dist/apps/{activities.d.ts.map → data/routes/activities.d.ts.map} +1 -1
  56. package/dist/apps/{activities.js → data/routes/activities.js} +13 -13
  57. package/dist/apps/data/routes/activities.js.map +1 -0
  58. package/dist/apps/{addresses.d.ts → data/routes/addresses.d.ts} +22 -22
  59. package/dist/apps/{addresses.d.ts.map → data/routes/addresses.d.ts.map} +1 -1
  60. package/dist/apps/{addresses.js → data/routes/addresses.js} +5 -5
  61. package/dist/apps/data/routes/addresses.js.map +1 -0
  62. package/dist/apps/{balances.d.ts → data/routes/balances.d.ts} +49 -49
  63. package/dist/apps/data/routes/balances.d.ts.map +1 -0
  64. package/dist/apps/{balances.js → data/routes/balances.js} +42 -11
  65. package/dist/apps/data/routes/balances.js.map +1 -0
  66. package/dist/apps/{blocks.d.ts → data/routes/blocks.d.ts} +47 -47
  67. package/dist/apps/data/routes/blocks.d.ts.map +1 -0
  68. package/dist/apps/{blocks.js → data/routes/blocks.js} +13 -13
  69. package/dist/apps/data/routes/blocks.js.map +1 -0
  70. package/dist/apps/{coingecko.d.ts → data/routes/coingecko.d.ts} +183 -183
  71. package/dist/apps/data/routes/coingecko.d.ts.map +1 -0
  72. package/dist/apps/{coingecko.js → data/routes/coingecko.js} +13 -13
  73. package/dist/apps/data/routes/coingecko.js.map +1 -0
  74. package/dist/apps/{exchanges.d.ts → data/routes/exchanges.d.ts} +460 -460
  75. package/dist/apps/data/routes/exchanges.d.ts.map +1 -0
  76. package/dist/apps/{exchanges.js → data/routes/exchanges.js} +19 -19
  77. package/dist/apps/data/routes/exchanges.js.map +1 -0
  78. package/dist/apps/{fee-amm.d.ts → data/routes/fee-amm.d.ts} +94 -94
  79. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -0
  80. package/dist/apps/{fee-amm.js → data/routes/fee-amm.js} +17 -17
  81. package/dist/apps/data/routes/fee-amm.js.map +1 -0
  82. package/dist/apps/{indexer.d.ts → data/routes/indexer.d.ts} +4 -4
  83. package/dist/apps/data/routes/indexer.d.ts.map +1 -0
  84. package/dist/apps/{indexer.js → data/routes/indexer.js} +13 -9
  85. package/dist/apps/data/routes/indexer.js.map +1 -0
  86. package/dist/apps/{receipts.d.ts → data/routes/receipts.d.ts} +6 -6
  87. package/dist/apps/data/routes/receipts.d.ts.map +1 -0
  88. package/dist/apps/{receipts.js → data/routes/receipts.js} +12 -12
  89. package/dist/apps/data/routes/receipts.js.map +1 -0
  90. package/dist/apps/{rpc.d.ts → data/routes/rpc.d.ts} +4 -4
  91. package/dist/apps/data/routes/rpc.d.ts.map +1 -0
  92. package/dist/apps/{rpc.js → data/routes/rpc.js} +6 -6
  93. package/dist/apps/data/routes/rpc.js.map +1 -0
  94. package/dist/apps/{tokenlist.d.ts → data/routes/tokenlist.d.ts} +4 -4
  95. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -0
  96. package/dist/apps/{tokenlist.js → data/routes/tokenlist.js} +8 -8
  97. package/dist/apps/data/routes/tokenlist.js.map +1 -0
  98. package/dist/apps/{tokens.d.ts → data/routes/tokens.d.ts} +11 -11
  99. package/dist/apps/data/routes/tokens.d.ts.map +1 -0
  100. package/dist/apps/{tokens.js → data/routes/tokens.js} +19 -19
  101. package/dist/apps/data/routes/tokens.js.map +1 -0
  102. package/dist/apps/{transactions.d.ts → data/routes/transactions.d.ts} +288 -288
  103. package/dist/apps/data/routes/transactions.d.ts.map +1 -0
  104. package/dist/apps/{transactions.js → data/routes/transactions.js} +13 -13
  105. package/dist/apps/data/routes/transactions.js.map +1 -0
  106. package/dist/apps/{transfers.d.ts → data/routes/transfers.d.ts} +35 -35
  107. package/dist/apps/data/routes/transfers.d.ts.map +1 -0
  108. package/dist/apps/{transfers.js → data/routes/transfers.js} +13 -13
  109. package/dist/apps/data/routes/transfers.js.map +1 -0
  110. package/dist/apps/{verified-tokens.d.ts → data/routes/verified-tokens.d.ts} +42 -42
  111. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -0
  112. package/dist/apps/{verified-tokens.js → data/routes/verified-tokens.js} +9 -9
  113. package/dist/apps/data/routes/verified-tokens.js.map +1 -0
  114. package/dist/apps/{webhooks.d.ts → data/routes/webhooks.d.ts} +66 -63
  115. package/dist/apps/{webhooks.d.ts.map → data/routes/webhooks.d.ts.map} +1 -1
  116. package/dist/apps/{webhooks.js → data/routes/webhooks.js} +67 -59
  117. package/dist/apps/data/routes/webhooks.js.map +1 -0
  118. package/dist/apps/docs/App.d.ts +27 -0
  119. package/dist/apps/docs/App.d.ts.map +1 -0
  120. package/dist/apps/docs/App.js +122 -0
  121. package/dist/apps/docs/App.js.map +1 -0
  122. package/dist/{internal/OpenApi.fonts.d.ts → apps/docs/fonts.d.ts} +1 -1
  123. package/dist/apps/docs/fonts.d.ts.map +1 -0
  124. package/dist/{internal/OpenApi.fonts.js → apps/docs/fonts.js} +1 -1
  125. package/dist/apps/docs/fonts.js.map +1 -0
  126. package/dist/apps/docs/index.d.ts +2 -0
  127. package/dist/apps/docs/index.d.ts.map +1 -0
  128. package/dist/apps/docs/index.js +2 -0
  129. package/dist/apps/docs/index.js.map +1 -0
  130. package/dist/{internal/OpenApi.logo.d.ts → apps/docs/logo.d.ts} +1 -1
  131. package/dist/apps/docs/logo.d.ts.map +1 -0
  132. package/dist/{internal/OpenApi.logo.js → apps/docs/logo.js} +1 -1
  133. package/dist/apps/docs/logo.js.map +1 -0
  134. package/dist/apps/index.d.ts +4 -0
  135. package/dist/apps/index.d.ts.map +1 -0
  136. package/dist/apps/index.js +4 -0
  137. package/dist/apps/index.js.map +1 -0
  138. package/dist/apps/metadata.d.ts +7 -0
  139. package/dist/apps/metadata.d.ts.map +1 -0
  140. package/dist/apps/metadata.js +15 -0
  141. package/dist/apps/metadata.js.map +1 -0
  142. package/dist/apps/platform/App.d.ts +2985 -0
  143. package/dist/apps/platform/App.d.ts.map +1 -0
  144. package/dist/apps/platform/App.js +74 -0
  145. package/dist/apps/platform/App.js.map +1 -0
  146. package/dist/apps/platform/index.d.ts +2 -0
  147. package/dist/apps/platform/index.d.ts.map +1 -0
  148. package/dist/apps/platform/index.js +2 -0
  149. package/dist/apps/platform/index.js.map +1 -0
  150. package/dist/apps/platform/routes/api-keys.d.ts +681 -0
  151. package/dist/apps/platform/routes/api-keys.d.ts.map +1 -0
  152. package/dist/apps/platform/routes/api-keys.js +328 -0
  153. package/dist/apps/platform/routes/api-keys.js.map +1 -0
  154. package/dist/apps/platform/routes/invitations.d.ts +733 -0
  155. package/dist/apps/platform/routes/invitations.d.ts.map +1 -0
  156. package/dist/apps/platform/routes/invitations.js +413 -0
  157. package/dist/apps/platform/routes/invitations.js.map +1 -0
  158. package/dist/apps/platform/routes/me.d.ts +95 -0
  159. package/dist/apps/platform/routes/me.d.ts.map +1 -0
  160. package/dist/apps/platform/routes/me.js +81 -0
  161. package/dist/apps/platform/routes/me.js.map +1 -0
  162. package/dist/apps/platform/routes/members.d.ts +554 -0
  163. package/dist/apps/platform/routes/members.d.ts.map +1 -0
  164. package/dist/apps/platform/routes/members.js +251 -0
  165. package/dist/apps/platform/routes/members.js.map +1 -0
  166. package/dist/apps/platform/routes/orgs.d.ts +582 -0
  167. package/dist/apps/platform/routes/orgs.d.ts.map +1 -0
  168. package/dist/apps/platform/routes/orgs.js +265 -0
  169. package/dist/apps/platform/routes/orgs.js.map +1 -0
  170. package/dist/apps/platform/routes/projects.d.ts +740 -0
  171. package/dist/apps/platform/routes/projects.d.ts.map +1 -0
  172. package/dist/apps/platform/routes/projects.js +286 -0
  173. package/dist/apps/platform/routes/projects.js.map +1 -0
  174. package/dist/apps/relay/App.d.ts +41 -0
  175. package/dist/apps/relay/App.d.ts.map +1 -0
  176. package/dist/apps/relay/App.js +103 -0
  177. package/dist/apps/relay/App.js.map +1 -0
  178. package/dist/apps/relay/Sponsorships.d.ts +107 -0
  179. package/dist/apps/relay/Sponsorships.d.ts.map +1 -0
  180. package/dist/apps/relay/Sponsorships.js +193 -0
  181. package/dist/apps/relay/Sponsorships.js.map +1 -0
  182. package/dist/apps/relay/index.d.ts +3 -0
  183. package/dist/apps/relay/index.d.ts.map +1 -0
  184. package/dist/apps/relay/index.js +3 -0
  185. package/dist/apps/relay/index.js.map +1 -0
  186. package/dist/{Cli.d.ts → cli/Cli.d.ts} +13 -2
  187. package/dist/cli/Cli.d.ts.map +1 -0
  188. package/dist/cli/Cli.js +19 -0
  189. package/dist/cli/Cli.js.map +1 -0
  190. package/dist/cli/bin.d.ts +3 -0
  191. package/dist/cli/bin.d.ts.map +1 -0
  192. package/dist/cli/bin.js +4 -0
  193. package/dist/cli/bin.js.map +1 -0
  194. package/dist/cli/commands/admin.d.ts +15 -0
  195. package/dist/cli/commands/admin.d.ts.map +1 -0
  196. package/dist/cli/commands/admin.js +60 -0
  197. package/dist/cli/commands/admin.js.map +1 -0
  198. package/dist/cloudflare.d.ts +7 -0
  199. package/dist/cloudflare.d.ts.map +1 -1
  200. package/dist/cloudflare.js +9 -0
  201. package/dist/cloudflare.js.map +1 -1
  202. package/dist/db/Db.d.ts +113 -0
  203. package/dist/db/Db.d.ts.map +1 -0
  204. package/dist/db/Db.js +402 -0
  205. package/dist/db/Db.js.map +1 -0
  206. package/dist/db/Schema.d.ts +168 -0
  207. package/dist/db/Schema.d.ts.map +1 -0
  208. package/dist/db/Schema.js +229 -0
  209. package/dist/db/Schema.js.map +1 -0
  210. package/dist/db/tables/invitations.d.ts +84 -0
  211. package/dist/db/tables/invitations.d.ts.map +1 -0
  212. package/dist/db/tables/invitations.js +165 -0
  213. package/dist/db/tables/invitations.js.map +1 -0
  214. package/dist/db/tables/memberships.d.ts +108 -0
  215. package/dist/db/tables/memberships.d.ts.map +1 -0
  216. package/dist/db/tables/memberships.js +153 -0
  217. package/dist/db/tables/memberships.js.map +1 -0
  218. package/dist/db/tables/organizations.d.ts +123 -0
  219. package/dist/db/tables/organizations.d.ts.map +1 -0
  220. package/dist/db/tables/organizations.js +170 -0
  221. package/dist/db/tables/organizations.js.map +1 -0
  222. package/dist/db/tables/projects.d.ts +65 -0
  223. package/dist/db/tables/projects.d.ts.map +1 -0
  224. package/dist/db/tables/projects.js +75 -0
  225. package/dist/db/tables/projects.js.map +1 -0
  226. package/dist/db/tables/sponsoredTransactions.d.ts +120 -0
  227. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -0
  228. package/dist/db/tables/sponsoredTransactions.js +161 -0
  229. package/dist/db/tables/sponsoredTransactions.js.map +1 -0
  230. package/dist/db/tables/users.d.ts +48 -0
  231. package/dist/db/tables/users.d.ts.map +1 -0
  232. package/dist/db/tables/users.js +65 -0
  233. package/dist/db/tables/users.js.map +1 -0
  234. package/dist/db/tables/verifiedTokens.d.ts +53 -0
  235. package/dist/db/tables/verifiedTokens.d.ts.map +1 -0
  236. package/dist/db/tables/verifiedTokens.js +74 -0
  237. package/dist/db/tables/verifiedTokens.js.map +1 -0
  238. package/dist/db/tables/webhookDeliveries.d.ts +71 -0
  239. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -0
  240. package/dist/db/tables/webhookDeliveries.js +119 -0
  241. package/dist/db/tables/webhookDeliveries.js.map +1 -0
  242. package/dist/db/tables/webhookSubscriptions.d.ts +158 -0
  243. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -0
  244. package/dist/db/tables/webhookSubscriptions.js +272 -0
  245. package/dist/db/tables/webhookSubscriptions.js.map +1 -0
  246. package/dist/handlers/internal/executionError.d.ts +25 -0
  247. package/dist/handlers/internal/executionError.d.ts.map +1 -0
  248. package/dist/handlers/internal/executionError.js +186 -0
  249. package/dist/handlers/internal/executionError.js.map +1 -0
  250. package/dist/handlers/internal/multisig.d.ts +233 -0
  251. package/dist/handlers/internal/multisig.d.ts.map +1 -0
  252. package/dist/handlers/internal/multisig.js +542 -0
  253. package/dist/handlers/internal/multisig.js.map +1 -0
  254. package/dist/handlers/internal/requestListener.d.ts +124 -0
  255. package/dist/handlers/internal/requestListener.d.ts.map +1 -0
  256. package/dist/handlers/internal/requestListener.js +173 -0
  257. package/dist/handlers/internal/requestListener.js.map +1 -0
  258. package/dist/handlers/internal/sponsorship.d.ts +113 -0
  259. package/dist/handlers/internal/sponsorship.d.ts.map +1 -0
  260. package/dist/handlers/internal/sponsorship.js +128 -0
  261. package/dist/handlers/internal/sponsorship.js.map +1 -0
  262. package/dist/handlers/internal/types.d.ts +284 -0
  263. package/dist/handlers/internal/types.d.ts.map +1 -0
  264. package/dist/handlers/internal/types.js +2 -0
  265. package/dist/handlers/internal/types.js.map +1 -0
  266. package/dist/handlers/internal/utils.d.ts +34 -0
  267. package/dist/handlers/internal/utils.d.ts.map +1 -0
  268. package/dist/handlers/internal/utils.js +131 -0
  269. package/dist/handlers/internal/utils.js.map +1 -0
  270. package/dist/handlers/relay.d.ts +123 -0
  271. package/dist/handlers/relay.d.ts.map +1 -0
  272. package/dist/handlers/relay.js +1278 -0
  273. package/dist/handlers/relay.js.map +1 -0
  274. package/dist/index.d.ts +4 -2
  275. package/dist/index.d.ts.map +1 -1
  276. package/dist/index.js +4 -2
  277. package/dist/index.js.map +1 -1
  278. package/dist/internal/Auth.d.ts +224 -16
  279. package/dist/internal/Auth.d.ts.map +1 -1
  280. package/dist/internal/Auth.js +572 -33
  281. package/dist/internal/Auth.js.map +1 -1
  282. package/dist/internal/Log.d.ts +7 -3
  283. package/dist/internal/Log.d.ts.map +1 -1
  284. package/dist/internal/Log.js +4 -0
  285. package/dist/internal/Log.js.map +1 -1
  286. package/dist/internal/OpenApi.d.ts +0 -19
  287. package/dist/internal/OpenApi.d.ts.map +1 -1
  288. package/dist/internal/OpenApi.js +0 -57
  289. package/dist/internal/OpenApi.js.map +1 -1
  290. package/dist/internal/RpcSchema.d.ts +10 -0
  291. package/dist/internal/RpcSchema.d.ts.map +1 -0
  292. package/dist/internal/RpcSchema.js +2 -0
  293. package/dist/internal/RpcSchema.js.map +1 -0
  294. package/dist/internal/Store.d.ts +49 -4
  295. package/dist/internal/Store.d.ts.map +1 -1
  296. package/dist/internal/Store.js +81 -5
  297. package/dist/internal/Store.js.map +1 -1
  298. package/dist/internal/VerifiedTokens.d.ts +15 -34
  299. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  300. package/dist/internal/VerifiedTokens.js +115 -159
  301. package/dist/internal/VerifiedTokens.js.map +1 -1
  302. package/dist/internal/Viem.d.ts +84 -0
  303. package/dist/internal/Viem.d.ts.map +1 -1
  304. package/dist/internal/Webhooks.d.ts +50 -36
  305. package/dist/internal/Webhooks.d.ts.map +1 -1
  306. package/dist/internal/Webhooks.js +92 -205
  307. package/dist/internal/Webhooks.js.map +1 -1
  308. package/package.json +37 -6
  309. package/src/ApiKey.test.ts +3 -3
  310. package/src/ApiKey.ts +11 -12
  311. package/src/ApiKeys.test.ts +278 -0
  312. package/src/ApiKeys.ts +358 -0
  313. package/src/App.test-d.ts +1 -1
  314. package/src/App.test.ts +40508 -19083
  315. package/src/App.ts +239 -416
  316. package/src/Client.test-d.ts +307 -16
  317. package/src/Handler.ts +154 -0
  318. package/src/Scope.ts +17 -4
  319. package/src/Webhooks.test.ts +8 -7
  320. package/src/Webhooks.ts +13 -7
  321. package/src/admin/Access.ts +1 -3
  322. package/src/admin/App.ts +19 -24
  323. package/src/admin/apps/api-keys.test.ts +70 -18
  324. package/src/admin/apps/api-keys.ts +92 -9
  325. package/src/admin/apps/scopes.test.ts +8 -0
  326. package/src/admin/apps/verified-tokens.test.ts +3 -30
  327. package/src/admin/apps/verified-tokens.ts +18 -37
  328. package/src/admin/ui.generated.ts +1 -1
  329. package/src/apps/composition.test.ts +66 -0
  330. package/src/apps/data/App.ts +295 -0
  331. package/src/apps/data/index.ts +2 -0
  332. package/src/apps/{activities.test.ts → data/routes/activities.test.ts} +3 -3
  333. package/src/apps/{activities.ts → data/routes/activities.ts} +15 -15
  334. package/src/apps/{addresses.ts → data/routes/addresses.ts} +6 -6
  335. package/src/apps/{balances.test.ts → data/routes/balances.test.ts} +6 -5
  336. package/src/apps/{balances.ts → data/routes/balances.ts} +46 -12
  337. package/src/apps/{blocks.test.ts → data/routes/blocks.test.ts} +4 -4
  338. package/src/apps/{blocks.ts → data/routes/blocks.ts} +14 -14
  339. package/src/apps/{coingecko.test.ts → data/routes/coingecko.test.ts} +2 -2
  340. package/src/apps/{coingecko.ts → data/routes/coingecko.ts} +14 -14
  341. package/src/apps/{exchanges.test.ts → data/routes/exchanges.test.ts} +2 -2
  342. package/src/apps/{exchanges.ts → data/routes/exchanges.ts} +20 -20
  343. package/src/apps/{fee-amm.test.ts → data/routes/fee-amm.test.ts} +3 -3
  344. package/src/apps/{fee-amm.ts → data/routes/fee-amm.ts} +18 -18
  345. package/src/apps/{indexer.test.ts → data/routes/indexer.test.ts} +27 -6
  346. package/src/apps/{indexer.ts → data/routes/indexer.ts} +13 -10
  347. package/src/apps/{receipts.test.ts → data/routes/receipts.test.ts} +4 -4
  348. package/src/apps/{receipts.ts → data/routes/receipts.ts} +13 -13
  349. package/src/apps/{rpc.test.ts → data/routes/rpc.test.ts} +142 -13
  350. package/src/apps/{rpc.ts → data/routes/rpc.ts} +7 -7
  351. package/src/apps/{tokenlist.test.ts → data/routes/tokenlist.test.ts} +8 -10
  352. package/src/apps/{tokenlist.ts → data/routes/tokenlist.ts} +9 -9
  353. package/src/apps/{tokens.test.ts → data/routes/tokens.test.ts} +6 -5
  354. package/src/apps/{tokens.ts → data/routes/tokens.ts} +20 -20
  355. package/src/apps/{transactions.test.ts → data/routes/transactions.test.ts} +4 -4
  356. package/src/apps/{transactions.ts → data/routes/transactions.ts} +15 -15
  357. package/src/apps/{transfers.test.ts → data/routes/transfers.test.ts} +3 -3
  358. package/src/apps/{transfers.ts → data/routes/transfers.ts} +15 -15
  359. package/src/apps/{verified-tokens.test.ts → data/routes/verified-tokens.test.ts} +27 -15
  360. package/src/apps/{verified-tokens.ts → data/routes/verified-tokens.ts} +10 -10
  361. package/src/apps/{webhooks.test.ts → data/routes/webhooks.test.ts} +137 -150
  362. package/src/apps/{webhooks.ts → data/routes/webhooks.ts} +83 -81
  363. package/src/apps/docs/App.ts +136 -0
  364. package/src/apps/docs/index.ts +1 -0
  365. package/src/apps/index.ts +3 -0
  366. package/src/apps/metadata.ts +23 -0
  367. package/src/apps/platform/App.ts +130 -0
  368. package/src/apps/platform/index.ts +1 -0
  369. package/src/apps/platform/routes/api-keys.test.ts +330 -0
  370. package/src/apps/platform/routes/api-keys.ts +427 -0
  371. package/src/apps/platform/routes/invitations.test.ts +361 -0
  372. package/src/apps/platform/routes/invitations.ts +519 -0
  373. package/src/apps/platform/routes/me.test.ts +121 -0
  374. package/src/apps/platform/routes/me.ts +106 -0
  375. package/src/apps/platform/routes/members.test.ts +195 -0
  376. package/src/apps/platform/routes/members.ts +313 -0
  377. package/src/apps/platform/routes/orgs.test.ts +313 -0
  378. package/src/apps/platform/routes/orgs.ts +343 -0
  379. package/src/apps/platform/routes/projects.test.ts +181 -0
  380. package/src/apps/platform/routes/projects.ts +367 -0
  381. package/src/apps/relay/App.test.ts +484 -0
  382. package/src/apps/relay/App.ts +128 -0
  383. package/src/apps/relay/Sponsorships.test.ts +375 -0
  384. package/src/apps/relay/Sponsorships.ts +305 -0
  385. package/src/apps/relay/index.ts +2 -0
  386. package/src/{Cli.test.ts → cli/Cli.test.ts} +10 -9
  387. package/src/{Cli.ts → cli/Cli.ts} +16 -9
  388. package/src/cli/bin.ts +4 -0
  389. package/src/cli/commands/admin.test.ts +71 -0
  390. package/src/cli/commands/admin.ts +60 -0
  391. package/src/cloudflare.ts +10 -0
  392. package/src/db/Db.test.ts +84 -0
  393. package/src/db/Db.ts +542 -0
  394. package/src/db/Schema.ts +301 -0
  395. package/src/db/tables/invitations.ts +198 -0
  396. package/src/db/tables/memberships.ts +208 -0
  397. package/src/db/tables/organizations.test.ts +160 -0
  398. package/src/db/tables/organizations.ts +232 -0
  399. package/src/db/tables/projects.ts +107 -0
  400. package/src/db/tables/sponsoredTransactions.test.ts +218 -0
  401. package/src/db/tables/sponsoredTransactions.ts +236 -0
  402. package/src/db/tables/users.ts +85 -0
  403. package/src/db/tables/verifiedTokens.ts +111 -0
  404. package/src/db/tables/webhookDeliveries.ts +159 -0
  405. package/src/db/tables/webhookSubscriptions.ts +358 -0
  406. package/src/handlers/internal/executionError.ts +207 -0
  407. package/src/handlers/internal/multisig.test.ts +818 -0
  408. package/src/handlers/internal/multisig.ts +823 -0
  409. package/src/handlers/internal/requestListener.ts +273 -0
  410. package/src/handlers/internal/sponsorship.ts +245 -0
  411. package/src/handlers/internal/types.ts +378 -0
  412. package/src/handlers/internal/utils.ts +153 -0
  413. package/src/handlers/relay.test.ts +2035 -0
  414. package/src/handlers/relay.ts +1623 -0
  415. package/src/index.ts +4 -2
  416. package/src/internal/Auth.test.ts +337 -21
  417. package/src/internal/Auth.ts +783 -44
  418. package/src/internal/Cursor.test.ts +3 -2
  419. package/src/internal/Log.test.ts +1 -1
  420. package/src/internal/Log.ts +11 -3
  421. package/src/internal/MetricSink.ts +1 -1
  422. package/src/internal/OpenApi.ts +0 -59
  423. package/src/internal/RateLimit.test.ts +1 -1
  424. package/src/internal/RpcSchema.ts +10 -0
  425. package/src/internal/Store.test.ts +150 -10
  426. package/src/internal/Store.ts +136 -11
  427. package/src/internal/Tidx.local.test.ts +1 -1
  428. package/src/internal/VerifiedTokens.test.ts +99 -115
  429. package/src/internal/VerifiedTokens.ts +123 -175
  430. package/src/internal/WebhookDestination.test.ts +1 -1
  431. package/src/internal/Webhooks.test.ts +111 -111
  432. package/src/internal/Webhooks.ts +103 -221
  433. package/dist/ApiKeySource.d.ts +0 -166
  434. package/dist/ApiKeySource.d.ts.map +0 -1
  435. package/dist/ApiKeySource.js +0 -234
  436. package/dist/ApiKeySource.js.map +0 -1
  437. package/dist/Cli.d.ts.map +0 -1
  438. package/dist/Cli.js +0 -13
  439. package/dist/Cli.js.map +0 -1
  440. package/dist/apps/activities.js.map +0 -1
  441. package/dist/apps/addresses.js.map +0 -1
  442. package/dist/apps/balances.d.ts.map +0 -1
  443. package/dist/apps/balances.js.map +0 -1
  444. package/dist/apps/blocks.d.ts.map +0 -1
  445. package/dist/apps/blocks.js.map +0 -1
  446. package/dist/apps/coingecko.d.ts.map +0 -1
  447. package/dist/apps/coingecko.js.map +0 -1
  448. package/dist/apps/exchanges.d.ts.map +0 -1
  449. package/dist/apps/exchanges.js.map +0 -1
  450. package/dist/apps/fee-amm.d.ts.map +0 -1
  451. package/dist/apps/fee-amm.js.map +0 -1
  452. package/dist/apps/indexer.d.ts.map +0 -1
  453. package/dist/apps/indexer.js.map +0 -1
  454. package/dist/apps/receipts.d.ts.map +0 -1
  455. package/dist/apps/receipts.js.map +0 -1
  456. package/dist/apps/rpc.d.ts.map +0 -1
  457. package/dist/apps/rpc.js.map +0 -1
  458. package/dist/apps/tokenlist.d.ts.map +0 -1
  459. package/dist/apps/tokenlist.js.map +0 -1
  460. package/dist/apps/tokens.d.ts.map +0 -1
  461. package/dist/apps/tokens.js.map +0 -1
  462. package/dist/apps/transactions.d.ts.map +0 -1
  463. package/dist/apps/transactions.js.map +0 -1
  464. package/dist/apps/transfers.d.ts.map +0 -1
  465. package/dist/apps/transfers.js.map +0 -1
  466. package/dist/apps/verified-tokens.d.ts.map +0 -1
  467. package/dist/apps/verified-tokens.js.map +0 -1
  468. package/dist/apps/webhooks.js.map +0 -1
  469. package/dist/internal/OpenApi.fonts.d.ts.map +0 -1
  470. package/dist/internal/OpenApi.fonts.js.map +0 -1
  471. package/dist/internal/OpenApi.logo.d.ts.map +0 -1
  472. package/dist/internal/OpenApi.logo.js.map +0 -1
  473. package/seeds/31318/icons/0x20c0000000000000000000000000000000000000.svg +0 -1
  474. package/seeds/31318/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
  475. package/seeds/31318/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
  476. package/seeds/31318/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
  477. package/seeds/31318/verified-tokens.json +0 -30
  478. package/seeds/4217/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
  479. package/seeds/4217/icons/0x20c000000000000000000000048c8f36df1c9a4a.svg +0 -1
  480. package/seeds/4217/icons/0x20c0000000000000000000000520792dcccccccc.svg +0 -1
  481. package/seeds/4217/icons/0x20c0000000000000000000000a6da882d075a4c3.svg +0 -4
  482. package/seeds/4217/icons/0x20c000000000000000000000111111111e910f0f.svg +0 -30
  483. package/seeds/4217/icons/0x20c00000000000000000000014f22ca97301eb73.svg +0 -1
  484. package/seeds/4217/icons/0x20c0000000000000000000001621e21f71cf12fb.svg +0 -1
  485. package/seeds/4217/icons/0x20c0000000000000000000002f52d5cc21a3207b.svg +0 -1
  486. package/seeds/4217/icons/0x20c0000000000000000000003158081efd85bfc2.svg +0 -11
  487. package/seeds/4217/icons/0x20c0000000000000000000003554d28269e0f3c2.svg +0 -1
  488. package/seeds/4217/icons/0x20c000000000000000000000383a23bacb546ab9.svg +0 -1
  489. package/seeds/4217/icons/0x20c00000000000000000000042109aef2f8b28e1.png +0 -0
  490. package/seeds/4217/icons/0x20c0000000000000000000005c0bac7cef389a11.svg +0 -1
  491. package/seeds/4217/icons/0x20c0000000000000000000006fd9a167923ba194.png +0 -0
  492. package/seeds/4217/icons/0x20c0000000000000000000007f7ba549dd0251b9.svg +0 -1
  493. package/seeds/4217/icons/0x20c0000000000000000000008191667423f70e67.svg +0 -5
  494. package/seeds/4217/icons/0x20c0000000000000000000008ee4fcff88888888.svg +0 -1
  495. package/seeds/4217/icons/0x20c0000000000000000000009a4a4b17e0dc6651.svg +0 -1
  496. package/seeds/4217/icons/0x20c000000000000000000000ab02d39df30bd17e.svg +0 -1
  497. package/seeds/4217/icons/0x20c000000000000000000000ae247a1130450f09.svg +0 -1
  498. package/seeds/4217/icons/0x20c000000000000000000000aeed2ec36a54d0e5.svg +0 -1
  499. package/seeds/4217/icons/0x20c000000000000000000000b9537d11c60e8b50.svg +0 -1
  500. package/seeds/4217/icons/0x20c000000000000000000000bd95bfb69fbe6ce3.svg +0 -1
  501. package/seeds/4217/icons/0x20c000000000000000000000c412ec89d0c08be5.svg +0 -1
  502. package/seeds/4217/icons/0x20c000000000000000000000f047dd7018e50367.png +0 -0
  503. package/seeds/4217/verified-tokens.json +0 -177
  504. package/seeds/42431/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
  505. package/seeds/42431/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
  506. package/seeds/42431/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
  507. package/seeds/42431/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
  508. package/seeds/42431/icons/0x20c0000000000000000000009e8d7eb59b783726.svg +0 -1
  509. package/seeds/42431/icons/0x20c000000000000000000000d72572838bbee59c.svg +0 -1
  510. package/seeds/42431/verified-tokens.json +0 -44
  511. package/seeds/openrpc/README.md +0 -27
  512. package/seeds/openrpc/execution-apis.json +0 -8989
  513. package/src/ApiKeySource.test-d.ts +0 -11
  514. package/src/ApiKeySource.test.ts +0 -295
  515. package/src/ApiKeySource.ts +0 -303
  516. /package/src/{internal/OpenApi.fonts.ts → apps/docs/fonts.ts} +0 -0
  517. /package/src/{internal/OpenApi.logo.ts → apps/docs/logo.ts} +0 -0
@@ -0,0 +1,818 @@
1
+ import { Address, Hex, P256 } from 'ox'
2
+ import { MultisigConfig, SignatureEnvelope, TxEnvelopeTempo } from 'ox/tempo'
3
+ import { createClient, custom } from 'viem'
4
+ import { prepareTransactionRequest, sendTransactionSync, signTransaction } from 'viem/actions'
5
+ import { Account, Transaction } from 'viem/tempo'
6
+ import { tempoDevnet } from 'viem/tempo/chains'
7
+
8
+ import * as Relay from '../../../test/Relay.js'
9
+ import * as Runtime from '../../../test/runtime.js'
10
+ import * as StateStore from '../../internal/Store.js'
11
+ import * as Multisig from './multisig.js'
12
+
13
+ const privateKey_1 = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
14
+ const privateKey_2 = '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d'
15
+ const privateKey_3 = '0x7c852118294f7e395961158d39c448445a22a434adcd1d4e9048bcd3d85e9e4d'
16
+ const feeToken = '0x20c0000000000000000000000000000000000000' as const
17
+
18
+ describe('memoryStore', () => {
19
+ test('behavior: submission claims are exclusive until TTL expiry', async () => {
20
+ const store = Multisig.memoryStore()
21
+ const operation = createOperation()
22
+
23
+ await store.savePending(operation)
24
+ const first = await store.claimSubmission(operation, { ttl: 1_000 })
25
+ const second = await store.claimSubmission(operation, { ttl: 1_000 })
26
+
27
+ expect({ first: first.status, second: second.status }).toMatchInlineSnapshot(`
28
+ {
29
+ "first": "claimed",
30
+ "second": "submitting",
31
+ }
32
+ `)
33
+ })
34
+
35
+ test('behavior: expired submission claims can be reclaimed', async () => {
36
+ const store = Multisig.memoryStore()
37
+ const operation = createOperation()
38
+
39
+ await store.savePending(operation)
40
+ await store.claimSubmission(operation, { ttl: -1 })
41
+ const reclaimed = await store.claimSubmission(operation, { ttl: 1_000 })
42
+
43
+ expect(reclaimed.status).toMatchInlineSnapshot(`"claimed"`)
44
+ })
45
+
46
+ test('behavior: pending saves merge signatures and submitted operations are not listed as pending', async () => {
47
+ const store = Multisig.memoryStore()
48
+ const operation = createOperation()
49
+
50
+ await store.savePending({ ...operation, signatures: [`0x${'11'.repeat(65)}`] })
51
+ const merged = await store.savePending({ ...operation, signatures: [`0x${'22'.repeat(65)}`] })
52
+ await store.claimSubmission(merged, { ttl: 1_000 })
53
+ await store.setSubmitted(operation.id, `0x${'33'.repeat(32)}`)
54
+
55
+ expect({
56
+ listed: await store.listPendingByAddress(operation.account),
57
+ signatures: merged.signatures.length,
58
+ status: (await store.get(operation.id))?.status,
59
+ }).toMatchInlineSnapshot(`
60
+ {
61
+ "listed": [],
62
+ "signatures": 2,
63
+ "status": "submitted",
64
+ }
65
+ `)
66
+ })
67
+ })
68
+
69
+ describe('handleRawTransaction', () => {
70
+ test('behavior: rejects first approvals when no config can be resolved', async () => {
71
+ const owner = Account.fromSecp256k1(privateKey_1)
72
+ const account = Account.fromMultisig({
73
+ threshold: 1,
74
+ owners: [{ owner: owner.address, weight: 1 }],
75
+ })
76
+ const transaction = {
77
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
78
+ chainId: tempoDevnet.id,
79
+ gas: 21_000n,
80
+ maxFeePerGas: 1n,
81
+ maxPriorityFeePerGas: 0n,
82
+ multisig: account.config,
83
+ nonce: 0n,
84
+ }
85
+ const signature = await owner.signTransaction(transaction as never)
86
+ const serialized = withoutInit(
87
+ await account.signTransaction({ ...transaction, signatures: [signature] } as never),
88
+ )
89
+
90
+ await expect(
91
+ Multisig.handleRawTransaction({
92
+ getClient: (() => undefined) as never,
93
+ method: 'eth_sendRawTransaction',
94
+ request: { params: [serialized] },
95
+ store: Multisig.memoryStore(),
96
+ }),
97
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
98
+ `[RpcResponse.InvalidParamsError: Multisig config is required to collect approvals. Provide it in the bootstrap transaction or configure \`multisig.resolveConfig\`.]`,
99
+ )
100
+ })
101
+
102
+ test('behavior: finalize submitted preserves async broadcast method', async () => {
103
+ const owner = Account.fromSecp256k1(privateKey_1)
104
+ const account = Account.fromMultisig({
105
+ threshold: 1,
106
+ owners: [{ owner: owner.address, weight: 1 }],
107
+ })
108
+ const transaction = {
109
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
110
+ chainId: tempoDevnet.id,
111
+ gas: 21_000n,
112
+ maxFeePerGas: 1n,
113
+ maxPriorityFeePerGas: 0n,
114
+ multisig: account.config,
115
+ nonce: 0n,
116
+ }
117
+ const signature = await owner.signTransaction(transaction as never)
118
+ const serialized = await account.signTransaction({
119
+ ...transaction,
120
+ signatures: [signature],
121
+ } as never)
122
+ let broadcastMethod: string | undefined
123
+
124
+ const hash = await Multisig.handleRawTransaction({
125
+ finalize: 'submitted',
126
+ getClient: (() => ({
127
+ request: async ({ method, params }: { method: string; params: unknown }) => {
128
+ broadcastMethod = method
129
+ return hashRawTransaction(params)
130
+ },
131
+ })) as never,
132
+ method: 'eth_sendRawTransaction',
133
+ request: { params: [serialized] },
134
+ store: Multisig.memoryStore(),
135
+ })
136
+
137
+ expect({ broadcastMethod, hash }).toMatchInlineSnapshot(`
138
+ {
139
+ "broadcastMethod": "eth_sendRawTransaction",
140
+ "hash": "${hash}",
141
+ }
142
+ `)
143
+ })
144
+ })
145
+
146
+ describe('config resolution', () => {
147
+ test('behavior: reuses pending bootstrap config when a later approval omits init', async () => {
148
+ const store = Multisig.memoryStore()
149
+ const owner_1 = Account.fromSecp256k1(privateKey_1)
150
+ const owner_2 = Account.fromSecp256k1(privateKey_2)
151
+ const account = Account.fromMultisig({
152
+ threshold: 2,
153
+ owners: [
154
+ { owner: owner_1.address, weight: 1 },
155
+ { owner: owner_2.address, weight: 1 },
156
+ ],
157
+ })
158
+ const transaction = {
159
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
160
+ chainId: tempoDevnet.id,
161
+ gas: 21_000n,
162
+ maxFeePerGas: 1n,
163
+ maxPriorityFeePerGas: 0n,
164
+ multisig: account.config,
165
+ nonce: 0n,
166
+ }
167
+ const signature_1 = await owner_1.signTransaction(transaction as never)
168
+ const signature_2 = await owner_2.signTransaction(transaction as never)
169
+ const first = await account.signTransaction({
170
+ ...transaction,
171
+ signatures: [signature_1],
172
+ } as never)
173
+ const second = withoutInit(
174
+ await account.signTransaction({ ...transaction, signatures: [signature_2] } as never),
175
+ )
176
+
177
+ await Multisig.handleRawTransaction({
178
+ getClient: (() => undefined) as never,
179
+ method: 'eth_sendRawTransaction',
180
+ request: { params: [first] },
181
+ store,
182
+ })
183
+ const hash = await Multisig.handleRawTransaction({
184
+ getClient: (() => ({
185
+ request: async ({ params }: { params: unknown }) => hashRawTransaction(params),
186
+ })) as never,
187
+ method: 'eth_sendRawTransaction',
188
+ request: { params: [second] },
189
+ store,
190
+ })
191
+
192
+ expect(hash).toMatchInlineSnapshot(`"${hash}"`)
193
+ })
194
+
195
+ test('behavior: preserves bootstrap init when it arrives after a resolver-backed pending approval', async () => {
196
+ const store = Multisig.memoryStore()
197
+ const owner_1 = Account.fromSecp256k1(privateKey_1)
198
+ const owner_2 = Account.fromSecp256k1(privateKey_2)
199
+ const account = Account.fromMultisig({
200
+ threshold: 2,
201
+ owners: [
202
+ { owner: owner_1.address, weight: 1 },
203
+ { owner: owner_2.address, weight: 1 },
204
+ ],
205
+ })
206
+ const transaction = {
207
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
208
+ chainId: tempoDevnet.id,
209
+ gas: 21_000n,
210
+ maxFeePerGas: 1n,
211
+ maxPriorityFeePerGas: 0n,
212
+ multisig: account.config,
213
+ nonce: 0n,
214
+ }
215
+ const signature_1 = await owner_1.signTransaction(transaction as never)
216
+ const signature_2 = await owner_2.signTransaction(transaction as never)
217
+ const first = withoutInit(
218
+ await account.signTransaction({ ...transaction, signatures: [signature_1] } as never),
219
+ )
220
+ const second = await account.signTransaction({
221
+ ...transaction,
222
+ signatures: [signature_2],
223
+ } as never)
224
+ let submitted: `0x${string}` | undefined
225
+
226
+ await Multisig.handleRawTransaction({
227
+ getClient: (() => undefined) as never,
228
+ method: 'eth_sendRawTransaction',
229
+ request: { params: [first] },
230
+ resolveConfig: () => account.config,
231
+ store,
232
+ })
233
+ const hash = await Multisig.handleRawTransaction({
234
+ getClient: (() => ({
235
+ request: async ({ params }: { params: unknown }) => {
236
+ submitted = Array.isArray(params) ? (params[0] as `0x${string}`) : undefined
237
+ return hashRawTransaction(params)
238
+ },
239
+ })) as never,
240
+ method: 'eth_sendRawTransaction',
241
+ request: { params: [second] },
242
+ resolveConfig: () => account.config,
243
+ store,
244
+ })
245
+
246
+ const transaction_submitted = Transaction.deserialize(submitted! as never) as {
247
+ signature: SignatureEnvelope.Multisig
248
+ }
249
+ expect({
250
+ hash,
251
+ init: transaction_submitted.signature.init
252
+ ? MultisigConfig.getAddress(transaction_submitted.signature.init)
253
+ : undefined,
254
+ }).toMatchInlineSnapshot(`
255
+ {
256
+ "hash": "${hash}",
257
+ "init": "${account.address.toLowerCase()}",
258
+ }
259
+ `)
260
+ })
261
+
262
+ test('behavior: attaches resolver-provided bootstrap config when approvals omit init', async () => {
263
+ const store = Multisig.memoryStore()
264
+ const owner_1 = Account.fromSecp256k1(privateKey_1)
265
+ const owner_2 = Account.fromSecp256k1(privateKey_2)
266
+ const account = Account.fromMultisig({
267
+ threshold: 2,
268
+ owners: [
269
+ { owner: owner_1.address, weight: 1 },
270
+ { owner: owner_2.address, weight: 1 },
271
+ ],
272
+ })
273
+ const transaction = {
274
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
275
+ chainId: tempoDevnet.id,
276
+ gas: 21_000n,
277
+ maxFeePerGas: 1n,
278
+ maxPriorityFeePerGas: 0n,
279
+ multisig: account.config,
280
+ nonce: 0n,
281
+ }
282
+ const signature_1 = await owner_1.signTransaction(transaction as never)
283
+ const signature_2 = await owner_2.signTransaction(transaction as never)
284
+ const first = withoutInit(
285
+ await account.signTransaction({ ...transaction, signatures: [signature_1] } as never),
286
+ )
287
+ const second = withoutInit(
288
+ await account.signTransaction({ ...transaction, signatures: [signature_2] } as never),
289
+ )
290
+ let submitted: `0x${string}` | undefined
291
+
292
+ await Multisig.handleRawTransaction({
293
+ getClient: (() => undefined) as never,
294
+ method: 'eth_sendRawTransaction',
295
+ request: { params: [first] },
296
+ resolveConfig: () => account.config,
297
+ store,
298
+ })
299
+ const hash = await Multisig.handleRawTransaction({
300
+ getClient: (() => ({
301
+ request: async ({ params }: { params: unknown }) => {
302
+ submitted = Array.isArray(params) ? (params[0] as `0x${string}`) : undefined
303
+ return hashRawTransaction(params)
304
+ },
305
+ })) as never,
306
+ method: 'eth_sendRawTransaction',
307
+ request: { params: [second] },
308
+ resolveConfig: () => account.config,
309
+ store,
310
+ })
311
+
312
+ const transaction_submitted = Transaction.deserialize(submitted! as never) as {
313
+ signature: SignatureEnvelope.Multisig
314
+ }
315
+ expect({
316
+ hash,
317
+ init: transaction_submitted.signature.init
318
+ ? MultisigConfig.getAddress(transaction_submitted.signature.init)
319
+ : undefined,
320
+ }).toMatchInlineSnapshot(`
321
+ {
322
+ "hash": "${hash}",
323
+ "init": "${account.address.toLowerCase()}",
324
+ }
325
+ `)
326
+ })
327
+
328
+ test('behavior: preserves bootstrap init when claimed operation omits stored init config', async () => {
329
+ const base = Multisig.memoryStore()
330
+ const store: Multisig.Store = {
331
+ claimSubmission: async (operation, options) => {
332
+ const result = await base.claimSubmission(operation, options)
333
+ if (result.status !== 'claimed') return result
334
+ return {
335
+ operation: { ...result.operation, initConfig: undefined },
336
+ status: result.status,
337
+ }
338
+ },
339
+ get: base.get,
340
+ listPendingByAddress: base.listPendingByAddress,
341
+ savePending: base.savePending,
342
+ setSubmitted: base.setSubmitted,
343
+ }
344
+ const owner = Account.fromSecp256k1(privateKey_1)
345
+ const account = Account.fromMultisig({
346
+ threshold: 1,
347
+ owners: [{ owner: owner.address, weight: 1 }],
348
+ })
349
+ const transaction = {
350
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
351
+ chainId: tempoDevnet.id,
352
+ gas: 21_000n,
353
+ maxFeePerGas: 1n,
354
+ maxPriorityFeePerGas: 0n,
355
+ multisig: account.config,
356
+ nonce: 0n,
357
+ }
358
+ const signature = await owner.signTransaction(transaction as never)
359
+ const serialized = await account.signTransaction({
360
+ ...transaction,
361
+ signatures: [signature],
362
+ } as never)
363
+ let submitted: `0x${string}` | undefined
364
+
365
+ const hash = await Multisig.handleRawTransaction({
366
+ getClient: (() => ({
367
+ request: async ({ params }: { params: unknown }) => {
368
+ submitted = Array.isArray(params) ? (params[0] as `0x${string}`) : undefined
369
+ return hashRawTransaction(params)
370
+ },
371
+ })) as never,
372
+ method: 'eth_sendRawTransaction',
373
+ request: { params: [serialized] },
374
+ store,
375
+ })
376
+
377
+ const transaction_submitted = Transaction.deserialize(submitted! as never) as {
378
+ signature: SignatureEnvelope.Multisig
379
+ }
380
+ expect({
381
+ hash,
382
+ init: transaction_submitted.signature.init
383
+ ? MultisigConfig.getAddress(transaction_submitted.signature.init)
384
+ : undefined,
385
+ }).toMatchInlineSnapshot(`
386
+ {
387
+ "hash": "${hash}",
388
+ "init": "${account.address.toLowerCase()}",
389
+ }
390
+ `)
391
+ })
392
+
393
+ test('behavior: rejects resolved configs that do not match the multisig account', async () => {
394
+ const owner_1 = Account.fromSecp256k1(privateKey_1)
395
+ const owner_2 = Account.fromSecp256k1(privateKey_2)
396
+ const account = Account.fromMultisig({
397
+ threshold: 1,
398
+ owners: [{ owner: owner_1.address, weight: 1 }],
399
+ })
400
+ const wrong = Account.fromMultisig({
401
+ threshold: 1,
402
+ owners: [{ owner: owner_2.address, weight: 1 }],
403
+ })
404
+ const transaction = {
405
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
406
+ chainId: tempoDevnet.id,
407
+ gas: 21_000n,
408
+ maxFeePerGas: 1n,
409
+ maxPriorityFeePerGas: 0n,
410
+ multisig: account.config,
411
+ nonce: 0n,
412
+ }
413
+ const signature = await owner_1.signTransaction(transaction as never)
414
+ const serialized = await account.signTransaction({
415
+ ...transaction,
416
+ signatures: [signature],
417
+ } as never)
418
+
419
+ await expect(
420
+ Multisig.handleRawTransaction({
421
+ getClient: (() => undefined) as never,
422
+ method: 'eth_sendRawTransaction',
423
+ request: { params: [serialized] },
424
+ resolveConfig: () => wrong.config,
425
+ store: Multisig.memoryStore(),
426
+ }),
427
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
428
+ `[RpcResponse.InvalidParamsError: Signature from non-owner 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266.]`,
429
+ )
430
+ })
431
+
432
+ test('behavior: accepts current configs for updated multisig signer sets', async () => {
433
+ const owner_1 = Account.fromSecp256k1(privateKey_1)
434
+ const owner_2 = Account.fromSecp256k1(privateKey_2)
435
+ const account = Account.fromMultisig({
436
+ threshold: 1,
437
+ owners: [{ owner: owner_1.address, weight: 1 }],
438
+ })
439
+ const current = MultisigConfig.from({
440
+ owners: [
441
+ { owner: owner_1.address, weight: 1 },
442
+ { owner: owner_2.address, weight: 1 },
443
+ ],
444
+ threshold: 1,
445
+ })
446
+ const transaction = {
447
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
448
+ chainId: tempoDevnet.id,
449
+ gas: 21_000n,
450
+ maxFeePerGas: 1n,
451
+ maxPriorityFeePerGas: 0n,
452
+ multisig: account.config,
453
+ nonce: 1n,
454
+ }
455
+ const signature = await owner_2.signTransaction(transaction as never)
456
+ const serialized = withoutInit(
457
+ await account.signTransaction({
458
+ ...transaction,
459
+ signatures: [signature],
460
+ } as never),
461
+ )
462
+ let submitted: `0x${string}` | undefined
463
+
464
+ const hash = await Multisig.handleRawTransaction({
465
+ getClient: (() => ({
466
+ request: async ({ params }: { params: unknown }) => {
467
+ submitted = Array.isArray(params) ? (params[0] as `0x${string}`) : undefined
468
+ return hashRawTransaction(params)
469
+ },
470
+ })) as never,
471
+ method: 'eth_sendRawTransaction',
472
+ request: { params: [serialized] },
473
+ resolveConfig: () => current,
474
+ store: Multisig.memoryStore(),
475
+ })
476
+
477
+ const transaction_submitted = Transaction.deserialize(submitted! as never) as {
478
+ signature: SignatureEnvelope.Multisig
479
+ }
480
+ expect({
481
+ account: transaction_submitted.signature.account,
482
+ hash,
483
+ init: transaction_submitted.signature.init,
484
+ }).toMatchInlineSnapshot(`
485
+ {
486
+ "account": "${account.address.toLowerCase()}",
487
+ "hash": "${hash}",
488
+ "init": undefined,
489
+ }
490
+ `)
491
+ })
492
+ })
493
+
494
+ describe('approval validation', () => {
495
+ test('behavior: rejects P256 approvals whose embedded owner key did not sign the operation', async () => {
496
+ const privateKey = P256.randomPrivateKey()
497
+ const publicKey = P256.getPublicKey({ privateKey })
498
+ const owner = Address.fromPublicKey(publicKey)
499
+ const account = Account.fromMultisig({
500
+ threshold: 1,
501
+ owners: [{ owner, weight: 1 }],
502
+ })
503
+ const transaction = {
504
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
505
+ chainId: tempoDevnet.id,
506
+ gas: 21_000n,
507
+ maxFeePerGas: 1n,
508
+ maxPriorityFeePerGas: 0n,
509
+ multisig: account.config,
510
+ nonce: 0n,
511
+ }
512
+ const signature = SignatureEnvelope.serialize(
513
+ SignatureEnvelope.from({
514
+ publicKey,
515
+ signature: P256.sign({ payload: `0x${'44'.repeat(32)}`, privateKey }),
516
+ type: 'p256',
517
+ }),
518
+ )
519
+ const serialized = await account.signTransaction({
520
+ ...transaction,
521
+ signatures: [signature],
522
+ } as never)
523
+
524
+ await expect(
525
+ Multisig.handleRawTransaction({
526
+ getClient: (() => ({
527
+ request: async ({ params }: { params: unknown }) => hashRawTransaction(params),
528
+ })) as never,
529
+ method: 'eth_sendRawTransaction',
530
+ request: { params: [serialized] },
531
+ store: Multisig.memoryStore(),
532
+ }),
533
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
534
+ `[RpcResponse.InvalidParamsError: Invalid signature from owner ${owner}.]`,
535
+ )
536
+ })
537
+ })
538
+
539
+ describe('handleRawTransaction with sponsor', () => {
540
+ test('behavior: broadcasts finalized multisig transactions with feePayerSignature and default feeToken', async () => {
541
+ const store = Multisig.memoryStore()
542
+ const owner_1 = Account.fromSecp256k1(privateKey_1)
543
+ const owner_2 = Account.fromSecp256k1(privateKey_2)
544
+ const feePayer = Account.fromSecp256k1(privateKey_3)
545
+ const account = Account.fromMultisig({
546
+ threshold: 2,
547
+ owners: [
548
+ { owner: owner_1.address, weight: 1 },
549
+ { owner: owner_2.address, weight: 1 },
550
+ ],
551
+ })
552
+ const transaction = {
553
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
554
+ chainId: tempoDevnet.id,
555
+ feePayerSignature: null,
556
+ gas: 21_000n,
557
+ maxFeePerGas: 1n,
558
+ maxPriorityFeePerGas: 0n,
559
+ multisig: account.config,
560
+ nonce: 0n,
561
+ }
562
+ const signature_1 = await owner_1.signTransaction(transaction as never)
563
+ const signature_2 = await owner_2.signTransaction(transaction as never)
564
+ const first = await account.signTransaction({
565
+ ...transaction,
566
+ signatures: [signature_1],
567
+ } as never)
568
+ const second = await account.signTransaction({
569
+ ...transaction,
570
+ signatures: [signature_2],
571
+ } as never)
572
+ const broadcasted: string[] = []
573
+ const sponsored: unknown[] = []
574
+
575
+ await Multisig.handleRawTransaction({
576
+ getClient: (() => undefined) as never,
577
+ method: 'eth_sendRawTransaction',
578
+ request: { params: [first] },
579
+ sponsor: {
580
+ account: feePayer as never,
581
+ resolveFeeToken: () => feeToken,
582
+ },
583
+ store,
584
+ })
585
+ const hash = await Multisig.handleRawTransaction({
586
+ getClient: () =>
587
+ createClient({
588
+ chain: tempoDevnet,
589
+ transport: custom({
590
+ request: async ({ method, params }) => {
591
+ if (method === 'eth_chainId') return Hex.fromNumber(tempoDevnet.id)
592
+ broadcasted.push((params as readonly string[])[0]!)
593
+ return hashRawTransaction(params)
594
+ },
595
+ }),
596
+ }),
597
+ method: 'eth_sendRawTransaction',
598
+ request: { params: [second] },
599
+ sponsor: {
600
+ account: feePayer as never,
601
+ onSponsored: (event) => {
602
+ sponsored.push(event)
603
+ expect(broadcasted).toHaveLength(0)
604
+ },
605
+ resolveFeeToken: () => feeToken,
606
+ },
607
+ store,
608
+ })
609
+
610
+ const transaction_broadcasted = Transaction.deserialize(broadcasted[0] as never) as Record<
611
+ string,
612
+ unknown
613
+ >
614
+ const signature = transaction_broadcasted['signature'] as { init?: unknown; type?: string }
615
+ expect({
616
+ feePayerSignature: Boolean(transaction_broadcasted['feePayerSignature']),
617
+ feeToken: (transaction_broadcasted['feeToken'] as string).toLowerCase(),
618
+ hash,
619
+ init: Boolean(signature.init),
620
+ sponsored: sponsored.length,
621
+ signature: signature.type,
622
+ }).toMatchInlineSnapshot(`
623
+ {
624
+ "feePayerSignature": true,
625
+ "feeToken": "0x20c0000000000000000000000000000000000000",
626
+ "hash": "${hash}",
627
+ "init": true,
628
+ "signature": "multisig",
629
+ "sponsored": 1,
630
+ }
631
+ `)
632
+ })
633
+
634
+ test('behavior: broadcasts already sponsored multisig transactions without replacing fee payer', async () => {
635
+ const owner = Account.fromSecp256k1(privateKey_1)
636
+ const feePayer_original = Account.fromSecp256k1(privateKey_2)
637
+ const feePayer_relay = Account.fromSecp256k1(privateKey_3)
638
+ const account = Account.fromMultisig({
639
+ threshold: 1,
640
+ owners: [{ owner: owner.address, weight: 1 }],
641
+ })
642
+ const transaction = {
643
+ calls: [{ to: '0xcafebabecafebabecafebabecafebabecafebabe', value: 1n }],
644
+ chainId: tempoDevnet.id,
645
+ feePayerSignature: null,
646
+ gas: 21_000n,
647
+ maxFeePerGas: 1n,
648
+ maxPriorityFeePerGas: 0n,
649
+ multisig: account.config,
650
+ nonce: 0n,
651
+ }
652
+ const signature = await owner.signTransaction(transaction as never)
653
+ const serialized = await account.signTransaction({
654
+ ...transaction,
655
+ signatures: [signature],
656
+ } as never)
657
+ const sponsored: `0x${string}`[] = []
658
+
659
+ await Multisig.handleRawTransaction({
660
+ getClient: () =>
661
+ createClient({
662
+ chain: tempoDevnet,
663
+ transport: custom({
664
+ request: async ({ method, params }) => {
665
+ if (method === 'eth_chainId') return Hex.fromNumber(tempoDevnet.id)
666
+ sponsored.push((params as readonly `0x${string}`[])[0]!)
667
+ return hashRawTransaction(params)
668
+ },
669
+ }),
670
+ }),
671
+ method: 'eth_sendRawTransaction',
672
+ request: { params: [serialized] },
673
+ sponsor: {
674
+ account: feePayer_original as never,
675
+ resolveFeeToken: () => feeToken,
676
+ },
677
+ store: Multisig.memoryStore(),
678
+ })
679
+ const presponsored = sponsored[0]
680
+ if (!presponsored) throw new Error('Expected pre-sponsored transaction.')
681
+
682
+ let broadcasted: `0x${string}` | undefined
683
+ const hash = await Multisig.handleRawTransaction({
684
+ getClient: (() => ({
685
+ request: async ({ params }: { params: unknown }) => {
686
+ broadcasted = Array.isArray(params) ? (params[0] as `0x${string}`) : undefined
687
+ return hashRawTransaction(params)
688
+ },
689
+ })) as never,
690
+ method: 'eth_sendRawTransaction',
691
+ request: { params: [presponsored] },
692
+ sponsor: {
693
+ account: feePayer_relay as never,
694
+ feeToken,
695
+ validate: () => false,
696
+ },
697
+ store: Multisig.memoryStore(),
698
+ })
699
+
700
+ const transaction_broadcasted = Transaction.deserialize(broadcasted! as never) as Record<
701
+ string,
702
+ unknown
703
+ >
704
+ expect({
705
+ feePayerSignature: Boolean(transaction_broadcasted['feePayerSignature']),
706
+ feeToken: (transaction_broadcasted['feeToken'] as string).toLowerCase(),
707
+ hash,
708
+ signature: (transaction_broadcasted['signature'] as { type?: string }).type,
709
+ }).toMatchInlineSnapshot(`
710
+ {
711
+ "feePayerSignature": true,
712
+ "feeToken": "0x20c0000000000000000000000000000000000000",
713
+ "hash": "${hash}",
714
+ "signature": "multisig",
715
+ }
716
+ `)
717
+ })
718
+ })
719
+
720
+ describe.runIf(Runtime.get().mode === 'localnet' && process.env.TEMPO_IMAGE_TAG === 'sha-8968664')(
721
+ 'e2e',
722
+ () => {
723
+ const owner_1 = Relay.accounts[1]!
724
+ const owner_2 = Relay.accounts[2]!
725
+ const feePayer = Relay.accounts[0]!
726
+ const sponsorFeeToken = Relay.addresses.pathUsd
727
+ const store = StateStore.memory()
728
+ let client: ReturnType<typeof Relay.getClient>
729
+ let server: Relay.Server
730
+
731
+ beforeAll(async () => {
732
+ server = await Relay.createServer(
733
+ (
734
+ await Relay.relay({
735
+ feePayer: {
736
+ account: feePayer,
737
+ feeToken: sponsorFeeToken,
738
+ },
739
+ multisig: { store },
740
+ })
741
+ ).listener,
742
+ )
743
+ client = Relay.getClient({ url: server.url })
744
+ })
745
+
746
+ afterAll(() => {
747
+ server.close()
748
+ })
749
+
750
+ test('behavior: sponsors bootstrap multisig', async () => {
751
+ const account = Account.fromMultisig({
752
+ threshold: 2,
753
+ owners: [
754
+ { owner: owner_1.address, weight: 1 },
755
+ { owner: owner_2.address, weight: 1 },
756
+ ],
757
+ })
758
+ const transaction = await prepareTransactionRequest(client, {
759
+ account,
760
+ feePayer: true,
761
+ to: account.address,
762
+ value: 0n,
763
+ })
764
+ const signatures = await Promise.all(
765
+ [owner_1, owner_2].map((owner) =>
766
+ signTransaction(client, { ...transaction, account: owner }),
767
+ ),
768
+ )
769
+ const receipt = await sendTransactionSync(client, {
770
+ ...transaction,
771
+ account,
772
+ signatures,
773
+ })
774
+
775
+ expect(receipt).toMatchObject({
776
+ feePayer: feePayer.address.toLowerCase(),
777
+ feeToken: sponsorFeeToken.toLowerCase(),
778
+ from: account.address.toLowerCase(),
779
+ status: 'success',
780
+ })
781
+ })
782
+ },
783
+ )
784
+
785
+ function createOperation(): Multisig.Operation {
786
+ const now = Date.now()
787
+ return {
788
+ account: '0x0000000000000000000000000000000000000001',
789
+ chainId: tempoDevnet.id,
790
+ createdAt: now,
791
+ id: `0x${'22'.repeat(32)}`,
792
+ payload: `0x${'33'.repeat(32)}`,
793
+ signatures: [],
794
+ status: 'pending',
795
+ transaction: `0x76${'44'.repeat(32)}`,
796
+ updatedAt: now,
797
+ }
798
+ }
799
+
800
+ function hashRawTransaction(params: unknown) {
801
+ const serialized = Array.isArray(params) ? params[0] : undefined
802
+ if (typeof serialized !== 'string') throw new Error('Expected raw transaction.')
803
+ return TxEnvelopeTempo.hash(
804
+ TxEnvelopeTempo.deserialize(serialized as TxEnvelopeTempo.Serialized) as TxEnvelopeTempo.Signed,
805
+ )
806
+ }
807
+
808
+ function withoutInit(serialized: `0x${string}`) {
809
+ const transaction = Transaction.deserialize(serialized as never) as Record<string, unknown>
810
+ const signature = transaction['signature'] as SignatureEnvelope.Multisig
811
+ const { signature: _, ...unsigned } = transaction
812
+ return TxEnvelopeTempo.serialize(TxEnvelopeTempo.from(unsigned as never), {
813
+ signature: SignatureEnvelope.from({
814
+ account: signature.account,
815
+ signatures: signature.signatures,
816
+ }),
817
+ })
818
+ }