@kasufinance/kasu-sdk 2.8.0 → 2.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -9
- package/dist/bundle.cjs.js +2077 -476
- package/dist/bundle.esm.js +2039 -478
- package/dist/domain/batch-proof.d.ts +210 -0
- package/dist/domain/batch-proof.js +384 -0
- package/dist/domain/batch-proof.js.map +1 -0
- package/dist/domain/explorer-urls.d.ts +33 -0
- package/dist/domain/explorer-urls.js +38 -0
- package/dist/domain/explorer-urls.js.map +1 -0
- package/dist/domain/fixed-term.d.ts +74 -0
- package/dist/domain/fixed-term.js +86 -0
- package/dist/domain/fixed-term.js.map +1 -0
- package/dist/domain/index.d.ts +12 -2
- package/dist/domain/index.js +7 -2
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/partners.d.ts +29 -0
- package/dist/domain/partners.js +20 -0
- package/dist/domain/partners.js.map +1 -1
- package/dist/domain/requests.d.ts +24 -0
- package/dist/domain/requests.js +33 -0
- package/dist/domain/requests.js.map +1 -1
- package/dist/domain/sponsored-calls.d.ts +74 -0
- package/dist/domain/sponsored-calls.js +156 -0
- package/dist/domain/sponsored-calls.js.map +1 -0
- package/dist/domain/yields.d.ts +121 -0
- package/dist/domain/yields.js +151 -0
- package/dist/domain/yields.js.map +1 -0
- package/dist/facade/calls.d.ts +59 -0
- package/dist/facade/calls.js +89 -0
- package/dist/facade/calls.js.map +1 -0
- package/dist/facade/chain-configs.js +5 -0
- package/dist/facade/chain-configs.js.map +1 -1
- package/dist/facade/flows.d.ts +24 -3
- package/dist/facade/flows.js +22 -2
- package/dist/facade/flows.js.map +1 -1
- package/dist/facade/index.d.ts +3 -1
- package/dist/facade/index.js +1 -0
- package/dist/facade/index.js.map +1 -1
- package/dist/facade/kasu.d.ts +8 -2
- package/dist/facade/kasu.js +17 -5
- package/dist/facade/kasu.js.map +1 -1
- package/dist/facade/strategies.d.ts +43 -2
- package/dist/facade/strategies.js +80 -4
- package/dist/facade/strategies.js.map +1 -1
- package/dist/facade/types.d.ts +18 -0
- package/dist/flows/batch-errors.d.ts +74 -0
- package/dist/flows/batch-errors.js +83 -0
- package/dist/flows/batch-errors.js.map +1 -0
- package/dist/flows/batch-submission.d.ts +223 -0
- package/dist/flows/batch-submission.js +321 -0
- package/dist/flows/batch-submission.js.map +1 -0
- package/dist/flows/deposit-flow.d.ts +13 -20
- package/dist/flows/deposit-flow.js +14 -25
- package/dist/flows/deposit-flow.js.map +1 -1
- package/dist/flows/index.d.ts +6 -2
- package/dist/flows/index.js +4 -2
- package/dist/flows/index.js.map +1 -1
- package/dist/flows/withdraw-flow.d.ts +95 -4
- package/dist/flows/withdraw-flow.js +107 -2
- package/dist/flows/withdraw-flow.js.map +1 -1
- package/dist/services/DataService/queries.js +1 -0
- package/dist/services/DataService/queries.js.map +1 -1
- package/dist/services/Portfolio/portfolio.js +11 -0
- package/dist/services/Portfolio/portfolio.js.map +1 -1
- package/dist/services/UserLending/user-lending.d.ts +13 -0
- package/dist/services/UserLending/user-lending.js +25 -4
- package/dist/services/UserLending/user-lending.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/batch-proof.ts +576 -0
- package/src/domain/explorer-urls.ts +74 -0
- package/src/domain/fixed-term.ts +115 -0
- package/src/domain/index.ts +56 -0
- package/src/domain/partners.ts +35 -0
- package/src/domain/requests.ts +37 -0
- package/src/domain/sponsored-calls.ts +213 -0
- package/src/domain/yields.ts +189 -0
- package/src/facade/calls.ts +135 -0
- package/src/facade/chain-configs.ts +5 -0
- package/src/facade/flows.ts +23 -2
- package/src/facade/index.ts +3 -0
- package/src/facade/kasu.ts +31 -2
- package/src/facade/strategies.ts +98 -7
- package/src/facade/types.ts +19 -0
- package/src/flows/batch-errors.ts +118 -0
- package/src/flows/batch-submission.ts +511 -0
- package/src/flows/deposit-flow.ts +27 -33
- package/src/flows/index.ts +33 -2
- package/src/flows/withdraw-flow.ts +219 -10
- package/src/services/DataService/queries.ts +1 -0
- package/src/services/Portfolio/portfolio.ts +14 -0
- package/src/services/UserLending/user-lending.ts +38 -10
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-errors.js","sourceRoot":"","sources":["../../src/flows/batch-errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGzC,YAAY,WAAmB,EAAE,OAAgB;QAC7C,KAAK,CACD,OAAO,aAAP,OAAO,cAAP,OAAO,GACH,kCACI,WAAW,CAAC,CAAC,CAAC,SAAS,WAAW,EAAE,CAAC,CAAC,CAAC,EAC3C,EAAE,CACT,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,yDAAyD;QACzD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC9D,CAAC;CACJ;AAiBD;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAI3C,YACI,IAAY,EACZ,OAA+B,EAC/B,OAA6B;QAE7B,KAAK,CAAC,oBAAoB,OAAO,KAAK,IAAI,GAAG,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,uDAAuD;QACvD,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;YAChC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,OAAO,EAAE;gBACjC,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,UAAU,EAAE,KAAK;gBACjB,QAAQ,EAAE,IAAI;gBACd,YAAY,EAAE,IAAI;aACrB,CAAC,CAAC;QACP,CAAC;QACD,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAChE,CAAC;CACJ;AAED;;;GAGG;AACH,MAAM,OAAO,iBAAkB,SAAQ,oBAAoB;IACvD,YAAY,IAAY,EAAE,OAA6B;QACnD,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAC7D,CAAC;CACJ;AAED,wFAAwF;AACxF,MAAM,UAAU,cAAc,CAAC,GAAY;IACvC,OAAO,GAAG,YAAY,oBAAoB,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CAAC,GAAY;IACnD,OAAO,CACH,GAAG,YAAY,kBAAkB,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,QAAQ,CACxE,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { DepositProof, DepositProofExpectation, ReceiptLike, UserOperationProof, UserOperationProofExpectation } from '../domain/batch-proof';
|
|
2
|
+
import { SponsoredCall } from '../domain/sponsored-calls';
|
|
3
|
+
import { WaitableTransaction } from './observable';
|
|
4
|
+
/**
|
|
5
|
+
* Submitting a sponsored atomic deposit batch, from the accepted calls to a
|
|
6
|
+
* PROVEN deposit — the polling policy and the outcome taxonomy, and nothing
|
|
7
|
+
* else. No relay vendor, no URL, no wallet: the app's ports do the I/O, and
|
|
8
|
+
* this decides what each answer MEANS.
|
|
9
|
+
*
|
|
10
|
+
* The one rule everything here serves: **an ambiguous result is never
|
|
11
|
+
* reported as failed.** "Failed" tells a lender to try again, and a batch that
|
|
12
|
+
* may already have moved the money must never invite a second deposit.
|
|
13
|
+
*/
|
|
14
|
+
/** One call of the batch. Structurally `BatchCall`. */
|
|
15
|
+
export interface SubmitBatchCall {
|
|
16
|
+
to: string;
|
|
17
|
+
data: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* One read of the submitted batch's status, already NORMALISED by the app's
|
|
21
|
+
* port — the vendor's status vocabulary stays in the app.
|
|
22
|
+
*/
|
|
23
|
+
export type BatchStatusRead =
|
|
24
|
+
/** Mined: a transaction hash exists. */
|
|
25
|
+
{
|
|
26
|
+
kind: 'mined';
|
|
27
|
+
txHash: string;
|
|
28
|
+
userOperationHash?: string | null;
|
|
29
|
+
}
|
|
30
|
+
/** The vendor says, definitively, that it reverted: nothing deposited. */
|
|
31
|
+
| {
|
|
32
|
+
kind: 'reverted';
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Final for the vendor but silent about the deposit, or the status read
|
|
36
|
+
* was refused: stop polling, outcome UNKNOWN (→ pending).
|
|
37
|
+
*/
|
|
38
|
+
| {
|
|
39
|
+
kind: 'unknown';
|
|
40
|
+
code: string;
|
|
41
|
+
}
|
|
42
|
+
/** Not there yet, replaced, or a transient failure: ask again. */
|
|
43
|
+
| {
|
|
44
|
+
kind: 'again';
|
|
45
|
+
userOperationHash?: string | null;
|
|
46
|
+
};
|
|
47
|
+
export interface BatchSubmissionPorts<R extends ReceiptLike = ReceiptLike> {
|
|
48
|
+
/**
|
|
49
|
+
* Hand the batch to the submitter; resolve with its transaction id once it
|
|
50
|
+
* is ACCEPTED.
|
|
51
|
+
*
|
|
52
|
+
* Throw `BatchRevertedError` when it is known to revert, and
|
|
53
|
+
* `BatchSubmissionError(code, 'failed')` ONLY when nothing was sent — no
|
|
54
|
+
* session, a refusal before broadcast. Any other throw is read as
|
|
55
|
+
* PENDING: this cannot know whether an unrecognised error left before or
|
|
56
|
+
* after the batch was accepted. Resending the same signed request after an
|
|
57
|
+
* ambiguous answer is the port's business (it owns the wire protocol).
|
|
58
|
+
*/
|
|
59
|
+
post(calls: readonly SubmitBatchCall[]): Promise<{
|
|
60
|
+
transactionId: string;
|
|
61
|
+
}>;
|
|
62
|
+
/** One status read. A throw is treated as `{ kind: 'again' }`. */
|
|
63
|
+
getStatus(transactionId: string): Promise<BatchStatusRead>;
|
|
64
|
+
/**
|
|
65
|
+
* The mined receipt. Bound it with a timeout of your own; a throw is
|
|
66
|
+
* PENDING (`receipt_unavailable`) — the batch was mined, its receipt was
|
|
67
|
+
* just not readable.
|
|
68
|
+
*/
|
|
69
|
+
getReceipt(txHash: string): Promise<R>;
|
|
70
|
+
/** ms epoch. */
|
|
71
|
+
now(): number;
|
|
72
|
+
sleep(ms: number): Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
export interface BatchPollingPolicy {
|
|
75
|
+
/** Delay before the second status read (the first is immediate). */
|
|
76
|
+
initialMs: number;
|
|
77
|
+
/** Ceiling on the delay between reads. */
|
|
78
|
+
maxMs: number;
|
|
79
|
+
/** Multiplier applied to the delay after each read, ≥ 1. */
|
|
80
|
+
backoff: number;
|
|
81
|
+
/** Stop polling — PENDING, never failed — after this long. */
|
|
82
|
+
timeoutMs: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* First read at once, then 3 s backing off ×1.5 to a 10 s ceiling, for up to
|
|
86
|
+
* 10 minutes. Running out of time is PENDING: the batch was accepted and may
|
|
87
|
+
* still land.
|
|
88
|
+
*/
|
|
89
|
+
export declare const DEFAULT_BATCH_POLLING_POLICY: Readonly<BatchPollingPolicy>;
|
|
90
|
+
/** A proven deposit: the `deposited` proof and the receipt it was read from. */
|
|
91
|
+
export interface ProvenBatch<R extends ReceiptLike = ReceiptLike> {
|
|
92
|
+
proof: Extract<DepositProof, {
|
|
93
|
+
kind: 'deposited';
|
|
94
|
+
}>;
|
|
95
|
+
receipt: R;
|
|
96
|
+
txHash: string;
|
|
97
|
+
}
|
|
98
|
+
/** What `submitBatch` resolves with once the batch is accepted. */
|
|
99
|
+
export interface BatchSubmission<R extends ReceiptLike = ReceiptLike> extends WaitableTransaction {
|
|
100
|
+
transactionId: string;
|
|
101
|
+
/**
|
|
102
|
+
* Polls to a mined receipt and proves the deposit in it. Resolves ONLY on
|
|
103
|
+
* a proven deposit. Rejects with `BatchRevertedError` when it definitively
|
|
104
|
+
* did not deposit, and with `BatchPendingError` for everything else.
|
|
105
|
+
*/
|
|
106
|
+
wait(): Promise<ProvenBatch<R>>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Submit `calls` and return once the submitter ACCEPTED them; `wait()` then
|
|
110
|
+
* polls and proves. Use it as the body of a `DepositFlow` `depositBatch`
|
|
111
|
+
* port, after `validateDepositBatchCalls` and the app's own signing:
|
|
112
|
+
*
|
|
113
|
+
* ```ts
|
|
114
|
+
* depositBatch: (calls) => {
|
|
115
|
+
* const { tranche, amount } = validateDepositBatchCalls(calls, expected);
|
|
116
|
+
* return submitBatch(
|
|
117
|
+
* // `pendingPool`: the strategy's pending pool, so only ITS
|
|
118
|
+
* // `DepositRequested` can prove the deposit.
|
|
119
|
+
* { calls, expect: { lender, tranche, amount, pendingPool } },
|
|
120
|
+
* { post, getStatus, getReceipt, now: Date.now, sleep },
|
|
121
|
+
* );
|
|
122
|
+
* },
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* | what happened | outcome |
|
|
126
|
+
* | ---------------------------------------------------- | ---------------------------------------- |
|
|
127
|
+
* | `post` throws `BatchRevertedError` | rethrown — reverted, nothing deposited |
|
|
128
|
+
* | `post` throws `BatchSubmissionError` | rethrown with its own outcome |
|
|
129
|
+
* | `post` throws anything else | `BatchPendingError('post_unknown')` |
|
|
130
|
+
* | `post` resolves without a transaction id | `BatchPendingError('malformed_answer')` |
|
|
131
|
+
* | status `reverted` | `BatchRevertedError('')` |
|
|
132
|
+
* | status `unknown` | `BatchPendingError(code)` |
|
|
133
|
+
* | polling runs out of time | `BatchPendingError('status_timeout')` |
|
|
134
|
+
* | receipt unreadable | `BatchPendingError('receipt_unavailable')` |
|
|
135
|
+
* | receipt: user operation reverted | `BatchRevertedError(revertError)` |
|
|
136
|
+
* | receipt: this deposit not shown | `BatchPendingError('deposit_unproven:<reason>')` |
|
|
137
|
+
* | receipt: this lender's deposit, tranche and amount | resolves `ProvenBatch` |
|
|
138
|
+
*
|
|
139
|
+
* Nothing on this path ever produces a `failed` outcome: by the time a batch
|
|
140
|
+
* has been posted, only a revert proves that nothing was deposited.
|
|
141
|
+
*/
|
|
142
|
+
export declare function submitBatch<R extends ReceiptLike = ReceiptLike>(input: {
|
|
143
|
+
calls: readonly SubmitBatchCall[];
|
|
144
|
+
/** What the receipt must show — see `proveDepositInReceipt`. */
|
|
145
|
+
expect: Omit<DepositProofExpectation, 'userOperationHash'>;
|
|
146
|
+
}, ports: BatchSubmissionPorts<R>, policy?: Partial<BatchPollingPolicy>): Promise<BatchSubmission<R>>;
|
|
147
|
+
/**
|
|
148
|
+
* What became of an earlier submission that ended PENDING — ONE status read,
|
|
149
|
+
* no polling — for an app's guard against lending twice:
|
|
150
|
+
*
|
|
151
|
+
* - `deposited` — mined, and the receipt proves the deposit;
|
|
152
|
+
* - `not-deposited` — definitively reverted (vendor status or the user
|
|
153
|
+
* operation's own flag);
|
|
154
|
+
* - `unknown` — anything else, including a read or receipt that failed.
|
|
155
|
+
*
|
|
156
|
+
* Only `not-deposited` may let a new lend proceed unprompted; `deposited`
|
|
157
|
+
* means the lender is told the earlier one landed (`already-submitted`).
|
|
158
|
+
*/
|
|
159
|
+
export declare function checkBatchOutcome<R extends ReceiptLike = ReceiptLike>(transactionId: string, expect: Omit<DepositProofExpectation, 'userOperationHash'>, ports: Pick<BatchSubmissionPorts<R>, 'getStatus' | 'getReceipt'>): Promise<'deposited' | 'not-deposited' | 'unknown'>;
|
|
160
|
+
/**
|
|
161
|
+
* `BatchSubmissionPorts` for ONE sponsored call: the same status, receipt and
|
|
162
|
+
* clock ports — a relay client written for the deposit batch serves both —
|
|
163
|
+
* with a `post` that receives the call together with its relay `kind`, so the
|
|
164
|
+
* app never maps one from the other.
|
|
165
|
+
*/
|
|
166
|
+
export interface SponsoredCallSubmissionPorts<R extends ReceiptLike = ReceiptLike> extends Omit<BatchSubmissionPorts<R>, 'post'> {
|
|
167
|
+
/**
|
|
168
|
+
* Hand the call to the submitter (`kind` and `[call]` in the relay's
|
|
169
|
+
* body); resolve with its transaction id once it is ACCEPTED. The same
|
|
170
|
+
* throw rules as `BatchSubmissionPorts.post`: `BatchRevertedError` when
|
|
171
|
+
* it is known to revert, `BatchSubmissionError(code, 'failed')` ONLY when
|
|
172
|
+
* nothing was sent, anything else is read as PENDING.
|
|
173
|
+
*/
|
|
174
|
+
post(call: SponsoredCall): Promise<{
|
|
175
|
+
transactionId: string;
|
|
176
|
+
}>;
|
|
177
|
+
}
|
|
178
|
+
/** An executed call: the `executed` proof and the receipt it was read from. */
|
|
179
|
+
export interface ExecutedCall<R extends ReceiptLike = ReceiptLike> {
|
|
180
|
+
proof: Extract<UserOperationProof, {
|
|
181
|
+
kind: 'executed';
|
|
182
|
+
}>;
|
|
183
|
+
receipt: R;
|
|
184
|
+
txHash: string;
|
|
185
|
+
}
|
|
186
|
+
/** What `submitSponsoredCall` resolves with once the call is accepted. */
|
|
187
|
+
export interface SponsoredCallSubmission<R extends ReceiptLike = ReceiptLike> extends WaitableTransaction {
|
|
188
|
+
transactionId: string;
|
|
189
|
+
/**
|
|
190
|
+
* Polls to a mined receipt and proves the sender's operation EXECUTED.
|
|
191
|
+
* Rejects with `BatchRevertedError` when it definitively did not, and
|
|
192
|
+
* with `BatchPendingError` for everything else.
|
|
193
|
+
*/
|
|
194
|
+
wait(): Promise<ExecutedCall<R>>;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* `submitBatch` for ONE sponsored `LendingPoolManager` call — the body of a
|
|
198
|
+
* `WithdrawFlow` `submitCall` port, and of an app's cancel or
|
|
199
|
+
* withdraw-at-expiry action. Same post, same polling policy, same outcome
|
|
200
|
+
* table; the proof is `proveUserOperationInReceipt` (the sender's operation
|
|
201
|
+
* succeeded) instead of the deposit proof, and an unproven receipt is
|
|
202
|
+
* `call_unproven:<reason>`.
|
|
203
|
+
*
|
|
204
|
+
* ```ts
|
|
205
|
+
* submitCall: (call) =>
|
|
206
|
+
* submitSponsoredCall(
|
|
207
|
+
* { call, expect: { sender: lender } },
|
|
208
|
+
* { post: (c) => postToMyRelay(c.kind, [c.call]), getStatus, getReceipt, now, sleep },
|
|
209
|
+
* ),
|
|
210
|
+
* ```
|
|
211
|
+
*
|
|
212
|
+
* The call is checked against its kind before anything is posted — a known
|
|
213
|
+
* kind, exactly `{ to, data }`, and `data` opening with that kind's selector —
|
|
214
|
+
* and a mismatch is `BatchSubmissionError('call_mismatch', 'failed')`: nothing
|
|
215
|
+
* was sent. Build calls with `kasu.calls`, and this never fires.
|
|
216
|
+
*
|
|
217
|
+
* As on the deposit path, nothing after the post ever produces `failed`.
|
|
218
|
+
*/
|
|
219
|
+
export declare function submitSponsoredCall<R extends ReceiptLike = ReceiptLike>(input: {
|
|
220
|
+
call: SponsoredCall;
|
|
221
|
+
/** Whose operation must have executed — see `proveUserOperationInReceipt`. */
|
|
222
|
+
expect: Omit<UserOperationProofExpectation, 'userOperationHash'>;
|
|
223
|
+
}, ports: SponsoredCallSubmissionPorts<R>, policy?: Partial<BatchPollingPolicy>): Promise<SponsoredCallSubmission<R>>;
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { proveDepositInReceipt, proveUserOperationInReceipt, } from '../domain/batch-proof';
|
|
11
|
+
import { SPONSORED_CALL_KINDS, SPONSORED_CALL_SELECTORS, } from '../domain/sponsored-calls';
|
|
12
|
+
import { BatchPendingError, BatchRevertedError, BatchSubmissionError, } from './batch-errors';
|
|
13
|
+
/**
|
|
14
|
+
* First read at once, then 3 s backing off ×1.5 to a 10 s ceiling, for up to
|
|
15
|
+
* 10 minutes. Running out of time is PENDING: the batch was accepted and may
|
|
16
|
+
* still land.
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_BATCH_POLLING_POLICY = Object.freeze({
|
|
19
|
+
initialMs: 3000,
|
|
20
|
+
maxMs: 10000,
|
|
21
|
+
backoff: 1.5,
|
|
22
|
+
timeoutMs: 10 * 60 * 1000,
|
|
23
|
+
});
|
|
24
|
+
function resolvePolicy(policy) {
|
|
25
|
+
var _a, _b, _c, _d;
|
|
26
|
+
const resolved = {
|
|
27
|
+
initialMs: (_a = policy === null || policy === void 0 ? void 0 : policy.initialMs) !== null && _a !== void 0 ? _a : DEFAULT_BATCH_POLLING_POLICY.initialMs,
|
|
28
|
+
maxMs: (_b = policy === null || policy === void 0 ? void 0 : policy.maxMs) !== null && _b !== void 0 ? _b : DEFAULT_BATCH_POLLING_POLICY.maxMs,
|
|
29
|
+
backoff: (_c = policy === null || policy === void 0 ? void 0 : policy.backoff) !== null && _c !== void 0 ? _c : DEFAULT_BATCH_POLLING_POLICY.backoff,
|
|
30
|
+
timeoutMs: (_d = policy === null || policy === void 0 ? void 0 : policy.timeoutMs) !== null && _d !== void 0 ? _d : DEFAULT_BATCH_POLLING_POLICY.timeoutMs,
|
|
31
|
+
};
|
|
32
|
+
const { initialMs, maxMs, backoff, timeoutMs } = resolved;
|
|
33
|
+
if (!(Number.isFinite(initialMs) && initialMs > 0) ||
|
|
34
|
+
!(Number.isFinite(maxMs) && maxMs >= initialMs) ||
|
|
35
|
+
!(Number.isFinite(backoff) && backoff >= 1) ||
|
|
36
|
+
!(Number.isFinite(timeoutMs) && timeoutMs > 0)) {
|
|
37
|
+
throw new TypeError('submitBatch: invalid polling policy');
|
|
38
|
+
}
|
|
39
|
+
return resolved;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Submit `calls` and return once the submitter ACCEPTED them; `wait()` then
|
|
43
|
+
* polls and proves. Use it as the body of a `DepositFlow` `depositBatch`
|
|
44
|
+
* port, after `validateDepositBatchCalls` and the app's own signing:
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* depositBatch: (calls) => {
|
|
48
|
+
* const { tranche, amount } = validateDepositBatchCalls(calls, expected);
|
|
49
|
+
* return submitBatch(
|
|
50
|
+
* // `pendingPool`: the strategy's pending pool, so only ITS
|
|
51
|
+
* // `DepositRequested` can prove the deposit.
|
|
52
|
+
* { calls, expect: { lender, tranche, amount, pendingPool } },
|
|
53
|
+
* { post, getStatus, getReceipt, now: Date.now, sleep },
|
|
54
|
+
* );
|
|
55
|
+
* },
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* | what happened | outcome |
|
|
59
|
+
* | ---------------------------------------------------- | ---------------------------------------- |
|
|
60
|
+
* | `post` throws `BatchRevertedError` | rethrown — reverted, nothing deposited |
|
|
61
|
+
* | `post` throws `BatchSubmissionError` | rethrown with its own outcome |
|
|
62
|
+
* | `post` throws anything else | `BatchPendingError('post_unknown')` |
|
|
63
|
+
* | `post` resolves without a transaction id | `BatchPendingError('malformed_answer')` |
|
|
64
|
+
* | status `reverted` | `BatchRevertedError('')` |
|
|
65
|
+
* | status `unknown` | `BatchPendingError(code)` |
|
|
66
|
+
* | polling runs out of time | `BatchPendingError('status_timeout')` |
|
|
67
|
+
* | receipt unreadable | `BatchPendingError('receipt_unavailable')` |
|
|
68
|
+
* | receipt: user operation reverted | `BatchRevertedError(revertError)` |
|
|
69
|
+
* | receipt: this deposit not shown | `BatchPendingError('deposit_unproven:<reason>')` |
|
|
70
|
+
* | receipt: this lender's deposit, tranche and amount | resolves `ProvenBatch` |
|
|
71
|
+
*
|
|
72
|
+
* Nothing on this path ever produces a `failed` outcome: by the time a batch
|
|
73
|
+
* has been posted, only a revert proves that nothing was deposited.
|
|
74
|
+
*/
|
|
75
|
+
export function submitBatch(input, ports, policy) {
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
const resolved = resolvePolicy(policy);
|
|
78
|
+
const transactionId = yield postOnce(() => ports.post(input.calls));
|
|
79
|
+
let settled = null;
|
|
80
|
+
return {
|
|
81
|
+
transactionId,
|
|
82
|
+
// Memoised: a second `wait()` reads the same outcome instead of
|
|
83
|
+
// polling the submitter twice.
|
|
84
|
+
wait: () => (settled !== null && settled !== void 0 ? settled : (settled = settle(transactionId, input.expect, ports, resolved))),
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The post, and what its answer means: the transaction id, or the error the
|
|
90
|
+
* outcome table names. Shared by both submitters, so the two cannot come to
|
|
91
|
+
* disagree about which throws are ambiguous.
|
|
92
|
+
*/
|
|
93
|
+
function postOnce(post) {
|
|
94
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
let accepted;
|
|
96
|
+
try {
|
|
97
|
+
accepted = yield post();
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
if (err instanceof BatchRevertedError)
|
|
101
|
+
throw err;
|
|
102
|
+
if (err instanceof BatchSubmissionError)
|
|
103
|
+
throw err;
|
|
104
|
+
throw new BatchPendingError('post_unknown', { cause: err });
|
|
105
|
+
}
|
|
106
|
+
const transactionId = accepted === null || accepted === void 0 ? void 0 : accepted.transactionId;
|
|
107
|
+
if (typeof transactionId !== 'string' || transactionId === '') {
|
|
108
|
+
throw new BatchPendingError('malformed_answer');
|
|
109
|
+
}
|
|
110
|
+
return transactionId;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function readStatus(ports, transactionId) {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
try {
|
|
116
|
+
return yield ports.getStatus(transactionId);
|
|
117
|
+
}
|
|
118
|
+
catch (_a) {
|
|
119
|
+
return { kind: 'again' };
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** Poll until a mined hash, or a typed reason there will not be one. */
|
|
124
|
+
function waitForMined(transactionId, ports, policy) {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
var _a;
|
|
127
|
+
const deadline = ports.now() + policy.timeoutMs;
|
|
128
|
+
let userOperationHash = null;
|
|
129
|
+
let delay = policy.initialMs;
|
|
130
|
+
for (;;) {
|
|
131
|
+
const read = yield readStatus(ports, transactionId);
|
|
132
|
+
switch (read.kind) {
|
|
133
|
+
case 'mined':
|
|
134
|
+
if (typeof read.txHash !== 'string' || read.txHash === '') {
|
|
135
|
+
break; // a malformed "mined" is not an answer; ask again
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
txHash: read.txHash,
|
|
139
|
+
userOperationHash: (_a = read.userOperationHash) !== null && _a !== void 0 ? _a : userOperationHash,
|
|
140
|
+
};
|
|
141
|
+
case 'reverted':
|
|
142
|
+
throw new BatchRevertedError('');
|
|
143
|
+
case 'unknown':
|
|
144
|
+
throw new BatchPendingError(read.code);
|
|
145
|
+
case 'again':
|
|
146
|
+
if (read.userOperationHash) {
|
|
147
|
+
userOperationHash = read.userOperationHash;
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
default:
|
|
151
|
+
// A read the port did not normalise: not an answer.
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
if (ports.now() + delay > deadline) {
|
|
155
|
+
throw new BatchPendingError('status_timeout');
|
|
156
|
+
}
|
|
157
|
+
yield ports.sleep(delay);
|
|
158
|
+
delay = Math.min(policy.maxMs, Math.round(delay * policy.backoff));
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/** Poll to a mined hash and read its receipt; a receipt read that throws is PENDING. */
|
|
163
|
+
function minedReceipt(transactionId, ports, policy) {
|
|
164
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
165
|
+
const mined = yield waitForMined(transactionId, ports, policy);
|
|
166
|
+
try {
|
|
167
|
+
return {
|
|
168
|
+
receipt: yield ports.getReceipt(mined.txHash),
|
|
169
|
+
txHash: mined.txHash,
|
|
170
|
+
userOperationHash: mined.userOperationHash,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
throw new BatchPendingError('receipt_unavailable', { cause: err });
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function settle(transactionId, expect, ports, policy) {
|
|
179
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
180
|
+
const mined = yield minedReceipt(transactionId, ports, policy);
|
|
181
|
+
let proof;
|
|
182
|
+
try {
|
|
183
|
+
proof = proveDepositInReceipt(mined.receipt, Object.assign(Object.assign({}, expect), { userOperationHash: mined.userOperationHash }));
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
// A receipt the proof cannot even read proves nothing either way.
|
|
187
|
+
throw new BatchPendingError('deposit_unproven', { cause: err });
|
|
188
|
+
}
|
|
189
|
+
if (proof.kind === 'reverted')
|
|
190
|
+
throw new BatchRevertedError(proof.revertError);
|
|
191
|
+
if (proof.kind === 'unproven') {
|
|
192
|
+
// The proof's reason rides in the code: "no-user-operation" (the hash
|
|
193
|
+
// is not this lender's operation at all) and "no-deposit-requested"
|
|
194
|
+
// (the operation ran and shows no deposit) are the two things an
|
|
195
|
+
// operator reading the alert needs to tell apart first.
|
|
196
|
+
throw new BatchPendingError(`deposit_unproven:${proof.reason}`);
|
|
197
|
+
}
|
|
198
|
+
return { proof, receipt: mined.receipt, txHash: mined.txHash };
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* What became of an earlier submission that ended PENDING — ONE status read,
|
|
203
|
+
* no polling — for an app's guard against lending twice:
|
|
204
|
+
*
|
|
205
|
+
* - `deposited` — mined, and the receipt proves the deposit;
|
|
206
|
+
* - `not-deposited` — definitively reverted (vendor status or the user
|
|
207
|
+
* operation's own flag);
|
|
208
|
+
* - `unknown` — anything else, including a read or receipt that failed.
|
|
209
|
+
*
|
|
210
|
+
* Only `not-deposited` may let a new lend proceed unprompted; `deposited`
|
|
211
|
+
* means the lender is told the earlier one landed (`already-submitted`).
|
|
212
|
+
*/
|
|
213
|
+
export function checkBatchOutcome(transactionId, expect, ports) {
|
|
214
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
215
|
+
var _a;
|
|
216
|
+
let read;
|
|
217
|
+
try {
|
|
218
|
+
read = yield ports.getStatus(transactionId);
|
|
219
|
+
}
|
|
220
|
+
catch (_b) {
|
|
221
|
+
return 'unknown';
|
|
222
|
+
}
|
|
223
|
+
if (read.kind === 'reverted')
|
|
224
|
+
return 'not-deposited';
|
|
225
|
+
if (read.kind !== 'mined' || typeof read.txHash !== 'string') {
|
|
226
|
+
return 'unknown';
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
const receipt = yield ports.getReceipt(read.txHash);
|
|
230
|
+
const proof = proveDepositInReceipt(receipt, Object.assign(Object.assign({}, expect), { userOperationHash: (_a = read.userOperationHash) !== null && _a !== void 0 ? _a : null }));
|
|
231
|
+
if (proof.kind === 'deposited')
|
|
232
|
+
return 'deposited';
|
|
233
|
+
if (proof.kind === 'reverted')
|
|
234
|
+
return 'not-deposited';
|
|
235
|
+
return 'unknown';
|
|
236
|
+
}
|
|
237
|
+
catch (_c) {
|
|
238
|
+
return 'unknown';
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* `submitBatch` for ONE sponsored `LendingPoolManager` call — the body of a
|
|
244
|
+
* `WithdrawFlow` `submitCall` port, and of an app's cancel or
|
|
245
|
+
* withdraw-at-expiry action. Same post, same polling policy, same outcome
|
|
246
|
+
* table; the proof is `proveUserOperationInReceipt` (the sender's operation
|
|
247
|
+
* succeeded) instead of the deposit proof, and an unproven receipt is
|
|
248
|
+
* `call_unproven:<reason>`.
|
|
249
|
+
*
|
|
250
|
+
* ```ts
|
|
251
|
+
* submitCall: (call) =>
|
|
252
|
+
* submitSponsoredCall(
|
|
253
|
+
* { call, expect: { sender: lender } },
|
|
254
|
+
* { post: (c) => postToMyRelay(c.kind, [c.call]), getStatus, getReceipt, now, sleep },
|
|
255
|
+
* ),
|
|
256
|
+
* ```
|
|
257
|
+
*
|
|
258
|
+
* The call is checked against its kind before anything is posted — a known
|
|
259
|
+
* kind, exactly `{ to, data }`, and `data` opening with that kind's selector —
|
|
260
|
+
* and a mismatch is `BatchSubmissionError('call_mismatch', 'failed')`: nothing
|
|
261
|
+
* was sent. Build calls with `kasu.calls`, and this never fires.
|
|
262
|
+
*
|
|
263
|
+
* As on the deposit path, nothing after the post ever produces `failed`.
|
|
264
|
+
*/
|
|
265
|
+
export function submitSponsoredCall(input, ports, policy) {
|
|
266
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
267
|
+
const resolved = resolvePolicy(policy);
|
|
268
|
+
if (!isWellFormedSponsoredCall(input.call)) {
|
|
269
|
+
throw new BatchSubmissionError('call_mismatch', 'failed');
|
|
270
|
+
}
|
|
271
|
+
const transactionId = yield postOnce(() => ports.post(input.call));
|
|
272
|
+
let settled = null;
|
|
273
|
+
return {
|
|
274
|
+
transactionId,
|
|
275
|
+
wait: () => (settled !== null && settled !== void 0 ? settled : (settled = settleCall(transactionId, input.expect, ports, resolved))),
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
function isWellFormedSponsoredCall(value) {
|
|
280
|
+
if (value === null || typeof value !== 'object')
|
|
281
|
+
return false;
|
|
282
|
+
const { kind, call } = value;
|
|
283
|
+
if (typeof kind !== 'string' ||
|
|
284
|
+
!SPONSORED_CALL_KINDS.includes(kind)) {
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
287
|
+
if (call === null || typeof call !== 'object')
|
|
288
|
+
return false;
|
|
289
|
+
const keys = Object.keys(call);
|
|
290
|
+
if (keys.length !== 2 || !keys.includes('to') || !keys.includes('data')) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
const { to, data } = call;
|
|
294
|
+
return (typeof to === 'string' &&
|
|
295
|
+
/^0x[0-9a-fA-F]{40}$/.test(to) &&
|
|
296
|
+
typeof data === 'string' &&
|
|
297
|
+
/^0x(?:[0-9a-fA-F]{2})*$/.test(data) &&
|
|
298
|
+
data
|
|
299
|
+
.toLowerCase()
|
|
300
|
+
.startsWith(SPONSORED_CALL_SELECTORS[kind]));
|
|
301
|
+
}
|
|
302
|
+
function settleCall(transactionId, expect, ports, policy) {
|
|
303
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
304
|
+
const mined = yield minedReceipt(transactionId, ports, policy);
|
|
305
|
+
let proof;
|
|
306
|
+
try {
|
|
307
|
+
proof = proveUserOperationInReceipt(mined.receipt, Object.assign(Object.assign({}, expect), { userOperationHash: mined.userOperationHash }));
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
throw new BatchPendingError('call_unproven', { cause: err });
|
|
311
|
+
}
|
|
312
|
+
if (proof.kind === 'reverted') {
|
|
313
|
+
throw new BatchRevertedError(proof.revertError);
|
|
314
|
+
}
|
|
315
|
+
if (proof.kind === 'unproven') {
|
|
316
|
+
throw new BatchPendingError(`call_unproven:${proof.reason}`);
|
|
317
|
+
}
|
|
318
|
+
return { proof, receipt: mined.receipt, txHash: mined.txHash };
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=batch-submission.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-submission.js","sourceRoot":"","sources":["../../src/flows/batch-submission.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BigNumber } from 'ethers';
|
|
2
2
|
import { GenerateContractResponse } from '../domain/loan-contract';
|
|
3
3
|
import { DepositParams, KycParams } from '../facade/types';
|
|
4
|
+
import { BatchRevertedError } from './batch-errors';
|
|
4
5
|
import { Flow } from './flow';
|
|
5
6
|
import { WaitableTransaction } from './observable';
|
|
6
7
|
/**
|
|
@@ -142,6 +143,17 @@ export type DepositFailure = {
|
|
|
142
143
|
} | {
|
|
143
144
|
step: 'request';
|
|
144
145
|
reason: 'contract-expired';
|
|
146
|
+
} | {
|
|
147
|
+
step: 'request';
|
|
148
|
+
/**
|
|
149
|
+
* Batch path only — a `BatchSubmissionError` whose outcome is not
|
|
150
|
+
* `failed`. `pending`: the batch was, or may have been, accepted and
|
|
151
|
+
* nothing proves whether it deposited — NEVER render it as a
|
|
152
|
+
* failure, which invites a second deposit. `already-submitted`: an
|
|
153
|
+
* earlier submission was proven, so this one was refused.
|
|
154
|
+
*/
|
|
155
|
+
reason: 'pending' | 'already-submitted';
|
|
156
|
+
error: unknown;
|
|
145
157
|
};
|
|
146
158
|
export type { WaitableTransaction };
|
|
147
159
|
/**
|
|
@@ -152,26 +164,7 @@ export interface BatchCall {
|
|
|
152
164
|
to: string;
|
|
153
165
|
data: string;
|
|
154
166
|
}
|
|
155
|
-
|
|
156
|
-
* What a `depositBatch` port throws when it KNOWS the batch reverted — from a
|
|
157
|
-
* simulation before sending, or from the submitter refusing to broadcast a
|
|
158
|
-
* batch that would revert. The run ends `{ step: 'request', reason:
|
|
159
|
-
* 'reverted', revertError }`.
|
|
160
|
-
*
|
|
161
|
-
* `revertError` is the custom error the contract named (`'ClearingIsPending'`,
|
|
162
|
-
* `'UserNotKycd'`, …), exactly as the ABI declares it. Pass `''` when the
|
|
163
|
-
* batch is known to revert but not why: the consumer then renders its generic
|
|
164
|
-
* `reverted` copy, which is what an unknown name gets anyway.
|
|
165
|
-
*
|
|
166
|
-
* Any OTHER throw from the port is read the way a direct deposit's is — a
|
|
167
|
-
* wallet rejection is `cancelled`, a decodable revert is `reverted`, and
|
|
168
|
-
* everything else is `failed` with the error kept. A port that cannot tell is
|
|
169
|
-
* better off throwing what it has than guessing a name.
|
|
170
|
-
*/
|
|
171
|
-
export declare class BatchRevertedError extends Error {
|
|
172
|
-
readonly revertError: string;
|
|
173
|
-
constructor(revertError: string, message?: string);
|
|
174
|
-
}
|
|
167
|
+
export { BatchRevertedError };
|
|
175
168
|
/** What the KYC signing service hands back. */
|
|
176
169
|
export interface KycSignature {
|
|
177
170
|
signature: string;
|