@kasufinance/kasu-sdk 2.7.0 → 2.7.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 +43 -5
- package/dist/bundle.cjs.js +281 -14
- package/dist/bundle.esm.js +278 -15
- package/dist/domain/index.d.ts +2 -0
- package/dist/domain/index.js +1 -0
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/revert-errors.d.ts +59 -0
- package/dist/domain/revert-errors.js +190 -0
- package/dist/domain/revert-errors.js.map +1 -0
- package/dist/flows/deposit-flow.d.ts +35 -4
- package/dist/flows/deposit-flow.js +89 -11
- package/dist/flows/deposit-flow.js.map +1 -1
- package/dist/flows/index.d.ts +1 -1
- package/dist/flows/index.js +1 -1
- package/dist/flows/index.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/index.ts +3 -0
- package/src/domain/revert-errors.ts +248 -0
- package/src/flows/deposit-flow.ts +125 -16
- package/src/flows/index.ts +2 -0
package/README.md
CHANGED
|
@@ -147,7 +147,8 @@ application formats them in its own design system and language.
|
|
|
147
147
|
| Requests | `deriveRequestState`, `submissionEvents`, `countSubmissions`, `firstSubmissionTimestamp`, `isCycleClosed` |
|
|
148
148
|
| Settlement | `computeSettlementWindow`, `nextCycleBoundary`, `deriveCycleDates`, `CLEARING_WINDOW_SECONDS` |
|
|
149
149
|
| Loan contract | `encodeDepositData`, `buildContractVersionType`, `buildLoanAgreementSignMessage`, `buildLegacyContractRequestMessage`, `buildFullNameRequestMessage`, `formatSignTimestampUtc`, `parseFormattedMessage`, `asContractType` |
|
|
150
|
-
| Wallet errors | `isUserRejected`, `isUnpredictableGas`
|
|
150
|
+
| Wallet errors | `isUserRejected`, `isUnpredictableGas`, `classifyWalletFailure` |
|
|
151
|
+
| Revert errors | `decodeRevert`, `extractRevertData` — the bytes a reverted call came back with, read as the custom error the contract named |
|
|
151
152
|
| AU minimum | `auMinimumRemaining`, `isAustralianKyc`, `auThresholdFor`, `isAuMinimumExempt`, `parseMinorUnits`, `AU_ALPHA3`, `AU_MIN_CUMULATIVE_BY_STABLE` |
|
|
152
153
|
|
|
153
154
|
Three rules worth knowing:
|
|
@@ -239,14 +240,51 @@ type DepositFailure =
|
|
|
239
240
|
| { step: DepositStep; reason: 'cancelled' } // isUserRejected
|
|
240
241
|
| { step: DepositStep; reason: 'failed'; error: unknown }
|
|
241
242
|
| { step: 'request'; reason: 'insufficient-balance'; error: unknown }
|
|
243
|
+
| {
|
|
244
|
+
step: 'request';
|
|
245
|
+
reason: 'reverted';
|
|
246
|
+
revertError: string; // e.g. 'ClearingIsPending'
|
|
247
|
+
error: unknown;
|
|
248
|
+
}
|
|
242
249
|
| { step: 'request'; reason: 'contract-expired' }; // the 5-minute TTL
|
|
243
250
|
```
|
|
244
251
|
|
|
245
252
|
A wallet rejection is `cancelled`, not a failure: the lender changed their
|
|
246
|
-
mind, and telling them something broke would be a lie.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
253
|
+
mind, and telling them something broke would be a lie. Everything else is
|
|
254
|
+
`failed` and carries the original error for your crash reporter.
|
|
255
|
+
|
|
256
|
+
A revert on the request step is read for WHAT reverted. `requestDepositWithKyc`
|
|
257
|
+
reverts for a family of reasons the ABI declares — `LendingPoolIsStopped`,
|
|
258
|
+
`ClearingIsPending`, `InvalidTranche`, `UserNotKycd`, `UserBlocked`,
|
|
259
|
+
`UserNotInAllowList`, `BlockExpired` — and none of them is a shortfall. Those
|
|
260
|
+
come back as `reverted`, with `revertError` naming the contract error. Only a
|
|
261
|
+
token balance or allowance failure, or revert data nothing can decode, is
|
|
262
|
+
`insufficient-balance`.
|
|
263
|
+
|
|
264
|
+
**Render `reverted` with generic copy and special-case only the names you have
|
|
265
|
+
words for.** A contract upgrade can add an error, so treat the set as open: a
|
|
266
|
+
consumer that assumed it was closed has nothing to show for a new one.
|
|
267
|
+
`decodeRevert(err)` is exported if you want the same reading elsewhere.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
if (failure.reason === 'reverted') {
|
|
271
|
+
switch (failure.revertError) {
|
|
272
|
+
case 'ClearingIsPending':
|
|
273
|
+
return t('deposit.error.clearing');
|
|
274
|
+
case 'UserNotKycd':
|
|
275
|
+
return t('deposit.error.kyc');
|
|
276
|
+
default:
|
|
277
|
+
return t('deposit.error.rejectedOnChain'); // generic
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Both personal signs are length-checked where they are taken.** A wallet is
|
|
283
|
+
not obliged to return 65 bytes and the ABI coder will not catch one that does
|
|
284
|
+
not — `0x` encodes into `depositData` as happily as a real signature does, and
|
|
285
|
+
the agreements service could then never verify the deposit. A malformed auth
|
|
286
|
+
signature fails the `generate` step and a malformed acceptance signature fails
|
|
287
|
+
`confirm`, both as `failed`, before anything is broadcast.
|
|
250
288
|
|
|
251
289
|
Three guarantees worth knowing:
|
|
252
290
|
|
package/dist/bundle.cjs.js
CHANGED
|
@@ -20837,12 +20837,12 @@ function toURLEncodedForm(data, options) {
|
|
|
20837
20837
|
});
|
|
20838
20838
|
}
|
|
20839
20839
|
|
|
20840
|
-
const MAX_DEPTH = DEFAULT_FORM_DATA_MAX_DEPTH;
|
|
20840
|
+
const MAX_DEPTH$1 = DEFAULT_FORM_DATA_MAX_DEPTH;
|
|
20841
20841
|
|
|
20842
20842
|
function throwIfDepthExceeded(index) {
|
|
20843
|
-
if (index > MAX_DEPTH) {
|
|
20843
|
+
if (index > MAX_DEPTH$1) {
|
|
20844
20844
|
throw new AxiosError$1(
|
|
20845
|
-
'FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH,
|
|
20845
|
+
'FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH$1,
|
|
20846
20846
|
AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED
|
|
20847
20847
|
);
|
|
20848
20848
|
}
|
|
@@ -24806,6 +24806,193 @@ function buildFullNameRequestMessage(address, timestampMs) {
|
|
|
24806
24806
|
return `I request my full name for ${address.toLowerCase()} at ${timestampMs}.`;
|
|
24807
24807
|
}
|
|
24808
24808
|
|
|
24809
|
+
// ---------------------------------------------------------------------------
|
|
24810
|
+
// The selector tables
|
|
24811
|
+
// ---------------------------------------------------------------------------
|
|
24812
|
+
/**
|
|
24813
|
+
* OpenZeppelin v5's ERC-20 errors. They are not in either Kasu ABI because no
|
|
24814
|
+
* Kasu contract declares them — they arrive from the TOKEN, through the
|
|
24815
|
+
* manager's `transferFrom`, and they are the modern spelling of the string
|
|
24816
|
+
* reverts below.
|
|
24817
|
+
*/
|
|
24818
|
+
const ERC20_ERROR_ABI = [
|
|
24819
|
+
'error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed)',
|
|
24820
|
+
'error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)',
|
|
24821
|
+
];
|
|
24822
|
+
/**
|
|
24823
|
+
* The protocol errors that mean the ERC-20 transfer failed rather than the
|
|
24824
|
+
* protocol refusing.
|
|
24825
|
+
*
|
|
24826
|
+
* `SafeERC20FailedOperation` is OpenZeppelin's wrapper around a token call
|
|
24827
|
+
* that returned false or reverted, which on this path IS the `transferFrom`;
|
|
24828
|
+
* `AddressInsufficientBalance` is its native-value sibling. Both belong with
|
|
24829
|
+
* the balance case, not with the pool conditions — a lender who sees one of
|
|
24830
|
+
* them really does need to fund or re-approve.
|
|
24831
|
+
*/
|
|
24832
|
+
const ERC20_FAMILY_NAMES = new Set([
|
|
24833
|
+
'AddressInsufficientBalance',
|
|
24834
|
+
'ERC20InsufficientAllowance',
|
|
24835
|
+
'ERC20InsufficientBalance',
|
|
24836
|
+
'SafeERC20FailedOperation',
|
|
24837
|
+
]);
|
|
24838
|
+
/** Solidity's `Error(string)`, the selector every `require` reason arrives under. */
|
|
24839
|
+
const STRING_REVERT_SELECTOR = '0x08c379a0';
|
|
24840
|
+
/**
|
|
24841
|
+
* The `require` reasons that are a balance or an allowance, across the token
|
|
24842
|
+
* implementations in circulation: OpenZeppelin v4's sentences, and the
|
|
24843
|
+
* shorthand the minimal implementations use.
|
|
24844
|
+
*/
|
|
24845
|
+
const ERC20_REASON_PATTERNS = [
|
|
24846
|
+
/exceeds\s+balance/,
|
|
24847
|
+
/exceeds\s+allowance/,
|
|
24848
|
+
/insufficient\s+balance/,
|
|
24849
|
+
/insufficient\s+allowance/,
|
|
24850
|
+
/transfer_from_failed/,
|
|
24851
|
+
/transferfrom\s+failed/,
|
|
24852
|
+
/low-level\s+call\s+failed/,
|
|
24853
|
+
];
|
|
24854
|
+
/**
|
|
24855
|
+
* selector → error name, built once on first use.
|
|
24856
|
+
*
|
|
24857
|
+
* Lazily, because a consumer that never sees a revert should not pay for three
|
|
24858
|
+
* `Interface` constructions at import. The two Kasu tables are the GENERATED
|
|
24859
|
+
* typechain ABIs, so this cannot drift from the contracts: regenerate the ABIs
|
|
24860
|
+
* and the new errors are recognised with no edit here.
|
|
24861
|
+
*/
|
|
24862
|
+
let selectorTable = null;
|
|
24863
|
+
function selectors() {
|
|
24864
|
+
if (selectorTable)
|
|
24865
|
+
return selectorTable;
|
|
24866
|
+
const table = new Map();
|
|
24867
|
+
const interfaces = [
|
|
24868
|
+
// The manager the deposit is called against, and the allow list it
|
|
24869
|
+
// delegates the KYC and block-window checks to.
|
|
24870
|
+
ILendingPoolManagerAbi__factory.createInterface(),
|
|
24871
|
+
IKasuAllowListAbi__factory.createInterface(),
|
|
24872
|
+
new ethers.ethers.utils.Interface(ERC20_ERROR_ABI),
|
|
24873
|
+
];
|
|
24874
|
+
for (const iface of interfaces) {
|
|
24875
|
+
for (const fragment of Object.values(iface.errors)) {
|
|
24876
|
+
// First writer wins: the same name declared by both ABIs is the
|
|
24877
|
+
// same selector, so the duplicate would be a no-op anyway.
|
|
24878
|
+
const sighash = iface.getSighash(fragment);
|
|
24879
|
+
if (!table.has(sighash))
|
|
24880
|
+
table.set(sighash, fragment.name);
|
|
24881
|
+
}
|
|
24882
|
+
}
|
|
24883
|
+
selectorTable = table;
|
|
24884
|
+
return table;
|
|
24885
|
+
}
|
|
24886
|
+
// ---------------------------------------------------------------------------
|
|
24887
|
+
// Getting the bytes out of the envelope
|
|
24888
|
+
// ---------------------------------------------------------------------------
|
|
24889
|
+
/**
|
|
24890
|
+
* How deep to look for the revert data. Providers nest it differently —
|
|
24891
|
+
* ethers' own error wraps the provider's, which wraps the RPC body — and a
|
|
24892
|
+
* bound is what keeps a self-referencing error object from being walked
|
|
24893
|
+
* forever.
|
|
24894
|
+
*/
|
|
24895
|
+
const MAX_DEPTH = 6;
|
|
24896
|
+
/** The keys ethers and the providers under it put a wrapped error on. */
|
|
24897
|
+
const NESTED_KEYS = [
|
|
24898
|
+
'data',
|
|
24899
|
+
'error',
|
|
24900
|
+
'originalError',
|
|
24901
|
+
'info',
|
|
24902
|
+
'cause',
|
|
24903
|
+
'body',
|
|
24904
|
+
];
|
|
24905
|
+
/** At least a 4-byte selector, and a whole number of bytes. */
|
|
24906
|
+
function isRevertData(value) {
|
|
24907
|
+
return (value.length >= 10 &&
|
|
24908
|
+
value.length % 2 === 0 &&
|
|
24909
|
+
/^0x[0-9a-fA-F]+$/.test(value));
|
|
24910
|
+
}
|
|
24911
|
+
/**
|
|
24912
|
+
* Find the revert data on an error, wherever the provider left it.
|
|
24913
|
+
*
|
|
24914
|
+
* ethers v5 raises `UNPREDICTABLE_GAS_LIMIT` with the provider's own error
|
|
24915
|
+
* attached, and each provider nests the bytes one layer differently:
|
|
24916
|
+
* `error.data`, `error.error.data`, `error.data.originalError.data`, or only
|
|
24917
|
+
* inside the JSON `body` of a `SERVER_ERROR`. Rather than enumerate the
|
|
24918
|
+
* products, walk a fixed set of keys to a fixed depth and take the first value
|
|
24919
|
+
* that is shaped like revert data.
|
|
24920
|
+
*/
|
|
24921
|
+
function extractRevertData(err) {
|
|
24922
|
+
return walk(err, 0);
|
|
24923
|
+
}
|
|
24924
|
+
function walk(node, depth) {
|
|
24925
|
+
if (node == null || depth > MAX_DEPTH)
|
|
24926
|
+
return null;
|
|
24927
|
+
if (typeof node === 'string') {
|
|
24928
|
+
if (isRevertData(node))
|
|
24929
|
+
return node;
|
|
24930
|
+
// A `SERVER_ERROR`'s body: the RPC's JSON reply, verbatim.
|
|
24931
|
+
if (!node.startsWith('{'))
|
|
24932
|
+
return null;
|
|
24933
|
+
try {
|
|
24934
|
+
return walk(JSON.parse(node), depth + 1);
|
|
24935
|
+
}
|
|
24936
|
+
catch (_a) {
|
|
24937
|
+
return null;
|
|
24938
|
+
}
|
|
24939
|
+
}
|
|
24940
|
+
if (typeof node !== 'object')
|
|
24941
|
+
return null;
|
|
24942
|
+
const record = node;
|
|
24943
|
+
for (const key of NESTED_KEYS) {
|
|
24944
|
+
const found = walk(record[key], depth + 1);
|
|
24945
|
+
if (found)
|
|
24946
|
+
return found;
|
|
24947
|
+
}
|
|
24948
|
+
return null;
|
|
24949
|
+
}
|
|
24950
|
+
// ---------------------------------------------------------------------------
|
|
24951
|
+
// Decoding
|
|
24952
|
+
// ---------------------------------------------------------------------------
|
|
24953
|
+
/**
|
|
24954
|
+
* Decode a failed call's revert into the error the contract named, or `null`
|
|
24955
|
+
* when there is nothing recognisable to name.
|
|
24956
|
+
*
|
|
24957
|
+
* `null` is the honest answer for an unknown selector, an unrelated `require`
|
|
24958
|
+
* string, or an error with no revert data at all — the caller keeps whatever
|
|
24959
|
+
* it did before rather than inventing a diagnosis from bytes it cannot read.
|
|
24960
|
+
*/
|
|
24961
|
+
function decodeRevert(err) {
|
|
24962
|
+
const data = extractRevertData(err);
|
|
24963
|
+
if (!data)
|
|
24964
|
+
return null;
|
|
24965
|
+
const selector = data.slice(0, 10).toLowerCase();
|
|
24966
|
+
if (selector === STRING_REVERT_SELECTOR) {
|
|
24967
|
+
const reason = decodeStringRevert(data);
|
|
24968
|
+
if (reason === null)
|
|
24969
|
+
return null;
|
|
24970
|
+
return isErc20Reason(reason)
|
|
24971
|
+
? { name: 'Error', family: 'erc20', reason }
|
|
24972
|
+
: null;
|
|
24973
|
+
}
|
|
24974
|
+
const name = selectors().get(selector);
|
|
24975
|
+
if (!name)
|
|
24976
|
+
return null;
|
|
24977
|
+
return {
|
|
24978
|
+
name,
|
|
24979
|
+
family: ERC20_FAMILY_NAMES.has(name) ? 'erc20' : 'protocol',
|
|
24980
|
+
};
|
|
24981
|
+
}
|
|
24982
|
+
function decodeStringRevert(data) {
|
|
24983
|
+
try {
|
|
24984
|
+
const [reason] = ethers.ethers.utils.defaultAbiCoder.decode(['string'], `0x${data.slice(10)}`);
|
|
24985
|
+
return reason;
|
|
24986
|
+
}
|
|
24987
|
+
catch (_a) {
|
|
24988
|
+
return null;
|
|
24989
|
+
}
|
|
24990
|
+
}
|
|
24991
|
+
function isErc20Reason(reason) {
|
|
24992
|
+
const lower = reason.toLowerCase();
|
|
24993
|
+
return ERC20_REASON_PATTERNS.some((pattern) => pattern.test(lower));
|
|
24994
|
+
}
|
|
24995
|
+
|
|
24809
24996
|
/**
|
|
24810
24997
|
* Wallet and RPC error predicates — pure functions over `unknown`.
|
|
24811
24998
|
*
|
|
@@ -24965,6 +25152,22 @@ function classifyWalletFailure(step, err) {
|
|
|
24965
25152
|
const CONTRACT_TTL_MS = 5 * 60 * 1000;
|
|
24966
25153
|
/** What a run without a spender, from either source, fails with. */
|
|
24967
25154
|
const NO_SPENDER_MESSAGE = 'DepositFlow: no ERC-20 spender; build the flow with kasu.flows.deposit() or pass `spender` on the input';
|
|
25155
|
+
/** What a malformed auth signature fails the generate step with. */
|
|
25156
|
+
const INVALID_AUTH_SIGNATURE_MESSAGE = 'DepositFlow: the wallet returned a malformed authentication signature; expected 65 bytes of 0x-prefixed hex';
|
|
25157
|
+
/** What a malformed acceptance signature fails the confirm step with. */
|
|
25158
|
+
const INVALID_ACCEPTANCE_SIGNATURE_MESSAGE = 'DepositFlow: the wallet returned a malformed acceptance signature; expected 65 bytes of 0x-prefixed hex';
|
|
25159
|
+
/**
|
|
25160
|
+
* Is this an EIP-191 personal sign, in the only shape the protocol accepts?
|
|
25161
|
+
*
|
|
25162
|
+
* 65 bytes — `r`, `s`, `v` — 0x-prefixed. Nothing downstream checks it: the
|
|
25163
|
+
* ABI coder takes any even-length hex as `bytes`, so `'0x'` and a 64-byte
|
|
25164
|
+
* string both encode happily into a `depositData` the agreements service then
|
|
25165
|
+
* cannot verify against anything. The check has to happen where the signature
|
|
25166
|
+
* is taken, which is here.
|
|
25167
|
+
*/
|
|
25168
|
+
function isPersonalSignature(signature) {
|
|
25169
|
+
return ethers.utils.isHexString(signature, 65);
|
|
25170
|
+
}
|
|
24968
25171
|
const INITIAL$1 = {
|
|
24969
25172
|
phase: 'idle',
|
|
24970
25173
|
step: null,
|
|
@@ -24989,13 +25192,32 @@ function badgeFor(step, approvalRequired) {
|
|
|
24989
25192
|
};
|
|
24990
25193
|
}
|
|
24991
25194
|
/**
|
|
24992
|
-
* The request step
|
|
24993
|
-
*
|
|
24994
|
-
*
|
|
24995
|
-
*
|
|
25195
|
+
* The request step's extra outcomes, in the order the evidence supports.
|
|
25196
|
+
*
|
|
25197
|
+
* A revert is read for WHAT reverted before it is read as a shortfall.
|
|
25198
|
+
* `requestDepositWithKyc` reverts for a whole family of declared reasons —
|
|
25199
|
+
* `LendingPoolIsStopped`, `ClearingIsPending`, `UserNotKycd`, `UserBlocked`,
|
|
25200
|
+
* `UserNotInAllowList`, `InvalidTranche`, `BlockExpired` — and every one of
|
|
25201
|
+
* them used to arrive as `insufficient-balance`, which told a fully funded
|
|
25202
|
+
* lender to top up a wallet that was never short while their pool was simply
|
|
25203
|
+
* mid-clearing. So: a decoded protocol error is `reverted` and names itself.
|
|
25204
|
+
*
|
|
25205
|
+
* Only a token balance or allowance failure — or revert data nothing can
|
|
25206
|
+
* decode, on the `UNPREDICTABLE_GAS_LIMIT` ethers raises for a failed gas
|
|
25207
|
+
* estimate — is still `insufficient-balance`, which is the case that reason
|
|
25208
|
+
* was named for and the one where topping up is genuinely the answer.
|
|
24996
25209
|
*/
|
|
24997
25210
|
function classifyRequest(err) {
|
|
24998
|
-
|
|
25211
|
+
const revert = decodeRevert(err);
|
|
25212
|
+
if ((revert === null || revert === void 0 ? void 0 : revert.family) === 'protocol') {
|
|
25213
|
+
return {
|
|
25214
|
+
step: 'request',
|
|
25215
|
+
reason: 'reverted',
|
|
25216
|
+
revertError: revert.name,
|
|
25217
|
+
error: err,
|
|
25218
|
+
};
|
|
25219
|
+
}
|
|
25220
|
+
if (revert !== null || isUnpredictableGas(err)) {
|
|
24999
25221
|
return { step: 'request', reason: 'insufficient-balance', error: err };
|
|
25000
25222
|
}
|
|
25001
25223
|
return classifyWalletFailure('request', err);
|
|
@@ -25047,6 +25269,18 @@ class DepositFlow extends Flow {
|
|
|
25047
25269
|
this._store.patch(Object.assign({ phase: 'accepting-sign' }, badgeFor('confirm', this._store.state.approvalRequired)), token);
|
|
25048
25270
|
try {
|
|
25049
25271
|
const signature = yield this._ports.signMessage(contract.contractMessage);
|
|
25272
|
+
// Checked HERE, not at the encoder: this is the signature the
|
|
25273
|
+
// agreements service verifies the deposit against, and a wallet
|
|
25274
|
+
// that returned something other than 65 bytes has not signed
|
|
25275
|
+
// anything. Failing the confirm step names the step that produced
|
|
25276
|
+
// it; letting it through would put an unverifiable blob on chain.
|
|
25277
|
+
if (!isPersonalSignature(signature)) {
|
|
25278
|
+
bridge.settle({
|
|
25279
|
+
kind: 'failed',
|
|
25280
|
+
error: new Error(INVALID_ACCEPTANCE_SIGNATURE_MESSAGE),
|
|
25281
|
+
});
|
|
25282
|
+
return;
|
|
25283
|
+
}
|
|
25050
25284
|
bridge.settle({ kind: 'accepted', signature });
|
|
25051
25285
|
}
|
|
25052
25286
|
catch (err) {
|
|
@@ -25140,6 +25374,18 @@ class DepositFlow extends Flow {
|
|
|
25140
25374
|
this._fail(token, approvalRequired, classifyWalletFailure('generate', err));
|
|
25141
25375
|
return;
|
|
25142
25376
|
}
|
|
25377
|
+
// The same EIP-191 shape as the acceptance, and the same reason to
|
|
25378
|
+
// check it: kasu-backend verifies this one to decide whether to issue
|
|
25379
|
+
// an agreement at all, so a malformed signature is a 4xx that says
|
|
25380
|
+
// nothing about which step produced it. Named here instead.
|
|
25381
|
+
if (!isPersonalSignature(signature)) {
|
|
25382
|
+
this._fail(token, approvalRequired, {
|
|
25383
|
+
step: 'generate',
|
|
25384
|
+
reason: 'failed',
|
|
25385
|
+
error: new Error(INVALID_AUTH_SIGNATURE_MESSAGE),
|
|
25386
|
+
});
|
|
25387
|
+
return;
|
|
25388
|
+
}
|
|
25143
25389
|
if (!this._store.isCurrent(token))
|
|
25144
25390
|
return;
|
|
25145
25391
|
// 3. Generate — POST the request.
|
|
@@ -25196,12 +25442,29 @@ class DepositFlow extends Flow {
|
|
|
25196
25442
|
});
|
|
25197
25443
|
return;
|
|
25198
25444
|
}
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25202
|
-
|
|
25203
|
-
|
|
25204
|
-
|
|
25445
|
+
// The acceptance signature is already known to be 65 bytes, but the
|
|
25446
|
+
// encoder also reads `timestamp`, `contractVersion` and
|
|
25447
|
+
// `contractType` off a response the SDK did not produce. `start()`
|
|
25448
|
+
// promises it does not reject, so anything that throws in here becomes
|
|
25449
|
+
// a failure the consumer can render rather than an unhandled rejection
|
|
25450
|
+
// in an application that was told it never had to catch one.
|
|
25451
|
+
let depositData;
|
|
25452
|
+
try {
|
|
25453
|
+
depositData = encodeDepositData({
|
|
25454
|
+
signature: outcome.signature,
|
|
25455
|
+
timestamp: contract.timestamp,
|
|
25456
|
+
contractVersion: contract.contractVersion,
|
|
25457
|
+
contractType: asContractType(contract.contractType),
|
|
25458
|
+
});
|
|
25459
|
+
}
|
|
25460
|
+
catch (err) {
|
|
25461
|
+
this._fail(token, approvalRequired, {
|
|
25462
|
+
step: 'request',
|
|
25463
|
+
reason: 'failed',
|
|
25464
|
+
error: err,
|
|
25465
|
+
});
|
|
25466
|
+
return;
|
|
25467
|
+
}
|
|
25205
25468
|
// 6. Approve — the EXACT amount, never `MaxUint256`. House rule: an
|
|
25206
25469
|
// unlimited allowance outlives the deposit it was granted for, and a
|
|
25207
25470
|
// later exploit of the spender would drain a wallet that has long
|
|
@@ -26901,6 +27164,8 @@ exports.EPOCHS_IN_YEAR = EPOCHS_IN_YEAR;
|
|
|
26901
27164
|
exports.Flow = Flow;
|
|
26902
27165
|
exports.FlowStore = FlowStore;
|
|
26903
27166
|
exports.FlowsFacade = FlowsFacade;
|
|
27167
|
+
exports.INVALID_ACCEPTANCE_SIGNATURE_MESSAGE = INVALID_ACCEPTANCE_SIGNATURE_MESSAGE;
|
|
27168
|
+
exports.INVALID_AUTH_SIGNATURE_MESSAGE = INVALID_AUTH_SIGNATURE_MESSAGE;
|
|
26904
27169
|
exports.INVOICEMATE = INVOICEMATE;
|
|
26905
27170
|
exports.Kasu = Kasu;
|
|
26906
27171
|
exports.KasuSdk = KasuSdk;
|
|
@@ -26930,11 +27195,13 @@ exports.classifyWalletFailure = classifyWalletFailure;
|
|
|
26930
27195
|
exports.compareTrancheSeniority = compareTrancheSeniority;
|
|
26931
27196
|
exports.computeSettlementWindow = computeSettlementWindow;
|
|
26932
27197
|
exports.countSubmissions = countSubmissions;
|
|
27198
|
+
exports.decodeRevert = decodeRevert;
|
|
26933
27199
|
exports.deriveCycleDates = deriveCycleDates;
|
|
26934
27200
|
exports.derivePoolStatus = derivePoolStatus;
|
|
26935
27201
|
exports.deriveRequestState = deriveRequestState;
|
|
26936
27202
|
exports.encodeDepositData = encodeDepositData;
|
|
26937
27203
|
exports.epochRateToApy = epochRateToApy;
|
|
27204
|
+
exports.extractRevertData = extractRevertData;
|
|
26938
27205
|
exports.fetchUnusedPoolIds = fetchUnusedPoolIds;
|
|
26939
27206
|
exports.firstSubmissionTimestamp = firstSubmissionTimestamp;
|
|
26940
27207
|
exports.floorToCents = floorToCents;
|