tapimo 0.7.2 → 0.9.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 (300) hide show
  1. package/README.md +10 -7
  2. package/dist/ApiKey.d.ts +3 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +10 -0
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +7 -3
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +9 -2
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +20117 -19183
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +61 -4
  13. package/dist/App.js.map +1 -1
  14. package/dist/admin/App.d.ts +84 -74
  15. package/dist/admin/App.d.ts.map +1 -1
  16. package/dist/admin/apps/api-keys.d.ts +14 -1
  17. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  18. package/dist/admin/apps/api-keys.js +6 -2
  19. package/dist/admin/apps/api-keys.js.map +1 -1
  20. package/dist/admin/apps/organizations.d.ts +2 -0
  21. package/dist/admin/apps/organizations.d.ts.map +1 -1
  22. package/dist/admin/apps/verified-tokens.d.ts +11 -11
  23. package/dist/admin/ui.generated.d.ts +1 -1
  24. package/dist/admin/ui.generated.js +67 -67
  25. package/dist/admin/ui.generated.js.map +1 -1
  26. package/dist/analytics/Analytics.d.ts +2 -0
  27. package/dist/analytics/Analytics.d.ts.map +1 -1
  28. package/dist/analytics/Analytics.js +3 -0
  29. package/dist/analytics/Analytics.js.map +1 -1
  30. package/dist/apps/data/App.d.ts +11696 -13937
  31. package/dist/apps/data/App.d.ts.map +1 -1
  32. package/dist/apps/data/App.js +4 -8
  33. package/dist/apps/data/App.js.map +1 -1
  34. package/dist/apps/data/routes/activities.d.ts +271 -271
  35. package/dist/apps/data/routes/addresses.d.ts +398 -167
  36. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  37. package/dist/apps/data/routes/balances.d.ts +278 -8
  38. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  39. package/dist/apps/data/routes/balances.js +114 -2
  40. package/dist/apps/data/routes/balances.js.map +1 -1
  41. package/dist/apps/data/routes/blocks.d.ts +123 -123
  42. package/dist/apps/data/routes/coingecko.d.ts +170 -170
  43. package/dist/apps/data/routes/earn.d.ts +498 -6
  44. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  45. package/dist/apps/data/routes/earn.js +876 -4
  46. package/dist/apps/data/routes/earn.js.map +1 -1
  47. package/dist/apps/data/routes/exchanges.d.ts +10 -10
  48. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  49. package/dist/apps/data/routes/indexer.d.ts +6 -6
  50. package/dist/apps/data/routes/indexer.js +4 -1
  51. package/dist/apps/data/routes/indexer.js.map +1 -1
  52. package/dist/apps/data/routes/receipts.d.ts +235 -235
  53. package/dist/apps/data/routes/rpc.d.ts +31 -31
  54. package/dist/apps/data/routes/rpc.js +4 -1
  55. package/dist/apps/data/routes/rpc.js.map +1 -1
  56. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  57. package/dist/apps/data/routes/tokens.d.ts +449 -449
  58. package/dist/apps/data/routes/transactions.d.ts +2 -2
  59. package/dist/apps/data/routes/transfers.d.ts +81 -81
  60. package/dist/apps/data/routes/valuation.d.ts +1 -1
  61. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  62. package/dist/apps/data/routes/webhooks.d.ts +9 -9
  63. package/dist/apps/data/routes/zones.d.ts +14 -14
  64. package/dist/apps/funding/Access.d.ts +16 -0
  65. package/dist/apps/funding/Access.d.ts.map +1 -0
  66. package/dist/apps/funding/Access.js +22 -0
  67. package/dist/apps/funding/Access.js.map +1 -0
  68. package/dist/apps/{data/routes/funding.d.ts → funding/App.d.ts} +1640 -3217
  69. package/dist/apps/funding/App.d.ts.map +1 -0
  70. package/dist/apps/funding/App.js +61 -0
  71. package/dist/apps/funding/App.js.map +1 -0
  72. package/dist/apps/funding/Inventory.d.ts +5 -0
  73. package/dist/apps/funding/Inventory.d.ts.map +1 -0
  74. package/dist/apps/funding/Inventory.js +25 -0
  75. package/dist/apps/funding/Inventory.js.map +1 -0
  76. package/dist/apps/funding/ProviderAttempts.d.ts +5 -0
  77. package/dist/apps/funding/ProviderAttempts.d.ts.map +1 -0
  78. package/dist/apps/funding/ProviderAttempts.js +24 -0
  79. package/dist/apps/funding/ProviderAttempts.js.map +1 -0
  80. package/dist/apps/funding/index.d.ts +2 -0
  81. package/dist/apps/funding/index.d.ts.map +1 -0
  82. package/dist/apps/funding/index.js +2 -0
  83. package/dist/apps/funding/index.js.map +1 -0
  84. package/dist/apps/funding/routes/chains.d.ts +169 -0
  85. package/dist/apps/funding/routes/chains.d.ts.map +1 -0
  86. package/dist/apps/funding/routes/chains.js +80 -0
  87. package/dist/apps/funding/routes/chains.js.map +1 -0
  88. package/dist/apps/funding/routes/deposit-addresses.d.ts +1997 -0
  89. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -0
  90. package/dist/apps/funding/routes/deposit-addresses.js +778 -0
  91. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -0
  92. package/dist/apps/funding/routes/providers.d.ts +91 -0
  93. package/dist/apps/funding/routes/providers.d.ts.map +1 -0
  94. package/dist/apps/funding/routes/providers.js +56 -0
  95. package/dist/apps/funding/routes/providers.js.map +1 -0
  96. package/dist/apps/funding/routes/quotes.d.ts +426 -0
  97. package/dist/apps/funding/routes/quotes.d.ts.map +1 -0
  98. package/dist/apps/funding/routes/quotes.js +188 -0
  99. package/dist/apps/funding/routes/quotes.js.map +1 -0
  100. package/dist/apps/funding/routes/transfers.d.ts +1999 -0
  101. package/dist/apps/funding/routes/transfers.d.ts.map +1 -0
  102. package/dist/apps/funding/routes/transfers.js +614 -0
  103. package/dist/apps/funding/routes/transfers.js.map +1 -0
  104. package/dist/apps/index.d.ts +1 -0
  105. package/dist/apps/index.d.ts.map +1 -1
  106. package/dist/apps/index.js +1 -0
  107. package/dist/apps/index.js.map +1 -1
  108. package/dist/apps/management/App.d.ts +430 -165
  109. package/dist/apps/management/App.d.ts.map +1 -1
  110. package/dist/apps/management/routes/api-keys.d.ts +298 -21
  111. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  112. package/dist/apps/management/routes/api-keys.js +75 -1
  113. package/dist/apps/management/routes/api-keys.js.map +1 -1
  114. package/dist/apps/management/routes/billing.d.ts +6 -6
  115. package/dist/apps/management/routes/faucet.d.ts +35 -35
  116. package/dist/apps/management/routes/invitations.d.ts +122 -122
  117. package/dist/apps/management/routes/invite-links.d.ts +38 -38
  118. package/dist/apps/management/routes/members.d.ts +69 -69
  119. package/dist/apps/management/routes/orgs.d.ts +99 -99
  120. package/dist/apps/management/routes/projects.d.ts +25 -25
  121. package/dist/apps/management/routes/scopes.d.ts +1 -1
  122. package/dist/apps/management/routes/usage.d.ts +72 -72
  123. package/dist/apps/management/routes/verified-token-requests.d.ts +77 -77
  124. package/dist/apps/management/routes/webhooks.d.ts +128 -128
  125. package/dist/apps/mcp.d.ts +2 -3
  126. package/dist/apps/mcp.d.ts.map +1 -1
  127. package/dist/apps/mcp.js +16 -14
  128. package/dist/apps/mcp.js.map +1 -1
  129. package/dist/apps/metadata.d.ts +4 -0
  130. package/dist/apps/metadata.d.ts.map +1 -1
  131. package/dist/apps/metadata.js +10 -0
  132. package/dist/apps/metadata.js.map +1 -1
  133. package/dist/apps/mpp/App.d.ts +44 -44
  134. package/dist/cloudflare.d.ts +50 -0
  135. package/dist/cloudflare.d.ts.map +1 -1
  136. package/dist/cloudflare.js +178 -0
  137. package/dist/cloudflare.js.map +1 -1
  138. package/dist/db/Db.d.ts +2 -0
  139. package/dist/db/Db.d.ts.map +1 -1
  140. package/dist/db/Db.js +45 -0
  141. package/dist/db/Db.js.map +1 -1
  142. package/dist/db/Schema.d.ts +12 -0
  143. package/dist/db/Schema.d.ts.map +1 -1
  144. package/dist/db/Schema.js +20 -0
  145. package/dist/db/Schema.js.map +1 -1
  146. package/dist/db/tables/fundingDepositAddresses.d.ts +13 -0
  147. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -1
  148. package/dist/db/tables/fundingDepositAddresses.js +12 -0
  149. package/dist/db/tables/fundingDepositAddresses.js.map +1 -1
  150. package/dist/db/tables/fundingDepositRequestObservations.d.ts +45 -0
  151. package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +1 -0
  152. package/dist/db/tables/fundingDepositRequestObservations.js +46 -0
  153. package/dist/db/tables/fundingDepositRequestObservations.js.map +1 -0
  154. package/dist/db/tables/fundingDeposits.d.ts +74 -1
  155. package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
  156. package/dist/db/tables/fundingDeposits.js +126 -0
  157. package/dist/db/tables/fundingDeposits.js.map +1 -1
  158. package/dist/internal/Auth.d.ts +15 -11
  159. package/dist/internal/Auth.d.ts.map +1 -1
  160. package/dist/internal/Auth.js +52 -17
  161. package/dist/internal/Auth.js.map +1 -1
  162. package/dist/internal/Cache.js +1 -1
  163. package/dist/internal/Cache.js.map +1 -1
  164. package/dist/internal/EdgeCache.d.ts +2 -2
  165. package/dist/internal/EdgeCache.d.ts.map +1 -1
  166. package/dist/internal/EdgeCache.js +10 -4
  167. package/dist/internal/EdgeCache.js.map +1 -1
  168. package/dist/internal/IpAllowlist.d.ts +15 -0
  169. package/dist/internal/IpAllowlist.d.ts.map +1 -0
  170. package/dist/internal/IpAllowlist.js +27 -0
  171. package/dist/internal/IpAllowlist.js.map +1 -0
  172. package/dist/internal/OpenApi.d.ts +1 -1
  173. package/dist/internal/OpenApi.js +1 -1
  174. package/dist/internal/OpenApi.js.map +1 -1
  175. package/dist/internal/Tidx.d.ts +6 -0
  176. package/dist/internal/Tidx.d.ts.map +1 -1
  177. package/dist/internal/Tidx.js +13 -3
  178. package/dist/internal/Tidx.js.map +1 -1
  179. package/dist/internal/Viem.d.ts +8 -0
  180. package/dist/internal/Viem.d.ts.map +1 -1
  181. package/dist/internal/Viem.js +12 -5
  182. package/dist/internal/Viem.js.map +1 -1
  183. package/dist/internal/funding/Deposit.d.ts +42 -0
  184. package/dist/internal/funding/Deposit.d.ts.map +1 -1
  185. package/dist/internal/funding/Deposit.js +37 -5
  186. package/dist/internal/funding/Deposit.js.map +1 -1
  187. package/dist/internal/funding/Evidence.d.ts +1 -5
  188. package/dist/internal/funding/Evidence.d.ts.map +1 -1
  189. package/dist/internal/funding/Evidence.js +4 -3
  190. package/dist/internal/funding/Evidence.js.map +1 -1
  191. package/dist/internal/funding/Provider.d.ts +102 -0
  192. package/dist/internal/funding/Provider.d.ts.map +1 -1
  193. package/dist/internal/funding/Provider.js +5 -0
  194. package/dist/internal/funding/Provider.js.map +1 -1
  195. package/dist/internal/funding/Reconciliation.d.ts +16 -2
  196. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  197. package/dist/internal/funding/Reconciliation.js +348 -54
  198. package/dist/internal/funding/Reconciliation.js.map +1 -1
  199. package/dist/internal/funding/SourceObservation.d.ts +108 -0
  200. package/dist/internal/funding/SourceObservation.d.ts.map +1 -0
  201. package/dist/internal/funding/SourceObservation.js +143 -0
  202. package/dist/internal/funding/SourceObservation.js.map +1 -0
  203. package/dist/internal/funding/Subsidy.d.ts +2 -2
  204. package/dist/internal/funding/Subsidy.d.ts.map +1 -1
  205. package/dist/internal/funding/Subsidy.js +1 -1
  206. package/dist/internal/funding/Subsidy.js.map +1 -1
  207. package/dist/internal/funding/index.d.ts +1 -0
  208. package/dist/internal/funding/index.d.ts.map +1 -1
  209. package/dist/internal/funding/index.js +1 -0
  210. package/dist/internal/funding/index.js.map +1 -1
  211. package/dist/internal/funding/providers/relay.d.ts +43 -1
  212. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  213. package/dist/internal/funding/providers/relay.js +438 -27
  214. package/dist/internal/funding/providers/relay.js.map +1 -1
  215. package/package.json +3 -3
  216. package/src/ApiKey.test.ts +35 -0
  217. package/src/ApiKey.ts +27 -0
  218. package/src/ApiKeys.test.ts +29 -0
  219. package/src/ApiKeys.ts +11 -3
  220. package/src/App.test.ts +55 -5
  221. package/src/App.ts +79 -5
  222. package/src/Client.test-d.ts +203 -28
  223. package/src/admin/apps/api-keys.test.ts +25 -1
  224. package/src/admin/apps/api-keys.ts +6 -2
  225. package/src/admin/ui.generated.ts +67 -67
  226. package/src/analytics/Analytics.ts +4 -0
  227. package/src/apps/composition.test.ts +130 -3
  228. package/src/apps/data/App.test.ts +0 -12
  229. package/src/apps/data/App.ts +4 -8
  230. package/src/apps/data/routes/balances.test.ts +42 -0
  231. package/src/apps/data/routes/balances.ts +218 -85
  232. package/src/apps/data/routes/earn.test.ts +363 -0
  233. package/src/apps/data/routes/earn.ts +1141 -3
  234. package/src/apps/data/routes/indexer.ts +2 -1
  235. package/src/apps/data/routes/rpc.ts +2 -0
  236. package/src/apps/data/routes/tokens.test.ts +6 -8
  237. package/src/apps/funding/Access.ts +26 -0
  238. package/src/apps/funding/App.test.ts +78 -0
  239. package/src/apps/funding/App.ts +78 -0
  240. package/src/apps/funding/Inventory.ts +30 -0
  241. package/src/apps/funding/ProviderAttempts.ts +26 -0
  242. package/src/apps/funding/index.ts +1 -0
  243. package/src/apps/funding/routes/chains.test.ts +78 -0
  244. package/src/apps/funding/routes/chains.ts +101 -0
  245. package/src/apps/funding/routes/deposit-addresses.test.ts +1649 -0
  246. package/src/apps/funding/routes/deposit-addresses.ts +932 -0
  247. package/src/apps/funding/routes/providers.test.ts +165 -0
  248. package/src/apps/funding/routes/providers.ts +73 -0
  249. package/src/apps/funding/routes/quotes.test.ts +511 -0
  250. package/src/apps/funding/routes/quotes.ts +205 -0
  251. package/src/apps/funding/routes/transfers.test.ts +1236 -0
  252. package/src/apps/funding/routes/transfers.ts +704 -0
  253. package/src/apps/index.ts +1 -0
  254. package/src/apps/management/routes/api-keys.test.ts +98 -0
  255. package/src/apps/management/routes/api-keys.ts +96 -1
  256. package/src/apps/mcp.test.ts +17 -2
  257. package/src/apps/mcp.ts +18 -13
  258. package/src/apps/metadata.ts +12 -0
  259. package/src/apps/mpp/internal/Policy.test.ts +7 -1
  260. package/src/cloudflare.ts +279 -0
  261. package/src/db/Db.ts +71 -0
  262. package/src/db/Schema.ts +24 -0
  263. package/src/db/tables/fundingDepositAddresses.ts +28 -0
  264. package/src/db/tables/fundingDepositRequestObservations.test.ts +106 -0
  265. package/src/db/tables/fundingDepositRequestObservations.ts +99 -0
  266. package/src/db/tables/fundingDeposits.test.ts +239 -0
  267. package/src/db/tables/fundingDeposits.ts +214 -1
  268. package/src/internal/Auth.test.ts +205 -5
  269. package/src/internal/Auth.ts +63 -19
  270. package/src/internal/Cache.test.ts +37 -3
  271. package/src/internal/Cache.ts +1 -1
  272. package/src/internal/EdgeCache.test.ts +7 -7
  273. package/src/internal/EdgeCache.ts +13 -4
  274. package/src/internal/IpAllowlist.test.ts +52 -0
  275. package/src/internal/IpAllowlist.ts +39 -0
  276. package/src/internal/Log.test.ts +7 -1
  277. package/src/internal/OpenApi.ts +1 -1
  278. package/src/internal/Tidx.test.ts +28 -0
  279. package/src/internal/Tidx.ts +19 -3
  280. package/src/internal/Viem.test.ts +28 -0
  281. package/src/internal/Viem.ts +21 -5
  282. package/src/internal/funding/Deposit.ts +74 -5
  283. package/src/internal/funding/Evidence.test.ts +2 -2
  284. package/src/internal/funding/Evidence.ts +4 -9
  285. package/src/internal/funding/Provider.ts +115 -0
  286. package/src/internal/funding/Reconciliation.local.test.ts +7 -0
  287. package/src/internal/funding/Reconciliation.test.ts +1364 -109
  288. package/src/internal/funding/Reconciliation.ts +467 -88
  289. package/src/internal/funding/SourceObservation.test.ts +301 -0
  290. package/src/internal/funding/SourceObservation.ts +267 -0
  291. package/src/internal/funding/Subsidy.ts +2 -2
  292. package/src/internal/funding/index.test.ts +1 -0
  293. package/src/internal/funding/index.ts +1 -0
  294. package/src/internal/funding/providers/relay.test.ts +94 -4
  295. package/src/internal/funding/providers/relay.ts +533 -27
  296. package/dist/apps/data/routes/funding.d.ts.map +0 -1
  297. package/dist/apps/data/routes/funding.js +0 -1557
  298. package/dist/apps/data/routes/funding.js.map +0 -1
  299. package/src/apps/data/routes/funding.test.ts +0 -2994
  300. package/src/apps/data/routes/funding.ts +0 -1821
