@avow-finance/sdk 0.0.0-stage → 0.1.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 (267) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +122 -2
  3. package/dist/agent-entry.d.ts +15 -0
  4. package/dist/agent-entry.d.ts.map +1 -0
  5. package/dist/agent-entry.js +11 -0
  6. package/dist/agent-entry.js.map +1 -0
  7. package/dist/agent-key.d.ts +34 -0
  8. package/dist/agent-key.d.ts.map +1 -0
  9. package/dist/agent-key.js +33 -0
  10. package/dist/agent-key.js.map +1 -0
  11. package/dist/agent.d.ts +261 -0
  12. package/dist/agent.d.ts.map +1 -0
  13. package/dist/agent.js +493 -0
  14. package/dist/agent.js.map +1 -0
  15. package/dist/avow-api.d.ts +78 -0
  16. package/dist/avow-api.d.ts.map +1 -0
  17. package/dist/avow-api.js +2 -0
  18. package/dist/avow-api.js.map +1 -0
  19. package/dist/contest.d.ts +135 -0
  20. package/dist/contest.d.ts.map +1 -0
  21. package/dist/contest.js +186 -0
  22. package/dist/contest.js.map +1 -0
  23. package/dist/http.d.ts +161 -0
  24. package/dist/http.d.ts.map +1 -0
  25. package/dist/http.js +311 -0
  26. package/dist/http.js.map +1 -0
  27. package/dist/index.d.ts +38 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +38 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/job/accept.d.ts +84 -0
  32. package/dist/job/accept.d.ts.map +1 -0
  33. package/dist/job/accept.js +136 -0
  34. package/dist/job/accept.js.map +1 -0
  35. package/dist/job/customer.d.ts +43 -0
  36. package/dist/job/customer.d.ts.map +1 -0
  37. package/dist/job/customer.js +83 -0
  38. package/dist/job/customer.js.map +1 -0
  39. package/dist/job/quote.d.ts +34 -0
  40. package/dist/job/quote.d.ts.map +1 -0
  41. package/dist/job/quote.js +37 -0
  42. package/dist/job/quote.js.map +1 -0
  43. package/dist/lock.d.ts +269 -0
  44. package/dist/lock.d.ts.map +1 -0
  45. package/dist/lock.js +283 -0
  46. package/dist/lock.js.map +1 -0
  47. package/dist/moderato.d.ts +27 -0
  48. package/dist/moderato.d.ts.map +1 -0
  49. package/dist/moderato.js +34 -0
  50. package/dist/moderato.js.map +1 -0
  51. package/dist/node/cli.d.ts +3 -0
  52. package/dist/node/cli.d.ts.map +1 -0
  53. package/dist/node/cli.js +346 -0
  54. package/dist/node/cli.js.map +1 -0
  55. package/dist/node/connect.d.ts +15 -0
  56. package/dist/node/connect.d.ts.map +1 -0
  57. package/dist/node/connect.js +83 -0
  58. package/dist/node/connect.js.map +1 -0
  59. package/dist/node/eval.d.ts +3 -0
  60. package/dist/node/eval.d.ts.map +1 -0
  61. package/dist/node/eval.js +67 -0
  62. package/dist/node/eval.js.map +1 -0
  63. package/dist/node/first-run.d.ts +50 -0
  64. package/dist/node/first-run.d.ts.map +1 -0
  65. package/dist/node/first-run.js +149 -0
  66. package/dist/node/first-run.js.map +1 -0
  67. package/dist/node/job.d.ts +50 -0
  68. package/dist/node/job.d.ts.map +1 -0
  69. package/dist/node/job.js +176 -0
  70. package/dist/node/job.js.map +1 -0
  71. package/dist/node/mailbox.d.ts +19 -0
  72. package/dist/node/mailbox.d.ts.map +1 -0
  73. package/dist/node/mailbox.js +81 -0
  74. package/dist/node/mailbox.js.map +1 -0
  75. package/dist/node/mcp.d.ts +74 -0
  76. package/dist/node/mcp.d.ts.map +1 -0
  77. package/dist/node/mcp.js +367 -0
  78. package/dist/node/mcp.js.map +1 -0
  79. package/dist/node/platform.d.ts +35 -0
  80. package/dist/node/platform.d.ts.map +1 -0
  81. package/dist/node/platform.js +102 -0
  82. package/dist/node/platform.js.map +1 -0
  83. package/dist/node/runner-session.d.ts +41 -0
  84. package/dist/node/runner-session.d.ts.map +1 -0
  85. package/dist/node/runner-session.js +100 -0
  86. package/dist/node/runner-session.js.map +1 -0
  87. package/dist/node/runner.d.ts +63 -0
  88. package/dist/node/runner.d.ts.map +1 -0
  89. package/dist/node/runner.js +341 -0
  90. package/dist/node/runner.js.map +1 -0
  91. package/dist/node/service-child.d.ts +2 -0
  92. package/dist/node/service-child.d.ts.map +1 -0
  93. package/dist/node/service-child.js +40 -0
  94. package/dist/node/service-child.js.map +1 -0
  95. package/dist/node/service-excerpt.d.ts +21 -0
  96. package/dist/node/service-excerpt.d.ts.map +1 -0
  97. package/dist/node/service-excerpt.js +32 -0
  98. package/dist/node/service-excerpt.js.map +1 -0
  99. package/dist/node/service-process.d.ts +12 -0
  100. package/dist/node/service-process.d.ts.map +1 -0
  101. package/dist/node/service-process.js +132 -0
  102. package/dist/node/service-process.js.map +1 -0
  103. package/dist/node/session-input.d.ts +12 -0
  104. package/dist/node/session-input.d.ts.map +1 -0
  105. package/dist/node/session-input.js +42 -0
  106. package/dist/node/session-input.js.map +1 -0
  107. package/dist/node/session-view.d.ts +20 -0
  108. package/dist/node/session-view.d.ts.map +1 -0
  109. package/dist/node/session-view.js +198 -0
  110. package/dist/node/session-view.js.map +1 -0
  111. package/dist/node-agent.d.ts +2 -0
  112. package/dist/node-agent.d.ts.map +1 -0
  113. package/dist/node-agent.js +6 -0
  114. package/dist/node-agent.js.map +1 -0
  115. package/dist/node.d.ts +2 -0
  116. package/dist/node.d.ts.map +1 -0
  117. package/dist/node.js +9 -0
  118. package/dist/node.js.map +1 -0
  119. package/dist/sandbox/agent.d.ts +187 -0
  120. package/dist/sandbox/agent.d.ts.map +1 -0
  121. package/dist/sandbox/agent.js +468 -0
  122. package/dist/sandbox/agent.js.map +1 -0
  123. package/dist/sandbox/business-store.d.ts +19 -0
  124. package/dist/sandbox/business-store.d.ts.map +1 -0
  125. package/dist/sandbox/business-store.js +19 -0
  126. package/dist/sandbox/business-store.js.map +1 -0
  127. package/dist/sandbox/business.d.ts +70 -0
  128. package/dist/sandbox/business.d.ts.map +1 -0
  129. package/dist/sandbox/business.js +115 -0
  130. package/dist/sandbox/business.js.map +1 -0
  131. package/dist/sandbox/connect.d.ts +59 -0
  132. package/dist/sandbox/connect.d.ts.map +1 -0
  133. package/dist/sandbox/connect.js +177 -0
  134. package/dist/sandbox/connect.js.map +1 -0
  135. package/dist/sandbox/deployment.d.ts +14 -0
  136. package/dist/sandbox/deployment.d.ts.map +1 -0
  137. package/dist/sandbox/deployment.js +38 -0
  138. package/dist/sandbox/deployment.js.map +1 -0
  139. package/dist/sandbox/keys.d.ts +45 -0
  140. package/dist/sandbox/keys.d.ts.map +1 -0
  141. package/dist/sandbox/keys.js +132 -0
  142. package/dist/sandbox/keys.js.map +1 -0
  143. package/dist/sandbox/mailbox.d.ts +90 -0
  144. package/dist/sandbox/mailbox.d.ts.map +1 -0
  145. package/dist/sandbox/mailbox.js +400 -0
  146. package/dist/sandbox/mailbox.js.map +1 -0
  147. package/dist/sandbox/mandate.d.ts +84 -0
  148. package/dist/sandbox/mandate.d.ts.map +1 -0
  149. package/dist/sandbox/mandate.js +107 -0
  150. package/dist/sandbox/mandate.js.map +1 -0
  151. package/dist/sandbox/namespace.d.ts +16 -0
  152. package/dist/sandbox/namespace.d.ts.map +1 -0
  153. package/dist/sandbox/namespace.js +16 -0
  154. package/dist/sandbox/namespace.js.map +1 -0
  155. package/dist/sandbox/session.d.ts +60 -0
  156. package/dist/sandbox/session.d.ts.map +1 -0
  157. package/dist/sandbox/session.js +94 -0
  158. package/dist/sandbox/session.js.map +1 -0
  159. package/dist/sandbox/setup.d.ts +136 -0
  160. package/dist/sandbox/setup.d.ts.map +1 -0
  161. package/dist/sandbox/setup.js +490 -0
  162. package/dist/sandbox/setup.js.map +1 -0
  163. package/dist/sandbox/store.d.ts +69 -0
  164. package/dist/sandbox/store.d.ts.map +1 -0
  165. package/dist/sandbox/store.js +115 -0
  166. package/dist/sandbox/store.js.map +1 -0
  167. package/dist/sandbox/supplier-key.d.ts +73 -0
  168. package/dist/sandbox/supplier-key.d.ts.map +1 -0
  169. package/dist/sandbox/supplier-key.js +180 -0
  170. package/dist/sandbox/supplier-key.js.map +1 -0
  171. package/dist/sandbox/suppliers.d.ts +7 -0
  172. package/dist/sandbox/suppliers.d.ts.map +1 -0
  173. package/dist/sandbox/suppliers.js +29 -0
  174. package/dist/sandbox/suppliers.js.map +1 -0
  175. package/dist/sandbox/terms.d.ts +32 -0
  176. package/dist/sandbox/terms.d.ts.map +1 -0
  177. package/dist/sandbox/terms.js +58 -0
  178. package/dist/sandbox/terms.js.map +1 -0
  179. package/dist/sandbox/vault.d.ts +24 -0
  180. package/dist/sandbox/vault.d.ts.map +1 -0
  181. package/dist/sandbox/vault.js +54 -0
  182. package/dist/sandbox/vault.js.map +1 -0
  183. package/dist/send.d.ts +122 -0
  184. package/dist/send.d.ts.map +1 -0
  185. package/dist/send.js +328 -0
  186. package/dist/send.js.map +1 -0
  187. package/dist/service-entry.d.ts +6 -0
  188. package/dist/service-entry.d.ts.map +1 -0
  189. package/dist/service-entry.js +6 -0
  190. package/dist/service-entry.js.map +1 -0
  191. package/dist/session/anthropic.d.ts +17 -0
  192. package/dist/session/anthropic.d.ts.map +1 -0
  193. package/dist/session/anthropic.js +215 -0
  194. package/dist/session/anthropic.js.map +1 -0
  195. package/dist/session/charge.d.ts +13 -0
  196. package/dist/session/charge.d.ts.map +1 -0
  197. package/dist/session/charge.js +33 -0
  198. package/dist/session/charge.js.map +1 -0
  199. package/dist/session/data.d.ts +8 -0
  200. package/dist/session/data.d.ts.map +1 -0
  201. package/dist/session/data.js +20 -0
  202. package/dist/session/data.js.map +1 -0
  203. package/dist/session/eval.d.ts +41 -0
  204. package/dist/session/eval.d.ts.map +1 -0
  205. package/dist/session/eval.js +281 -0
  206. package/dist/session/eval.js.map +1 -0
  207. package/dist/session/executor.d.ts +80 -0
  208. package/dist/session/executor.d.ts.map +1 -0
  209. package/dist/session/executor.js +381 -0
  210. package/dist/session/executor.js.map +1 -0
  211. package/dist/session/fixture-world.d.ts +29 -0
  212. package/dist/session/fixture-world.d.ts.map +1 -0
  213. package/dist/session/fixture-world.js +708 -0
  214. package/dist/session/fixture-world.js.map +1 -0
  215. package/dist/session/live-world.d.ts +22 -0
  216. package/dist/session/live-world.d.ts.map +1 -0
  217. package/dist/session/live-world.js +329 -0
  218. package/dist/session/live-world.js.map +1 -0
  219. package/dist/session/ollama.d.ts +29 -0
  220. package/dist/session/ollama.d.ts.map +1 -0
  221. package/dist/session/ollama.js +177 -0
  222. package/dist/session/ollama.js.map +1 -0
  223. package/dist/session/provider.d.ts +79 -0
  224. package/dist/session/provider.d.ts.map +1 -0
  225. package/dist/session/provider.js +19 -0
  226. package/dist/session/provider.js.map +1 -0
  227. package/dist/session/scripted.d.ts +45 -0
  228. package/dist/session/scripted.d.ts.map +1 -0
  229. package/dist/session/scripted.js +236 -0
  230. package/dist/session/scripted.js.map +1 -0
  231. package/dist/session/selection.d.ts +37 -0
  232. package/dist/session/selection.d.ts.map +1 -0
  233. package/dist/session/selection.js +104 -0
  234. package/dist/session/selection.js.map +1 -0
  235. package/dist/session/service-check.d.ts +48 -0
  236. package/dist/session/service-check.d.ts.map +1 -0
  237. package/dist/session/service-check.js +86 -0
  238. package/dist/session/service-check.js.map +1 -0
  239. package/dist/session/service.d.ts +128 -0
  240. package/dist/session/service.d.ts.map +1 -0
  241. package/dist/session/service.js +150 -0
  242. package/dist/session/service.js.map +1 -0
  243. package/dist/session/session.d.ts +95 -0
  244. package/dist/session/session.d.ts.map +1 -0
  245. package/dist/session/session.js +312 -0
  246. package/dist/session/session.js.map +1 -0
  247. package/dist/session/toolbox.d.ts +69 -0
  248. package/dist/session/toolbox.d.ts.map +1 -0
  249. package/dist/session/toolbox.js +391 -0
  250. package/dist/session/toolbox.js.map +1 -0
  251. package/dist/session/tools.d.ts +45 -0
  252. package/dist/session/tools.d.ts.map +1 -0
  253. package/dist/session/tools.js +137 -0
  254. package/dist/session/tools.js.map +1 -0
  255. package/dist/session/world.d.ts +188 -0
  256. package/dist/session/world.d.ts.map +1 -0
  257. package/dist/session/world.js +2 -0
  258. package/dist/session/world.js.map +1 -0
  259. package/dist/sign.d.ts +19 -0
  260. package/dist/sign.d.ts.map +1 -0
  261. package/dist/sign.js +33 -0
  262. package/dist/sign.js.map +1 -0
  263. package/dist/supplier.d.ts +41 -0
  264. package/dist/supplier.d.ts.map +1 -0
  265. package/dist/supplier.js +57 -0
  266. package/dist/supplier.js.map +1 -0
  267. package/package.json +55 -3
@@ -0,0 +1,135 @@
1
+ import { type ChargeKind, type ContestReason, type ContestStatement, type ContestStatementAnswer, type ReasonCode } from '@avow-finance/spec';
2
+ import { type LockedBacking } from '@avow-finance/verifier';
3
+ import { type Address, type Chain, type Client, type Hex, type TransactionReceipt, type Transport } from 'viem';
4
+ import type { Account as TempoAccount } from 'viem/tempo';
5
+ import type { BusinessRecords } from './avow-api.js';
6
+ import { type Call } from './lock.js';
7
+ import { type OnSent, type SendLimits } from './send.js';
8
+ /**
9
+ * How long, in seconds, a contest sent now may take to land. The root key sends it on an expiring
10
+ * nonce, which viem keeps valid for 25 seconds from when it's prepared, so a contest of a pending
11
+ * charge goes out only while its window stays open that long past the latest block.
12
+ */
13
+ export declare const CONTEST_SEND_MARGIN = 25n;
14
+ /**
15
+ * Why the lock won't take the business's contest of a commitment in a block up to `landsBy`, by the
16
+ * chain's clock, or null when it will. The lock takes one contest per commitment, of a pending
17
+ * charge until its contest window closes, or of a report Avow hasn't confirmed or referred at any
18
+ * time. `contest` passes the latest block's time plus `CONTEST_SEND_MARGIN`.
19
+ */
20
+ export declare function contestProblem(held: LockedBacking, landsBy: bigint): ReasonCode | null;
21
+ /** What contesting a charge needs: the business account's root key, its lock and Avow. */
22
+ export interface ContestConfig {
23
+ /** A client for the chain the business's lock is on, with the chain's fee token set. */
24
+ client: Client<Transport, Chain>;
25
+ /** The business account's root key, the one key the lock takes a direct contest from. */
26
+ root: TempoAccount.RootAccount;
27
+ /** The business's lock. */
28
+ lock: Address;
29
+ /** Avow's records the root key gives the statement to, as `httpBusinessRecords` serves them. */
30
+ avow: BusinessRecords;
31
+ /**
32
+ * Sends calls from the root key, which pays its own fee, and resolves with the receipt once they
33
+ * land. By default the key signs locally and the hash is tracked through `sendOwn`, which throws
34
+ * a `SendError` when the transaction fails or its outcome is unknown. A test passes its own.
35
+ */
36
+ send?: (calls: readonly Call[], onSent: OnSent) => Promise<TransactionReceipt>;
37
+ limits?: SendLimits;
38
+ }
39
+ /** One contest the business makes. */
40
+ export interface ContestRequest {
41
+ commitmentId: Hex;
42
+ reason: ContestReason;
43
+ /** The business's account in its own words, which the statement carries. */
44
+ text: string;
45
+ /**
46
+ * Called with the statement and the contest transaction's hash before its bytes go out, and
47
+ * awaited, so a caller can keep what it needs to settle a run that stops before the end.
48
+ */
49
+ onSent?: (sent: SentContest) => unknown;
50
+ }
51
+ /** A contest whose transaction is going out, before anyone has seen it land. */
52
+ export interface SentContest {
53
+ statement: ContestStatement;
54
+ hash: Hex;
55
+ /** The first block time at which the transaction can no longer land, or null when it has none. */
56
+ validBefore: bigint | null;
57
+ }
58
+ /** A contest the lock took, with when it paused the charge and how long Avow has to rule. */
59
+ export interface LandedContest {
60
+ statement: ContestStatement;
61
+ statementHash: Hex;
62
+ transactionHash: Hex;
63
+ /** The charge the contested report names, with its amount in base units of the lock's token. */
64
+ charge: {
65
+ kind: ChargeKind;
66
+ amount: bigint;
67
+ };
68
+ /** When the lock paused the charge, which days 30 and 90 count from. */
69
+ pausedAt: bigint;
70
+ /** When Avow's ruling key stops, the pause plus the lock's `rulingKeyEnd`. Avow rules before it. */
71
+ ruleBy: bigint;
72
+ }
73
+ /** Whether Avow recorded the statement, with when, or the error that stopped it. */
74
+ export type StatementPosting = {
75
+ ok: true;
76
+ recordedAt: bigint;
77
+ } | {
78
+ ok: false;
79
+ error: Error;
80
+ };
81
+ /**
82
+ * A contest's outcome. A refusal comes before anything is sent. Once the lock takes the contest,
83
+ * it stands whatever happens to the statement, so the result carries the contest with whether Avow
84
+ * recorded the statement, which `postContestStatement` can give Avow again at any time.
85
+ */
86
+ export type ContestResult = {
87
+ ok: false;
88
+ reason: ReasonCode;
89
+ } | {
90
+ ok: true;
91
+ contest: LandedContest;
92
+ posted: StatementPosting;
93
+ };
94
+ /**
95
+ * How many times a statement goes to Avow while Avow doesn't see the contest final yet. With the
96
+ * default wait of two seconds between tries, that gives the contest's block about 18 seconds to
97
+ * reach Avow's node and become final, many times what Tempo's finality takes.
98
+ */
99
+ export declare const STATEMENT_TRIES = 10;
100
+ /**
101
+ * Gives Avow the statement for a contest the lock took, and returns Avow's answer. Avow records a
102
+ * statement only once the contest's block is final, and its node can be a block behind the one
103
+ * that gave the contest's receipt, so while Avow answers that the transaction holds no contest yet,
104
+ * it asks again, up to `STATEMENT_TRIES` times. Any other
105
+ * refusal, or no definite answer, throws an `AvowApiError`. Avow keeps one statement per
106
+ * commitment, so posting the same statement again is always safe.
107
+ */
108
+ export declare function postContestStatement(avow: BusinessRecords, contest: Pick<LandedContest, 'statement' | 'transactionHash'>, limits?: SendLimits): Promise<ContestStatementAnswer>;
109
+ /**
110
+ * Contests a charge with the business account's root key and gives Avow the statement. It reads
111
+ * the lock first and refuses, sending nothing, a commitment the lock doesn't hold
112
+ * (`chain.reserve_missing`), one already contested, one with no pending charge or standing report,
113
+ * and a pending charge whose contest window closes within `CONTEST_SEND_MARGIN` of the latest
114
+ * block's time, since a contest sent then could land too late. It also refuses a reason that
115
+ * doesn't answer the kind of charge reported and a statement the format doesn't take, since a
116
+ * contest can't be taken back. It throws, sending nothing, when the root key isn't
117
+ * the account that owns the lock.
118
+ *
119
+ * Then it sends the lock's `contest` from the root key, which pays its own fee, signed locally and
120
+ * tracked by its hash, with `onSent` told before the bytes go out. A send that fails or whose
121
+ * outcome is unknown throws the sender's `SendError`. Once the receipt shows the contest landed, it
122
+ * posts the statement to Avow, signed by the root key. The contest stands whether or not that
123
+ * works, so the result carries it either way, with whether Avow recorded the statement.
124
+ */
125
+ export declare function contest(config: ContestConfig, request: ContestRequest): Promise<ContestResult>;
126
+ /**
127
+ * Reads a contest a successful transaction carried, as `contest` returns it, so a caller that
128
+ * stopped after sending can settle it from the chain. The charge is the one the contested report
129
+ * named, read from the lock as of the contest's block, so a report the supplier filed after
130
+ * withdrawing that one never reads as the charge contested. It returns null when the transaction
131
+ * isn't on the chain, failed, or holds no contest of the statement's commitment from the lock, and
132
+ * throws when the transaction carried a contest with another reason, statement or report.
133
+ */
134
+ export declare function readLandedContest(config: Pick<ContestConfig, 'client' | 'lock'>, statement: ContestStatement, transactionHash: Hex): Promise<LandedContest | null>;
135
+ //# sourceMappingURL=contest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contest.d.ts","sourceRoot":"","sources":["../src/contest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ import { answersCharge, CONTEST_REASONS, contestStatementHash, parseContestStatement, } from '@avow-finance/spec';
2
+ import { contestInLogs, LOCK_ABI, readBacking, readContest, } from '@avow-finance/verifier';
3
+ import { isAddressEqual, } from 'viem';
4
+ import { getBlock, readContract } from 'viem/actions';
5
+ import { AvowApiError } from './http.js';
6
+ import { contestCall } from './lock.js';
7
+ import { SEND_LIMITS, sendOwn } from './send.js';
8
+ /**
9
+ * How long, in seconds, a contest sent now may take to land. The root key sends it on an expiring
10
+ * nonce, which viem keeps valid for 25 seconds from when it's prepared, so a contest of a pending
11
+ * charge goes out only while its window stays open that long past the latest block.
12
+ */
13
+ export const CONTEST_SEND_MARGIN = 25n;
14
+ /**
15
+ * Why the lock won't take the business's contest of a commitment in a block up to `landsBy`, by the
16
+ * chain's clock, or null when it will. The lock takes one contest per commitment, of a pending
17
+ * charge until its contest window closes, or of a report Avow hasn't confirmed or referred at any
18
+ * time. `contest` passes the latest block's time plus `CONTEST_SEND_MARGIN`.
19
+ */
20
+ export function contestProblem(held, landsBy) {
21
+ // A contest stays on record when the supplier withdraws the report, and a later report pauses
22
+ // at once, so a contested commitment the lock still holds takes no second contest.
23
+ if (held.contested && (held.state === 'paused' || held.state === 'accepted')) {
24
+ return 'contest.already_contested';
25
+ }
26
+ const pending = held.state === 'charge_pending';
27
+ if (!pending && !(held.state === 'accepted' && held.hasReport))
28
+ return 'contest.not_contestable';
29
+ if (pending && landsBy >= held.chargeStart + held.contestWindow)
30
+ return 'contest.window_closed';
31
+ return null;
32
+ }
33
+ /**
34
+ * How many times a statement goes to Avow while Avow doesn't see the contest final yet. With the
35
+ * default wait of two seconds between tries, that gives the contest's block about 18 seconds to
36
+ * reach Avow's node and become final, many times what Tempo's finality takes.
37
+ */
38
+ export const STATEMENT_TRIES = 10;
39
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
40
+ /** The latest block's time, which the lock judges a contest window by. */
41
+ async function chainTime(client) {
42
+ return (await getBlock(client, { blockTag: 'latest' })).timestamp;
43
+ }
44
+ /** The lock's `rulingKeyEnd`, which the factory fixed and no call changes. */
45
+ function rulingKeyEnd(client, lock) {
46
+ return readContract(client, { address: lock, abi: LOCK_ABI, functionName: 'rulingKeyEnd' });
47
+ }
48
+ /** The business account that owns the lock, the one account whose root key can contest on it. */
49
+ function lockAccount(client, lock) {
50
+ return readContract(client, { address: lock, abi: LOCK_ABI, functionName: 'account' });
51
+ }
52
+ /**
53
+ * The contest a statement made, from the lock's event and the report it named, or a throw when
54
+ * the event isn't the one the statement's contest logs or names another report. The lock logs its
55
+ * event in the transaction that took the contest, so an event that differs means the transaction
56
+ * carried another contest than the statement's.
57
+ */
58
+ function landedFrom(seen, statement, facts) {
59
+ const statementHash = contestStatementHash(statement);
60
+ const { kind, number, amount } = facts.report;
61
+ if (!seen ||
62
+ !kind ||
63
+ number !== statement.reportNumber ||
64
+ seen.reasonCode !== CONTEST_REASONS[statement.reason].code ||
65
+ seen.statementHash !== statementHash) {
66
+ throw new Error(`${facts.transactionHash} holds no contest of ${statement.commitmentId} with this statement`);
67
+ }
68
+ return {
69
+ statement,
70
+ statementHash,
71
+ transactionHash: facts.transactionHash,
72
+ charge: { kind, amount },
73
+ pausedAt: seen.pausedAt,
74
+ ruleBy: seen.pausedAt + facts.rulingKeyEnd,
75
+ };
76
+ }
77
+ /**
78
+ * Gives Avow the statement for a contest the lock took, and returns Avow's answer. Avow records a
79
+ * statement only once the contest's block is final, and its node can be a block behind the one
80
+ * that gave the contest's receipt, so while Avow answers that the transaction holds no contest yet,
81
+ * it asks again, up to `STATEMENT_TRIES` times. Any other
82
+ * refusal, or no definite answer, throws an `AvowApiError`. Avow keeps one statement per
83
+ * commitment, so posting the same statement again is always safe.
84
+ */
85
+ export async function postContestStatement(avow, contest, limits = SEND_LIMITS) {
86
+ for (let i = 1;; i++) {
87
+ try {
88
+ return await avow.postContestStatement({
89
+ statement: contest.statement,
90
+ contestedIn: contest.transactionHash,
91
+ });
92
+ }
93
+ catch (e) {
94
+ const unseen = e instanceof AvowApiError && e.reason === 'contest.not_on_chain';
95
+ if (!unseen || i >= STATEMENT_TRIES)
96
+ throw e;
97
+ await sleep(limits.wait);
98
+ }
99
+ }
100
+ }
101
+ /**
102
+ * Contests a charge with the business account's root key and gives Avow the statement. It reads
103
+ * the lock first and refuses, sending nothing, a commitment the lock doesn't hold
104
+ * (`chain.reserve_missing`), one already contested, one with no pending charge or standing report,
105
+ * and a pending charge whose contest window closes within `CONTEST_SEND_MARGIN` of the latest
106
+ * block's time, since a contest sent then could land too late. It also refuses a reason that
107
+ * doesn't answer the kind of charge reported and a statement the format doesn't take, since a
108
+ * contest can't be taken back. It throws, sending nothing, when the root key isn't
109
+ * the account that owns the lock.
110
+ *
111
+ * Then it sends the lock's `contest` from the root key, which pays its own fee, signed locally and
112
+ * tracked by its hash, with `onSent` told before the bytes go out. A send that fails or whose
113
+ * outcome is unknown throws the sender's `SendError`. Once the receipt shows the contest landed, it
114
+ * posts the statement to Avow, signed by the root key. The contest stands whether or not that
115
+ * works, so the result carries it either way, with whether Avow recorded the statement.
116
+ */
117
+ export async function contest(config, request) {
118
+ const { client, lock } = config;
119
+ const limits = config.limits ?? SEND_LIMITS;
120
+ const commitmentId = request.commitmentId.toLowerCase();
121
+ const [held, now, keyEnd, account] = await Promise.all([
122
+ readBacking(client, lock, commitmentId, 'buyer'),
123
+ chainTime(client),
124
+ rulingKeyEnd(client, lock),
125
+ lockAccount(client, lock),
126
+ ]);
127
+ if (!isAddressEqual(account, config.root.address)) {
128
+ throw new Error(`The lock ${lock} belongs to the account ${account}, so the root key ${config.root.address} can't contest on it`);
129
+ }
130
+ if (!held)
131
+ return { ok: false, reason: 'chain.reserve_missing' };
132
+ const problem = contestProblem(held, now + CONTEST_SEND_MARGIN);
133
+ if (problem)
134
+ return { ok: false, reason: problem };
135
+ if (!held.reportKind || !answersCharge(request.reason, held.reportKind)) {
136
+ return { ok: false, reason: 'contest.reason_not_for_charge' };
137
+ }
138
+ const parsed = parseContestStatement({
139
+ commitmentId,
140
+ side: 'buyer',
141
+ reportNumber: held.reportCount,
142
+ reason: request.reason,
143
+ text: request.text,
144
+ });
145
+ if (!parsed.ok)
146
+ return { ok: false, reason: parsed.reason };
147
+ const statement = parsed.value;
148
+ const send = config.send ??
149
+ ((calls, onSent) => sendOwn({ client, account: config.root, calls, onSent, limits }));
150
+ const receipt = await send([contestCall(lock, statement)], (hash, validBefore) => request.onSent?.({ statement, hash, validBefore }));
151
+ // The lock took the contest only while it named the report read above, so that's its charge.
152
+ const landed = landedFrom(contestInLogs(receipt.logs, lock, commitmentId, 'buyer'), statement, {
153
+ transactionHash: receipt.transactionHash,
154
+ report: { number: held.reportCount, kind: held.reportKind, amount: held.reportAmount },
155
+ rulingKeyEnd: keyEnd,
156
+ });
157
+ let posted;
158
+ try {
159
+ const answer = await postContestStatement(config.avow, landed, limits);
160
+ posted = { ok: true, recordedAt: answer.recordedAt };
161
+ }
162
+ catch (e) {
163
+ posted = { ok: false, error: e instanceof Error ? e : new Error(String(e)) };
164
+ }
165
+ return { ok: true, contest: landed, posted };
166
+ }
167
+ /**
168
+ * Reads a contest a successful transaction carried, as `contest` returns it, so a caller that
169
+ * stopped after sending can settle it from the chain. The charge is the one the contested report
170
+ * named, read from the lock as of the contest's block, so a report the supplier filed after
171
+ * withdrawing that one never reads as the charge contested. It returns null when the transaction
172
+ * isn't on the chain, failed, or holds no contest of the statement's commitment from the lock, and
173
+ * throws when the transaction carried a contest with another reason, statement or report.
174
+ */
175
+ export async function readLandedContest(config, statement, transactionHash) {
176
+ const { client, lock } = config;
177
+ const { commitmentId, side } = statement;
178
+ const [seen, keyEnd] = await Promise.all([
179
+ readContest(client, lock, commitmentId, side, transactionHash),
180
+ rulingKeyEnd(client, lock),
181
+ ]);
182
+ if (!seen)
183
+ return null;
184
+ return landedFrom(seen, statement, { transactionHash, report: seen.report, rulingKeyEnd: keyEnd });
185
+ }
186
+ //# sourceMappingURL=contest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contest.js","sourceRoot":"","sources":["../src/contest.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,161 @@
1
+ import { type ApiRequest, type AvowDomain, type Enrollment, type EnrollmentRequest, type Parsed, type ReasonCode, type RequestKey, type Signed, type SponsorshipRefusal, type SupplierAuthorizationAnswer } from '@avow-finance/spec';
2
+ import type { Address, Hex } from 'viem';
3
+ import type { PrivateKeyAccount } from 'viem/accounts';
4
+ import type { Account as TempoAccount } from 'viem/tempo';
5
+ import type { AgentKey } from './agent.js';
6
+ import type { AvowApi, AvowRecords, BusinessRecords } from './avow-api.js';
7
+ /**
8
+ * Avow's API refused a request, answered with something the client can't use, or gave no definite
9
+ * answer in time. `status` is the HTTP status, 0 when no answer came, and `reason` the reason code
10
+ * Avow gave, or the parser's reason for an answer that doesn't parse. `requestId` names the
11
+ * operation. Sending the same signed bytes again is always safe, since Avow answers an identical
12
+ * repeat without acting again.
13
+ */
14
+ export declare class AvowApiError extends Error {
15
+ readonly status: number;
16
+ readonly reason: ReasonCode | null;
17
+ readonly requestId: Hex;
18
+ /**
19
+ * Whether Avow answered definitely, with a refusal or an answer the client can't use. When it's
20
+ * false the client gave up with no definite answer, so Avow may still have recorded the request,
21
+ * and a caller shouldn't treat it as refused.
22
+ */
23
+ readonly definite: boolean;
24
+ /**
25
+ * What Avow's relay added to its refusal, such as when the key can ask again or which budget is
26
+ * spent, or null for any other answer.
27
+ */
28
+ readonly sponsorship: SponsorshipRefusal | null;
29
+ constructor(message: string, details: {
30
+ status: number;
31
+ reason: ReasonCode | null;
32
+ requestId: Hex;
33
+ definite: boolean;
34
+ sponsorship?: SponsorshipRefusal | null;
35
+ }, options?: {
36
+ cause?: unknown;
37
+ });
38
+ }
39
+ /** The reason Avow gave somewhere in an error's causes, such as its relay's refusal. */
40
+ export declare function relayReason(error: unknown): ReasonCode | null;
41
+ /** One resend of the same bytes after no definite answer, as `onResend` receives it. */
42
+ export interface AvowResend {
43
+ requestId: Hex;
44
+ /** The last answer's status, or 0 when none came. */
45
+ status: number;
46
+ /** The last answer's reason, when Avow gave one. */
47
+ reason: ReasonCode | null;
48
+ /** What happened to the last attempt. */
49
+ message: string;
50
+ /** Milliseconds until the bytes go again. */
51
+ waitMs: number;
52
+ }
53
+ export interface AvowRequestConfig {
54
+ /**
55
+ * The deployment's origin, such as `https://api.testnet.avow.finance`. It is the audience every
56
+ * request is signed for, so it can't carry a path, query or fragment.
57
+ */
58
+ baseUrl: string;
59
+ /** The key that signs every request: an agent's through `agentRequestKey`, or a supplier's. */
60
+ key: RequestKey;
61
+ /** Seconds each signed request stays valid, two minutes by default. Avow refuses more than five. */
62
+ requestValidity?: bigint;
63
+ /**
64
+ * Seconds the client keeps sending the same bytes while no definite answer comes, ten minutes by
65
+ * default. It keeps going past the request's expiry, since Avow answers an identical repeat of a
66
+ * request it has recorded, and says `message.expired` about one it never started.
67
+ */
68
+ retryFor?: bigint;
69
+ /** Milliseconds before the first resend, doubling up to 15 seconds. */
70
+ retryWait?: number;
71
+ /** Milliseconds one attempt may take before it's abandoned and sent again, 30 seconds by default. */
72
+ attemptTimeout?: number;
73
+ /** The clock, in unix seconds. The system clock by default. */
74
+ now?: () => bigint;
75
+ fetch?: typeof fetch;
76
+ /** Receives each signed request, so the signer can keep the record of what it asked Avow. */
77
+ onSigned?: (request: Signed<ApiRequest>) => void;
78
+ /** Hears about each resend before it waits, so a long run of them never goes unseen. */
79
+ onResend?: (resend: AvowResend) => void;
80
+ }
81
+ export interface HttpAvowApiConfig extends AvowRequestConfig {
82
+ /** The chain and lock the agent's mandate names. Every request is signed under this domain. */
83
+ domain: AvowDomain;
84
+ }
85
+ /** One operation for Avow's API. */
86
+ export interface AvowRequest<T> {
87
+ /** The chain and lock the request is signed under. */
88
+ domain: AvowDomain;
89
+ path: string;
90
+ body: unknown;
91
+ /**
92
+ * Parses the JSON body of a 2xx answer, or gives the reason it can't. Avow answers a repeat with
93
+ * the answer it recorded, so an answer this refuses would come back the same, and it's thrown at
94
+ * once with that reason. It gets the digest of the request it answers, which Avow's timestamps
95
+ * name, and the audience that request was signed for.
96
+ */
97
+ read: (json: unknown, sent: {
98
+ digest: Hex;
99
+ audience: string;
100
+ }) => Parsed<T>;
101
+ }
102
+ /** The agent's access key as a request signer: its own address and its bare signature. */
103
+ export declare function agentRequestKey(key: AgentKey): RequestKey;
104
+ /**
105
+ * The business account's root key as a request signer. Its address is the account's own, and a
106
+ * root key signs bare, so Avow reads the signature as the account's without a keychain envelope.
107
+ */
108
+ export declare function rootRequestKey(root: TempoAccount.RootAccount): RequestKey;
109
+ /**
110
+ * A supplier's signing key as a request signer, for the requests a supplier signs itself, such as
111
+ * asking Avow for an authorization or quoting the test customer. It's a plain key, so it signs bare.
112
+ */
113
+ export declare function signingRequestKey(key: PrivateKeyAccount): RequestKey;
114
+ /**
115
+ * Sends operations to Avow's hosted API, each with a fresh request id and signed with `key` for the
116
+ * deployment at `baseUrl`. It sends the same bytes again after no answer, an answer of any status
117
+ * whose body isn't JSON, a 5xx or `request.in_progress`, until Avow answers definitely or
118
+ * `retryFor` runs out. Avow answers with JSON whatever the status, so bytes that aren't JSON never
119
+ * came whole from Avow. Avow answers an identical repeat with its first answer and does nothing
120
+ * again, so a lost answer never turns into a second action. It never follows a redirect, so a
121
+ * signed body goes nowhere but the deployment it was signed for. A refusal, which is any other 4xx
122
+ * with a JSON body, a 2xx answer `read` refuses, or no definite answer in time, throws an
123
+ * `AvowApiError` with the reason.
124
+ */
125
+ export declare function avowRequests(config: AvowRequestConfig): <T>({ domain, path, body: value, read }: AvowRequest<T>) => Promise<T>;
126
+ /**
127
+ * Avow's hosted API as an `AvowApi`, for an agent whose mandate names `domain`. Each call is one
128
+ * operation sent through `avowRequests`, so a lost answer never turns into a second approval, a
129
+ * second co-signature or a second record. It serves the reserve check, the relay and Avow's records
130
+ * of cancellations and job starts. Each record's answer carries Avow's timestamp, which has to name
131
+ * the digest of the request the agent signed and the time the answer gives. A commitment already
132
+ * cancelled answers with the first cancellation, whose timestamp names the request that carried it,
133
+ * so `cancel` gives the first cancellation's time to every later call too.
134
+ */
135
+ export declare function httpAvowApi(config: HttpAvowApiConfig): AvowApi & {
136
+ records: AvowRecords;
137
+ };
138
+ /**
139
+ * Avow's hosted API as the records the business account's root key writes to, for the business
140
+ * whose lock `domain` names. Each call is one operation sent through `avowRequests`, signed with
141
+ * `key`, which `rootRequestKey` makes from the root key. A contest statement's answer has to name
142
+ * the hash of the statement sent.
143
+ */
144
+ export declare function httpBusinessRecords(config: HttpAvowApiConfig): BusinessRecords;
145
+ /**
146
+ * Enrolls an agent with Avow once its key is on the chain with the mandate's hash. The agent signs
147
+ * the request with that key, under the mandate's chain and lock, and gets back what Avow recorded.
148
+ */
149
+ export declare function enrollAgent(config: AvowRequestConfig, enrollment: EnrollmentRequest): Promise<Enrollment>;
150
+ /**
151
+ * Asks Avow for a fresh authorization for a commitment's reserve, signed with the supplier's
152
+ * signing key under the buyer's lock. Avow answers with its authorization, the approval the reserve
153
+ * was funded under and the buyer's mandate, which the supplier's verifier checks before it accepts,
154
+ * or with the reason it signed none, such as a reserve not funded yet.
155
+ */
156
+ export declare function requestSupplierAuthorization(config: AvowRequestConfig, commitment: {
157
+ chainId: number;
158
+ lock: Address;
159
+ commitmentId: Hex;
160
+ }): Promise<SupplierAuthorizationAnswer>;
161
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,UAAU,EACf,KAAK,UAAU,EAGf,KAAK,UAAU,EACf,KAAK,iBAAiB,EAItB,KAAK,MAAM,EAWX,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,MAAM,EACX,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAEjC,MAAM,oBAAoB,CAAA;AAC3B,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE1E;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,kBAAkB,GAAG,IAAI,CAAA;IAE/C,YACE,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;QACzB,SAAS,EAAE,GAAG,CAAA;QACd,QAAQ,EAAE,OAAO,CAAA;QACjB,WAAW,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAA;KACxC,EACD,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAS9B;CACF;AAED,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAO7D;AAED,wFAAwF;AACxF,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,GAAG,CAAA;IACd,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAA;IACd,oDAAoD;IACpD,MAAM,EAAE,UAAU,GAAG,IAAI,CAAA;IACzB,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAA;IACf,+FAA+F;IAC/F,GAAG,EAAE,UAAU,CAAA;IACf,oGAAoG;IACpG,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qGAAqG;IACrG,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;IAChD,wFAAwF;IACxF,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAA;CACxC;AAED,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,+FAA+F;IAC/F,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW,CAAC,CAAC;IAC5B,sDAAsD;IACtD,MAAM,EAAE,UAAU,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,OAAO,CAAA;IACb;;;;;OAKG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;QAAE,MAAM,EAAE,GAAG,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CAAA;CAC5E;AAED,0FAA0F;AAC1F,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,GAAG,UAAU,CAKzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,CAAC,WAAW,GAAG,UAAU,CAEzE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,GAAG,UAAU,CAEpE;AA8BD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,iBAAiB,IAazB,CAAC,uCAAuC,WAAW,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAAC,CAmF/F;AAMD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,GAAG;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,CA4DzF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,GAAG,eAAe,CAe9E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,UAAU,EAAE,iBAAiB,GAC5B,OAAO,CAAC,UAAU,CAAC,CAOrB;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,iBAAiB,EACzB,UAAU,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,YAAY,EAAE,GAAG,CAAA;CAAE,GAChE,OAAO,CAAC,2BAA2B,CAAC,CAQtC"}