@@ -0,0 +1,704 @@
1
+ import { type Context, Hono } from 'hono'
2
+ import { etag } from 'hono/etag'
3
+ import * as z from 'zod/mini'
4
+
5
+ import type * as App from '../../../App.js'
6
+ import * as Db from '../../../db/Db.js'
7
+ import * as FundingIdempotency from '../../../db/tables/fundingIdempotency.js'
8
+ import * as FundingTransfers from '../../../db/tables/fundingTransfers.js'
9
+ import * as Auth from '../../../internal/Auth.js'
10
+ import * as Cache from '../../../internal/Cache.js'
11
+ import * as FundingCatalog from '../../../internal/funding/Catalog.js'
12
+ import * as FundingProvider from '../../../internal/funding/Provider.js'
13
+ import * as FundingTransfer from '../../../internal/funding/Transfer.js'
14
+ import * as Idempotency from '../../../internal/Idempotency.js'
15
+ import * as OpenApi from '../../../internal/OpenApi.js'
16
+ import * as Response from '../../../internal/Response.js'
17
+ import * as Schema from '../../../internal/Schema.js'
18
+ import * as Value from '../../../internal/Value.js'
19
+ import * as Access from '../Access.js'
20
+ import * as ProviderAttempts from '../ProviderAttempts.js'
21
+
22
+ /** Zod schemas owned by funding transfer resources. */
23
+ export namespace schema {
24
+ /** A durable funding transfer. Reads never include the executable `action`. */
25
+ export const Transfer = FundingTransfer.schema.FundingTransfer
26
+ /** Schemas for the listFundingTransfers operation. */
27
+ export namespace listFundingTransfers {
28
+ /** Query parameters for listing funding transfers. */
29
+ export const Query = z
30
+ .object({
31
+ cursor: Schema.Cursor,
32
+ include: Schema.totalCountInclude,
33
+ limit: Schema.Limit,
34
+ status: z.optional(FundingTransfer.schema.Status),
35
+ })
36
+ .check(z.describe('Query parameters for listing funding transfers.'))
37
+
38
+ /** Paginated funding transfer list. */
39
+ export const Response = z
40
+ .object({
41
+ data: z.array(Transfer).check(z.describe('Funding transfers on this page, newest first.')),
42
+ meta: z
43
+ .optional(Schema.CountMeta)
44
+ .check(z.describe('Extra response metadata requested with `include`.')),
45
+ nextCursor: Schema.NextCursor,
46
+ })
47
+ .check(z.describe('A page of funding transfers.'))
48
+ }
49
+
50
+ /** Schemas for the createFundingTransfer operation. */
51
+ export namespace createFundingTransfer {
52
+ /** Funding transfer creation request body. */
53
+ export const Body = FundingTransfer.schema.CreateRequest
54
+
55
+ /** Required headers for funding transfer creation. */
56
+ export const Headers = z.object({
57
+ 'idempotency-key': z
58
+ .string()
59
+ .check(
60
+ z.minLength(1),
61
+ z.describe(
62
+ 'Opaque retry key scoped to the API key. Matching requests replay successful responses for 24 hours; changed input conflicts, in-flight requests block, and failed attempts release the key.',
63
+ ),
64
+ z.meta({ examples: ['funding_01k1c5j8q8p0be6j5v9m6d1e4r'] }),
65
+ ),
66
+ })
67
+
68
+ /** The created transfer with its one-time executable action. */
69
+ export const Response = FundingTransfer.schema.CreatedFundingTransfer
70
+ }
71
+
72
+ const destinationCreateFields = {
73
+ amount: FundingTransfer.schema.CreateRequest.shape.amount,
74
+ mode: FundingTransfer.schema.CreateRequest.shape.mode,
75
+ recipient: FundingTransfer.schema.CreateRequest.shape.recipient,
76
+ sender: FundingTransfer.schema.CreateRequest.shape.sender,
77
+ slippageBps: FundingTransfer.schema.CreateRequest.shape.slippageBps,
78
+ sourceChain: FundingTransfer.schema.CreateRequest.shape.sourceChain,
79
+ sourceToken: FundingTransfer.schema.CreateRequest.shape.sourceToken,
80
+ }
81
+
82
+ /** Schemas for the createFundingTransferVault operation. */
83
+ export namespace createFundingTransferVault {
84
+ /** Funding transfer creation request for an Earn vault destination. */
85
+ export const Body = z
86
+ .strictObject({
87
+ ...destinationCreateFields,
88
+ vaultAddress: z
89
+ .string()
90
+ .check(
91
+ z.regex(/^0x[0-9a-fA-F]{40}$/),
92
+ z.describe('Tempo Earn vault contract address.'),
93
+ z.meta({ examples: [`0x${'f4'.repeat(20)}`] }),
94
+ ),
95
+ })
96
+ .check(z.describe('Vault funding transfer creation request.'))
97
+
98
+ /** Required headers for vault funding transfer creation. */
99
+ export const Headers = createFundingTransfer.Headers
100
+ }
101
+
102
+ /** Schemas for the createFundingTransferZone operation. */
103
+ export namespace createFundingTransferZone {
104
+ /** Funding transfer creation request for a Zone destination. */
105
+ export const Body = z
106
+ .strictObject({
107
+ amount: destinationCreateFields.amount,
108
+ destinationChain: z
109
+ .string()
110
+ .check(
111
+ z.regex(/^eip155:\d+$/),
112
+ z.describe('Configured Zone CAIP-2 id.'),
113
+ z.meta({ examples: ['eip155:421700001'] }),
114
+ ),
115
+ destinationToken: FundingTransfer.schema.CreateRequest.shape.destinationToken,
116
+ mode: destinationCreateFields.mode,
117
+ recipient: destinationCreateFields.recipient,
118
+ recipientFallback: z
119
+ .string()
120
+ .check(
121
+ z.regex(/^0x[0-9a-fA-F]{40}$/),
122
+ z.describe('Public Tempo recipient used if the Zone credit cannot complete.'),
123
+ z.meta({ examples: [`0x${'22'.repeat(20)}`] }),
124
+ ),
125
+ sender: destinationCreateFields.sender,
126
+ slippageBps: destinationCreateFields.slippageBps,
127
+ sourceChain: destinationCreateFields.sourceChain,
128
+ sourceToken: destinationCreateFields.sourceToken,
129
+ })
130
+ .check(z.describe('Zone funding transfer creation request.'))
131
+
132
+ /** Required headers for Zone funding transfer creation. */
133
+ export const Headers = createFundingTransfer.Headers
134
+ }
135
+
136
+ /** Schemas for the getFundingTransfer operation. */
137
+ export namespace getFundingTransfer {
138
+ /** Path parameters for a funding transfer read. */
139
+ export const Params = z
140
+ .object({
141
+ id: z
142
+ .string()
143
+ .check(
144
+ z.describe('Funding transfer ID (`ftr_…`).'),
145
+ z.meta({ examples: ['ftr_001785729600000_2ZPE2gvateYEQ0dQslgvkhjx'] }),
146
+ ),
147
+ })
148
+ .check(z.describe('Path parameters for a funding transfer request.'))
149
+
150
+ /** The funding transfer resource, returned directly. */
151
+ export const Response = Transfer
152
+ }
153
+ }
154
+
155
+ const baseChainExample = {
156
+ addressFormat: 'hex',
157
+ id: 'eip155:8453',
158
+ kind: 'evm',
159
+ name: 'Base',
160
+ } as const
161
+
162
+ const baseUsdcExample = {
163
+ address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
164
+ currency: 'USD',
165
+ decimals: 6,
166
+ name: 'USD Coin',
167
+ standard: 'ERC-20',
168
+ symbol: 'USDC',
169
+ tokenKey: 'eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
170
+ verified: true,
171
+ } as const
172
+
173
+ const fundingTransferExample = {
174
+ createdAt: '2026-01-01T00:00:00.000Z',
175
+ destinationAmount: Value.tokenAmount({ baseUnits: '979295', currency: 'USD', decimals: 6 }),
176
+ destinationAmountMin: Value.tokenAmount({ baseUnits: '939242', currency: 'USD', decimals: 6 }),
177
+ destinationChain: {
178
+ addressFormat: 'hex',
179
+ id: 'eip155:4217',
180
+ kind: 'evm',
181
+ name: 'Tempo',
182
+ },
183
+ destinationToken: {
184
+ address: '0x20c0000000000000000000000000000000000000',
185
+ currency: 'USD',
186
+ decimals: 6,
187
+ name: 'PathUSD',
188
+ standard: 'TIP-20',
189
+ symbol: 'pathUSD',
190
+ tokenKey: 'eip155:4217/erc20:0x20c0000000000000000000000000000000000000',
191
+ verified: true,
192
+ },
193
+ fees: [
194
+ {
195
+ amount: Value.tokenAmount({ baseUnits: '20705', currency: 'USD', decimals: 6 }),
196
+ side: 'source',
197
+ token: baseUsdcExample,
198
+ type: 'provider',
199
+ },
200
+ ],
201
+ id: 'ftr_001767225600000_2ZPE2gvateYEQ0dQslgvkhjx',
202
+ method: 'transaction',
203
+ mode: 'exactSource',
204
+ provider: { id: 'relay', name: 'Relay' },
205
+ quote: {
206
+ expiresAt: '2026-01-01T00:01:00.000Z',
207
+ sampledAt: '2026-01-01T00:00:00.000Z',
208
+ },
209
+ recipient: `0x${'11'.repeat(20)}`,
210
+ sender: `0x${'22'.repeat(20)}`,
211
+ sourceAmount: Value.tokenAmount({ baseUnits: '1000000', currency: 'USD', decimals: 6 }),
212
+ sourceChain: baseChainExample,
213
+ sourceToken: baseUsdcExample,
214
+ status: 'awaiting-source',
215
+ updatedAt: '2026-01-01T00:00:00.000Z',
216
+ version: 1,
217
+ } satisfies z.output<typeof schema.Transfer>
218
+
219
+ const listFundingTransfersResponseExample = {
220
+ data: [fundingTransferExample],
221
+ nextCursor: null,
222
+ } satisfies z.output<typeof schema.listFundingTransfers.Response>
223
+
224
+ const createdFundingTransferExample = {
225
+ action: {
226
+ calls: [
227
+ {
228
+ data: `0x095ea7b3000000000000000000000000${'44'.repeat(20)}00000000000000000000000000000000000000000000000000000000000f4240`,
229
+ to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
230
+ value: '0x0',
231
+ },
232
+ {
233
+ data: '0xe8017952',
234
+ to: `0x${'44'.repeat(20)}`,
235
+ value: '0x0',
236
+ },
237
+ ],
238
+ type: 'evm:calls',
239
+ },
240
+ ...fundingTransferExample,
241
+ } satisfies z.output<typeof schema.createFundingTransfer.Response>
242
+
243
+ const unimplementedFundingTransferResponses = (() => {
244
+ const responses = OpenApi.responses({
245
+ errors: {
246
+ 400: { codes: ['body_invalid', 'idempotency_key_required'] },
247
+ 501: {
248
+ codes: ['not_implemented'],
249
+ description: 'This funding transfer destination is not implemented.',
250
+ },
251
+ },
252
+ success: {
253
+ description: 'Unused until this destination is implemented.',
254
+ schema: z.never(),
255
+ },
256
+ })
257
+ const { 200: success, 502: upstream, ...errors } = responses
258
+ void success
259
+ void upstream
260
+ return errors
261
+ })()
262
+
263
+ // Replay the exact successful creation response for 24 hours.
264
+ const idempotencyReplayTtlMs = 86_400_000
265
+ // Pending claims only cover the bounded provider preparation window.
266
+ const idempotencyPendingTtlMs = 60_000
267
+ const fundingEtag = etag()
268
+
269
+ /** Mounts durable funding transfer routes. */
270
+ export function transfers() {
271
+ return new Hono<App.Environment>()
272
+ .get(
273
+ '/v1/funding/transfers',
274
+ Auth.policy({ apiKey: { scopes: ['funding:read'] } }),
275
+ OpenApi.validate('query', schema.listFundingTransfers.Query, {
276
+ code: 'query_invalid',
277
+ message: 'Check the query parameters and try again.',
278
+ }),
279
+ OpenApi.describeRoute({
280
+ description: 'Lists transfers from newest to oldest.',
281
+ operationId: 'listFundingTransfers',
282
+ responses: OpenApi.responses({
283
+ errors: {
284
+ 400: { codes: ['query_invalid'] },
285
+ },
286
+ success: {
287
+ description: 'A page of funding transfers.',
288
+ example: listFundingTransfersResponseExample,
289
+ schema: schema.listFundingTransfers.Response,
290
+ },
291
+ }),
292
+ summary: 'List transfers',
293
+ tags: ['Funding Transfers'],
294
+ }),
295
+ fundingEtag,
296
+ async (c) => {
297
+ if (Auth.narrowAccess) return Auth.accessError(c)
298
+ if (OpenApi.narrowValidation)
299
+ return OpenApi.validationError(c, {
300
+ code: 'query_invalid',
301
+ message: 'Check the query parameters and try again.',
302
+ })
303
+
304
+ const owner = Access.owner(c)
305
+ if (!owner) return Access.unauthorized(c)
306
+
307
+ const db = Db.get(c.get('db'))
308
+ const { cursor, include, limit, status } = c.req.valid('query')
309
+ try {
310
+ // `totalCount` is opt-in and capped (a capped subquery shares the
311
+ // list filter); run it concurrently with the page list. Best-effort:
312
+ // a failure omits `meta` rather than failing the page.
313
+ const countPromise = include.includes('totalCount')
314
+ ? FundingTransfers.count(db, owner, { cap: Schema.countCap, status }).catch(() => {
315
+ c.set('fundingTransferCountFailed', true)
316
+ return undefined
317
+ })
318
+ : undefined
319
+
320
+ // Fetch one extra to detect a further page without a second round-trip.
321
+ const rows = await FundingTransfers.list(db, owner, { cursor, limit: limit + 1, status })
322
+ const hasMore = rows.length > limit
323
+ const data = (hasMore ? rows.slice(0, limit) : rows).map(FundingTransfer.toPublic)
324
+ const nextCursor = hasMore ? (data[data.length - 1]?.id ?? null) : null
325
+
326
+ const count = countPromise ? await countPromise : undefined
327
+
328
+ c.header('Cache-Control', Cache.policies.feed)
329
+ c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key')
330
+
331
+ return c.json(
332
+ Response.validated(schema.listFundingTransfers.Response, {
333
+ data,
334
+ ...(count !== undefined
335
+ ? {
336
+ meta: {
337
+ totalCountCapped: count > Schema.countCap,
338
+ totalCount: Math.min(count, Schema.countCap),
339
+ },
340
+ }
341
+ : {}),
342
+ nextCursor,
343
+ }),
344
+ 200,
345
+ )
346
+ } catch (cause) {
347
+ return Response.upstream(c, cause)
348
+ }
349
+ },
350
+ )
351
+ .get(
352
+ '/v1/funding/transfers/:id{ftr_[A-Za-z0-9_-]+}',
353
+ Auth.policy({ apiKey: { scopes: ['funding:read'] } }),
354
+ OpenApi.validate('param', schema.getFundingTransfer.Params, {
355
+ code: 'param_invalid',
356
+ message: 'Check the path parameters and try again.',
357
+ }),
358
+ OpenApi.describeRoute({
359
+ description: 'Returns a transfer by ID.',
360
+ operationId: 'getFundingTransfer',
361
+ responses: OpenApi.responses({
362
+ errors: {
363
+ 400: { codes: ['param_invalid'] },
364
+ 404: {
365
+ codes: ['funding_transfer_not_found'],
366
+ description: 'No visible funding transfer exists for the identifier.',
367
+ },
368
+ },
369
+ success: {
370
+ description: 'The requested funding transfer.',
371
+ example: fundingTransferExample,
372
+ schema: schema.getFundingTransfer.Response,
373
+ },
374
+ }),
375
+ summary: 'Get transfer',
376
+ tags: ['Funding Transfers'],
377
+ }),
378
+ async (c) => {
379
+ if (Auth.narrowAccess) return Auth.accessError(c)
380
+ if (OpenApi.narrowValidation)
381
+ return OpenApi.validationError(c, {
382
+ code: 'param_invalid',
383
+ message: 'Check the path parameters and try again.',
384
+ })
385
+
386
+ const owner = Access.owner(c)
387
+ if (!owner) return Access.unauthorized(c)
388
+
389
+ const db = Db.get(c.get('db'))
390
+ const { id } = c.req.valid('param')
391
+ try {
392
+ // Ownership filters in SQL, so absent and foreign rows are the same 404.
393
+ const record = await FundingTransfers.getOwned(db, owner, id)
394
+ if (!record)
395
+ return Response.error(c, {
396
+ code: 'funding_transfer_not_found',
397
+ message: 'Funding transfer not found',
398
+ status: 404,
399
+ })
400
+ c.header('Cache-Control', Cache.policies.noStore)
401
+ c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key')
402
+ return c.json(
403
+ Response.validated(
404
+ schema.getFundingTransfer.Response,
405
+ FundingTransfer.toPublic(record),
406
+ ),
407
+ 200,
408
+ )
409
+ } catch (cause) {
410
+ return Response.upstream(c, cause)
411
+ }
412
+ },
413
+ )
414
+ .post(
415
+ '/v1/funding/transfers',
416
+ Auth.policy({ apiKey: { scopes: ['funding:write'] } }),
417
+ OpenApi.validate('header', schema.createFundingTransfer.Headers, {
418
+ code: 'idempotency_key_required',
419
+ message: 'Funding transfer creation requires an `Idempotency-Key` header.',
420
+ }),
421
+ OpenApi.validate('json', schema.createFundingTransfer.Body, {
422
+ code: 'body_invalid',
423
+ message: 'Check the request body and try again.',
424
+ }),
425
+ OpenApi.describeRoute({
426
+ description: 'Creates a transfer to a Tempo account.',
427
+ operationId: 'createFundingTransfer',
428
+ responses: OpenApi.responses({
429
+ errors: {
430
+ 400: { codes: ['body_invalid', 'idempotency_key_required'] },
431
+ 404: {
432
+ codes: ['quote_not_available'],
433
+ description: 'No provider can prepare the requested route.',
434
+ },
435
+ 409: {
436
+ codes: ['idempotency_conflict', 'idempotency_in_progress'],
437
+ description: 'The Idempotency-Key conflicts with an existing or in-flight request.',
438
+ },
439
+ 502: {
440
+ codes: ['upstream_error'],
441
+ description: 'No provider succeeded and at least one failed unexpectedly.',
442
+ },
443
+ },
444
+ success: {
445
+ description: 'The created funding transfer with its one-time executable action.',
446
+ example: createdFundingTransferExample,
447
+ schema: schema.createFundingTransfer.Response,
448
+ },
449
+ }),
450
+ summary: 'Create transfer',
451
+ tags: ['Funding Transfers'],
452
+ }),
453
+ async (c) => {
454
+ if (Auth.narrowAccess) return Auth.accessError(c)
455
+ if (OpenApi.narrowValidation)
456
+ return OpenApi.validationError(c, {
457
+ code: 'body_invalid',
458
+ message: 'Check the request body and try again.',
459
+ })
460
+
461
+ const principal = Auth.getPrincipal(c)
462
+ const owner = Access.owner(c)
463
+ if (!owner || principal?.type !== 'api_key') return Access.unauthorized(c)
464
+ c.header('Cache-Control', 'no-store')
465
+
466
+ const idempotencyKey = c.req.valid('header')['idempotency-key']
467
+
468
+ const body = c.req.valid('json')
469
+ const db = Db.get(c.get('db'))
470
+ const identity = {
471
+ apiKeyId: principal.id,
472
+ keyHash: Idempotency.inputHash(idempotencyKey),
473
+ requestHash: Idempotency.inputHash(body),
474
+ }
475
+ const claim = await FundingIdempotency.claim(db, {
476
+ ...identity,
477
+ ttlMs: idempotencyPendingTtlMs,
478
+ })
479
+ if (claim.type === 'mismatch')
480
+ return Response.error(c, {
481
+ code: 'idempotency_conflict',
482
+ message: 'This Idempotency-Key was already used with different input.',
483
+ status: 409,
484
+ })
485
+ if (claim.type === 'pending')
486
+ return Response.error(c, {
487
+ code: 'idempotency_in_progress',
488
+ message: 'An equivalent funding transfer creation is still running.',
489
+ status: 409,
490
+ })
491
+ if (claim.type === 'replay')
492
+ return c.json(
493
+ JSON.parse(claim.response) as z.output<typeof schema.createFundingTransfer.Response>,
494
+ 200,
495
+ )
496
+
497
+ const release = async () => {
498
+ try {
499
+ await FundingIdempotency.release(db, {
500
+ apiKeyId: identity.apiKeyId,
501
+ createdAt: claim.createdAt,
502
+ keyHash: identity.keyHash,
503
+ })
504
+ } catch {
505
+ // The pending claim expires on its own; the response stays authoritative.
506
+ }
507
+ }
508
+ try {
509
+ const attempts: FundingProvider.ProviderAttempt[] = []
510
+ const catalog = await FundingCatalog.snapshot(c)
511
+ const providers = c.get('providers').filter(FundingProvider.is)
512
+ const selected = await FundingProvider.prepareTransfer({
513
+ catalog,
514
+ destinationChainId: c.get('chainId'),
515
+ destinationToken: body.destinationToken,
516
+ method: 'transaction',
517
+ mode: body.mode,
518
+ onAttempt: (attempt) => attempts.push(attempt),
519
+ providers,
520
+ recipient: body.recipient,
521
+ sender: body.sender,
522
+ slippageBps: body.slippageBps,
523
+ sourceAmount: body.amount,
524
+ sourceChain: body.sourceChain,
525
+ sourceToken: body.sourceToken,
526
+ })
527
+ if (attempts.length > 0)
528
+ c.set('fundingProviderAttempts', attempts.map(ProviderAttempts.format))
529
+ if (!selected) {
530
+ await release()
531
+ return quoteNotAvailable(c)
532
+ }
533
+
534
+ const { candidate, result } = selected
535
+ const feeToken = (side: 'destination' | 'source') =>
536
+ side === 'source' ? candidate.sourceToken : candidate.destinationToken
537
+ const snapshot: FundingTransfer.Snapshot = {
538
+ destinationAmount: Value.tokenAmount({
539
+ baseUnits: result.destinationAmount,
540
+ currency: candidate.destinationToken.currency,
541
+ decimals: candidate.destinationToken.decimals,
542
+ }),
543
+ destinationAmountMin: Value.tokenAmount({
544
+ baseUnits: result.destinationAmountMin,
545
+ currency: candidate.destinationToken.currency,
546
+ decimals: candidate.destinationToken.decimals,
547
+ }),
548
+ destinationChain: candidate.destinationChain,
549
+ destinationToken: candidate.destinationToken,
550
+ fees: result.fees.map((fee) => ({
551
+ amount: Value.tokenAmount({
552
+ baseUnits: fee.amount,
553
+ currency: feeToken(fee.side).currency,
554
+ decimals: feeToken(fee.side).decimals,
555
+ }),
556
+ side: fee.side,
557
+ token: feeToken(fee.side),
558
+ type: 'provider',
559
+ })),
560
+ method: 'transaction',
561
+ mode: body.mode,
562
+ provider: candidate.provider,
563
+ quote: { expiresAt: result.expiresAt, sampledAt: result.sampledAt },
564
+ recipient: body.recipient,
565
+ sender: body.sender,
566
+ sourceAmount: Value.tokenAmount({
567
+ baseUnits: candidate.sourceAmount.amount,
568
+ currency: candidate.sourceToken.currency,
569
+ decimals: candidate.sourceToken.decimals,
570
+ }),
571
+ sourceChain: candidate.sourceChain,
572
+ sourceToken: candidate.sourceToken,
573
+ }
574
+
575
+ // The transfer row, its version-1 event, and the replay body commit
576
+ // atomically so a crash cannot leave a claimed key without a replay.
577
+ const created = await db.transaction(async (tx) => {
578
+ const record = await FundingTransfer.createIn(tx, {
579
+ apiKeyId: principal.id,
580
+ environment: owner.environment,
581
+ orgId: owner.orgId,
582
+ projectId: owner.projectId,
583
+ providerState: result.correlation,
584
+ snapshot,
585
+ })
586
+ const validated = Response.validated(
587
+ schema.createFundingTransfer.Response,
588
+ FundingTransfer.toCreated(record, result.action),
589
+ )
590
+ const completion = await FundingIdempotency.complete(tx, {
591
+ apiKeyId: identity.apiKeyId,
592
+ createdAt: claim.createdAt,
593
+ keyHash: identity.keyHash,
594
+ replayTtlMs: idempotencyReplayTtlMs,
595
+ response: JSON.stringify(validated),
596
+ transferId: record.id,
597
+ })
598
+ if (!completion)
599
+ throw new IdempotencyLeaseLostError('Funding transfer creation lease was lost.')
600
+ return validated
601
+ })
602
+ return c.json(created, 200)
603
+ } catch (cause) {
604
+ await release()
605
+ if (cause instanceof FundingProvider.InvalidAmountError)
606
+ return Response.error(c, { code: 'body_invalid', message: 'Invalid `amount`.', status: 400 }) // prettier-ignore
607
+ if (cause instanceof FundingProvider.UnsupportedSourceChainError)
608
+ return quoteNotAvailable(c)
609
+ if (cause instanceof FundingProvider.ProviderQuoteError) {
610
+ if (cause.fundingProviderAttempts.length > 0)
611
+ c.set('fundingProviderAttempts', cause.fundingProviderAttempts)
612
+ if (cause.providerFailure) c.set('providerFailure', cause.providerFailure)
613
+ if (cause.providerFailures) c.set('providerFailures', cause.providerFailures)
614
+ return Response.error(c, {
615
+ code: 'upstream_error',
616
+ message: 'No funding provider could prepare the transfer.',
617
+ status: 502,
618
+ })
619
+ }
620
+ throw cause
621
+ }
622
+ },
623
+ )
624
+ .post(
625
+ '/v1/funding/transfers/vault',
626
+ Auth.policy({ apiKey: { scopes: ['funding:write'] } }),
627
+ OpenApi.validate('header', schema.createFundingTransferVault.Headers, {
628
+ code: 'idempotency_key_required',
629
+ message: 'Funding transfer creation requires an `Idempotency-Key` header.',
630
+ }),
631
+ OpenApi.validate('json', schema.createFundingTransferVault.Body, {
632
+ code: 'body_invalid',
633
+ message: 'Check the request body and try again.',
634
+ }),
635
+ OpenApi.describeRoute({
636
+ description: 'Creates a transfer into a Tempo Earn vault.',
637
+ operationId: 'createFundingTransferVault',
638
+ responses: unimplementedFundingTransferResponses,
639
+ summary: 'Create transfer into vault',
640
+ tags: ['Funding Transfers'],
641
+ }),
642
+ (c) => {
643
+ if (Auth.narrowAccess) return Auth.accessError(c)
644
+ if (OpenApi.narrowValidation)
645
+ return OpenApi.validationError(c, {
646
+ code: 'body_invalid',
647
+ message: 'Check the request body and try again.',
648
+ })
649
+
650
+ c.header('Cache-Control', 'no-store')
651
+ return Response.error(c, {
652
+ code: 'not_implemented',
653
+ message: 'Vault funding transfers are not implemented.',
654
+ status: 501,
655
+ })
656
+ },
657
+ )
658
+ .post(
659
+ '/v1/funding/transfers/zone',
660
+ Auth.policy({ apiKey: { scopes: ['funding:write'] } }),
661
+ OpenApi.validate('header', schema.createFundingTransferZone.Headers, {
662
+ code: 'idempotency_key_required',
663
+ message: 'Funding transfer creation requires an `Idempotency-Key` header.',
664
+ }),
665
+ OpenApi.validate('json', schema.createFundingTransferZone.Body, {
666
+ code: 'body_invalid',
667
+ message: 'Check the request body and try again.',
668
+ }),
669
+ OpenApi.describeRoute({
670
+ description: 'Creates a transfer into a Tempo Zone.',
671
+ operationId: 'createFundingTransferZone',
672
+ responses: unimplementedFundingTransferResponses,
673
+ summary: 'Create transfer into zone',
674
+ tags: ['Funding Transfers'],
675
+ }),
676
+ (c) => {
677
+ if (Auth.narrowAccess) return Auth.accessError(c)
678
+ if (OpenApi.narrowValidation)
679
+ return OpenApi.validationError(c, {
680
+ code: 'body_invalid',
681
+ message: 'Check the request body and try again.',
682
+ })
683
+
684
+ c.header('Cache-Control', 'no-store')
685
+ return Response.error(c, {
686
+ code: 'not_implemented',
687
+ message: 'Zone funding transfers are not implemented.',
688
+ status: 501,
689
+ })
690
+ },
691
+ )
692
+ }
693
+
694
+ function quoteNotAvailable(c: Context<App.Environment>) {
695
+ return Response.error(c, {
696
+ code: 'quote_not_available',
697
+ message: 'No provider can prepare the requested funding route.',
698
+ status: 404,
699
+ })
700
+ }
701
+
702
+ class IdempotencyLeaseLostError extends Error {
703
+ override name = 'Funding.IdempotencyLeaseLostError'
704
+ }