@kasufinance/kasu-sdk 2.7.0 → 2.8.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.
- package/README.md +88 -6
- package/dist/bundle.cjs.js +541 -21
- package/dist/bundle.esm.js +537 -22
- 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/facade/flows.d.ts +17 -1
- package/dist/facade/flows.js +15 -2
- package/dist/facade/flows.js.map +1 -1
- package/dist/facade/kasu.js +2 -1
- package/dist/facade/kasu.js.map +1 -1
- package/dist/flows/deposit-flow.d.ts +170 -8
- package/dist/flows/deposit-flow.js +333 -15
- package/dist/flows/deposit-flow.js.map +1 -1
- package/dist/flows/index.d.ts +2 -2
- 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/facade/flows.ts +12 -0
- package/src/facade/kasu.ts +1 -0
- package/src/flows/deposit-flow.ts +509 -22
- package/src/flows/index.ts +4 -0
package/dist/bundle.esm.js
CHANGED
|
@@ -20835,12 +20835,12 @@ function toURLEncodedForm(data, options) {
|
|
|
20835
20835
|
});
|
|
20836
20836
|
}
|
|
20837
20837
|
|
|
20838
|
-
const MAX_DEPTH = DEFAULT_FORM_DATA_MAX_DEPTH;
|
|
20838
|
+
const MAX_DEPTH$1 = DEFAULT_FORM_DATA_MAX_DEPTH;
|
|
20839
20839
|
|
|
20840
20840
|
function throwIfDepthExceeded(index) {
|
|
20841
|
-
if (index > MAX_DEPTH) {
|
|
20841
|
+
if (index > MAX_DEPTH$1) {
|
|
20842
20842
|
throw new AxiosError$1(
|
|
20843
|
-
'FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH,
|
|
20843
|
+
'FormData field is too deeply nested (' + index + ' levels). Max depth: ' + MAX_DEPTH$1,
|
|
20844
20844
|
AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED
|
|
20845
20845
|
);
|
|
20846
20846
|
}
|
|
@@ -24804,6 +24804,193 @@ function buildFullNameRequestMessage(address, timestampMs) {
|
|
|
24804
24804
|
return `I request my full name for ${address.toLowerCase()} at ${timestampMs}.`;
|
|
24805
24805
|
}
|
|
24806
24806
|
|
|
24807
|
+
// ---------------------------------------------------------------------------
|
|
24808
|
+
// The selector tables
|
|
24809
|
+
// ---------------------------------------------------------------------------
|
|
24810
|
+
/**
|
|
24811
|
+
* OpenZeppelin v5's ERC-20 errors. They are not in either Kasu ABI because no
|
|
24812
|
+
* Kasu contract declares them — they arrive from the TOKEN, through the
|
|
24813
|
+
* manager's `transferFrom`, and they are the modern spelling of the string
|
|
24814
|
+
* reverts below.
|
|
24815
|
+
*/
|
|
24816
|
+
const ERC20_ERROR_ABI = [
|
|
24817
|
+
'error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed)',
|
|
24818
|
+
'error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed)',
|
|
24819
|
+
];
|
|
24820
|
+
/**
|
|
24821
|
+
* The protocol errors that mean the ERC-20 transfer failed rather than the
|
|
24822
|
+
* protocol refusing.
|
|
24823
|
+
*
|
|
24824
|
+
* `SafeERC20FailedOperation` is OpenZeppelin's wrapper around a token call
|
|
24825
|
+
* that returned false or reverted, which on this path IS the `transferFrom`;
|
|
24826
|
+
* `AddressInsufficientBalance` is its native-value sibling. Both belong with
|
|
24827
|
+
* the balance case, not with the pool conditions — a lender who sees one of
|
|
24828
|
+
* them really does need to fund or re-approve.
|
|
24829
|
+
*/
|
|
24830
|
+
const ERC20_FAMILY_NAMES = new Set([
|
|
24831
|
+
'AddressInsufficientBalance',
|
|
24832
|
+
'ERC20InsufficientAllowance',
|
|
24833
|
+
'ERC20InsufficientBalance',
|
|
24834
|
+
'SafeERC20FailedOperation',
|
|
24835
|
+
]);
|
|
24836
|
+
/** Solidity's `Error(string)`, the selector every `require` reason arrives under. */
|
|
24837
|
+
const STRING_REVERT_SELECTOR = '0x08c379a0';
|
|
24838
|
+
/**
|
|
24839
|
+
* The `require` reasons that are a balance or an allowance, across the token
|
|
24840
|
+
* implementations in circulation: OpenZeppelin v4's sentences, and the
|
|
24841
|
+
* shorthand the minimal implementations use.
|
|
24842
|
+
*/
|
|
24843
|
+
const ERC20_REASON_PATTERNS = [
|
|
24844
|
+
/exceeds\s+balance/,
|
|
24845
|
+
/exceeds\s+allowance/,
|
|
24846
|
+
/insufficient\s+balance/,
|
|
24847
|
+
/insufficient\s+allowance/,
|
|
24848
|
+
/transfer_from_failed/,
|
|
24849
|
+
/transferfrom\s+failed/,
|
|
24850
|
+
/low-level\s+call\s+failed/,
|
|
24851
|
+
];
|
|
24852
|
+
/**
|
|
24853
|
+
* selector → error name, built once on first use.
|
|
24854
|
+
*
|
|
24855
|
+
* Lazily, because a consumer that never sees a revert should not pay for three
|
|
24856
|
+
* `Interface` constructions at import. The two Kasu tables are the GENERATED
|
|
24857
|
+
* typechain ABIs, so this cannot drift from the contracts: regenerate the ABIs
|
|
24858
|
+
* and the new errors are recognised with no edit here.
|
|
24859
|
+
*/
|
|
24860
|
+
let selectorTable = null;
|
|
24861
|
+
function selectors() {
|
|
24862
|
+
if (selectorTable)
|
|
24863
|
+
return selectorTable;
|
|
24864
|
+
const table = new Map();
|
|
24865
|
+
const interfaces = [
|
|
24866
|
+
// The manager the deposit is called against, and the allow list it
|
|
24867
|
+
// delegates the KYC and block-window checks to.
|
|
24868
|
+
ILendingPoolManagerAbi__factory.createInterface(),
|
|
24869
|
+
IKasuAllowListAbi__factory.createInterface(),
|
|
24870
|
+
new ethers.utils.Interface(ERC20_ERROR_ABI),
|
|
24871
|
+
];
|
|
24872
|
+
for (const iface of interfaces) {
|
|
24873
|
+
for (const fragment of Object.values(iface.errors)) {
|
|
24874
|
+
// First writer wins: the same name declared by both ABIs is the
|
|
24875
|
+
// same selector, so the duplicate would be a no-op anyway.
|
|
24876
|
+
const sighash = iface.getSighash(fragment);
|
|
24877
|
+
if (!table.has(sighash))
|
|
24878
|
+
table.set(sighash, fragment.name);
|
|
24879
|
+
}
|
|
24880
|
+
}
|
|
24881
|
+
selectorTable = table;
|
|
24882
|
+
return table;
|
|
24883
|
+
}
|
|
24884
|
+
// ---------------------------------------------------------------------------
|
|
24885
|
+
// Getting the bytes out of the envelope
|
|
24886
|
+
// ---------------------------------------------------------------------------
|
|
24887
|
+
/**
|
|
24888
|
+
* How deep to look for the revert data. Providers nest it differently —
|
|
24889
|
+
* ethers' own error wraps the provider's, which wraps the RPC body — and a
|
|
24890
|
+
* bound is what keeps a self-referencing error object from being walked
|
|
24891
|
+
* forever.
|
|
24892
|
+
*/
|
|
24893
|
+
const MAX_DEPTH = 6;
|
|
24894
|
+
/** The keys ethers and the providers under it put a wrapped error on. */
|
|
24895
|
+
const NESTED_KEYS = [
|
|
24896
|
+
'data',
|
|
24897
|
+
'error',
|
|
24898
|
+
'originalError',
|
|
24899
|
+
'info',
|
|
24900
|
+
'cause',
|
|
24901
|
+
'body',
|
|
24902
|
+
];
|
|
24903
|
+
/** At least a 4-byte selector, and a whole number of bytes. */
|
|
24904
|
+
function isRevertData(value) {
|
|
24905
|
+
return (value.length >= 10 &&
|
|
24906
|
+
value.length % 2 === 0 &&
|
|
24907
|
+
/^0x[0-9a-fA-F]+$/.test(value));
|
|
24908
|
+
}
|
|
24909
|
+
/**
|
|
24910
|
+
* Find the revert data on an error, wherever the provider left it.
|
|
24911
|
+
*
|
|
24912
|
+
* ethers v5 raises `UNPREDICTABLE_GAS_LIMIT` with the provider's own error
|
|
24913
|
+
* attached, and each provider nests the bytes one layer differently:
|
|
24914
|
+
* `error.data`, `error.error.data`, `error.data.originalError.data`, or only
|
|
24915
|
+
* inside the JSON `body` of a `SERVER_ERROR`. Rather than enumerate the
|
|
24916
|
+
* products, walk a fixed set of keys to a fixed depth and take the first value
|
|
24917
|
+
* that is shaped like revert data.
|
|
24918
|
+
*/
|
|
24919
|
+
function extractRevertData(err) {
|
|
24920
|
+
return walk(err, 0);
|
|
24921
|
+
}
|
|
24922
|
+
function walk(node, depth) {
|
|
24923
|
+
if (node == null || depth > MAX_DEPTH)
|
|
24924
|
+
return null;
|
|
24925
|
+
if (typeof node === 'string') {
|
|
24926
|
+
if (isRevertData(node))
|
|
24927
|
+
return node;
|
|
24928
|
+
// A `SERVER_ERROR`'s body: the RPC's JSON reply, verbatim.
|
|
24929
|
+
if (!node.startsWith('{'))
|
|
24930
|
+
return null;
|
|
24931
|
+
try {
|
|
24932
|
+
return walk(JSON.parse(node), depth + 1);
|
|
24933
|
+
}
|
|
24934
|
+
catch (_a) {
|
|
24935
|
+
return null;
|
|
24936
|
+
}
|
|
24937
|
+
}
|
|
24938
|
+
if (typeof node !== 'object')
|
|
24939
|
+
return null;
|
|
24940
|
+
const record = node;
|
|
24941
|
+
for (const key of NESTED_KEYS) {
|
|
24942
|
+
const found = walk(record[key], depth + 1);
|
|
24943
|
+
if (found)
|
|
24944
|
+
return found;
|
|
24945
|
+
}
|
|
24946
|
+
return null;
|
|
24947
|
+
}
|
|
24948
|
+
// ---------------------------------------------------------------------------
|
|
24949
|
+
// Decoding
|
|
24950
|
+
// ---------------------------------------------------------------------------
|
|
24951
|
+
/**
|
|
24952
|
+
* Decode a failed call's revert into the error the contract named, or `null`
|
|
24953
|
+
* when there is nothing recognisable to name.
|
|
24954
|
+
*
|
|
24955
|
+
* `null` is the honest answer for an unknown selector, an unrelated `require`
|
|
24956
|
+
* string, or an error with no revert data at all — the caller keeps whatever
|
|
24957
|
+
* it did before rather than inventing a diagnosis from bytes it cannot read.
|
|
24958
|
+
*/
|
|
24959
|
+
function decodeRevert(err) {
|
|
24960
|
+
const data = extractRevertData(err);
|
|
24961
|
+
if (!data)
|
|
24962
|
+
return null;
|
|
24963
|
+
const selector = data.slice(0, 10).toLowerCase();
|
|
24964
|
+
if (selector === STRING_REVERT_SELECTOR) {
|
|
24965
|
+
const reason = decodeStringRevert(data);
|
|
24966
|
+
if (reason === null)
|
|
24967
|
+
return null;
|
|
24968
|
+
return isErc20Reason(reason)
|
|
24969
|
+
? { name: 'Error', family: 'erc20', reason }
|
|
24970
|
+
: null;
|
|
24971
|
+
}
|
|
24972
|
+
const name = selectors().get(selector);
|
|
24973
|
+
if (!name)
|
|
24974
|
+
return null;
|
|
24975
|
+
return {
|
|
24976
|
+
name,
|
|
24977
|
+
family: ERC20_FAMILY_NAMES.has(name) ? 'erc20' : 'protocol',
|
|
24978
|
+
};
|
|
24979
|
+
}
|
|
24980
|
+
function decodeStringRevert(data) {
|
|
24981
|
+
try {
|
|
24982
|
+
const [reason] = ethers.utils.defaultAbiCoder.decode(['string'], `0x${data.slice(10)}`);
|
|
24983
|
+
return reason;
|
|
24984
|
+
}
|
|
24985
|
+
catch (_a) {
|
|
24986
|
+
return null;
|
|
24987
|
+
}
|
|
24988
|
+
}
|
|
24989
|
+
function isErc20Reason(reason) {
|
|
24990
|
+
const lower = reason.toLowerCase();
|
|
24991
|
+
return ERC20_REASON_PATTERNS.some((pattern) => pattern.test(lower));
|
|
24992
|
+
}
|
|
24993
|
+
|
|
24807
24994
|
/**
|
|
24808
24995
|
* Wallet and RPC error predicates — pure functions over `unknown`.
|
|
24809
24996
|
*
|
|
@@ -24959,19 +25146,94 @@ function classifyWalletFailure(step, err) {
|
|
|
24959
25146
|
: { step, reason: 'failed', error: err };
|
|
24960
25147
|
}
|
|
24961
25148
|
|
|
25149
|
+
/**
|
|
25150
|
+
* What a `depositBatch` port throws when it KNOWS the batch reverted — from a
|
|
25151
|
+
* simulation before sending, or from the submitter refusing to broadcast a
|
|
25152
|
+
* batch that would revert. The run ends `{ step: 'request', reason:
|
|
25153
|
+
* 'reverted', revertError }`.
|
|
25154
|
+
*
|
|
25155
|
+
* `revertError` is the custom error the contract named (`'ClearingIsPending'`,
|
|
25156
|
+
* `'UserNotKycd'`, …), exactly as the ABI declares it. Pass `''` when the
|
|
25157
|
+
* batch is known to revert but not why: the consumer then renders its generic
|
|
25158
|
+
* `reverted` copy, which is what an unknown name gets anyway.
|
|
25159
|
+
*
|
|
25160
|
+
* Any OTHER throw from the port is read the way a direct deposit's is — a
|
|
25161
|
+
* wallet rejection is `cancelled`, a decodable revert is `reverted`, and
|
|
25162
|
+
* everything else is `failed` with the error kept. A port that cannot tell is
|
|
25163
|
+
* better off throwing what it has than guessing a name.
|
|
25164
|
+
*/
|
|
25165
|
+
class BatchRevertedError extends Error {
|
|
25166
|
+
constructor(revertError, message) {
|
|
25167
|
+
super(message !== null && message !== void 0 ? message : `DepositFlow: the batch reverted${revertError ? ` with ${revertError}` : ''}`);
|
|
25168
|
+
this.name = 'BatchRevertedError';
|
|
25169
|
+
this.revertError = revertError;
|
|
25170
|
+
// Keeps `instanceof` honest under a down-levelled build.
|
|
25171
|
+
Object.setPrototypeOf(this, BatchRevertedError.prototype);
|
|
25172
|
+
}
|
|
25173
|
+
}
|
|
24962
25174
|
/** Generated agreements are valid for five minutes upstream. */
|
|
24963
25175
|
const CONTRACT_TTL_MS = 5 * 60 * 1000;
|
|
24964
25176
|
/** What a run without a spender, from either source, fails with. */
|
|
24965
25177
|
const NO_SPENDER_MESSAGE = 'DepositFlow: no ERC-20 spender; build the flow with kasu.flows.deposit() or pass `spender` on the input';
|
|
25178
|
+
/** What a malformed auth signature fails the generate step with. */
|
|
25179
|
+
const INVALID_AUTH_SIGNATURE_MESSAGE = 'DepositFlow: the wallet returned a malformed authentication signature; expected 65 bytes of 0x-prefixed hex';
|
|
25180
|
+
/** What a malformed acceptance signature fails the confirm step with. */
|
|
25181
|
+
const INVALID_ACCEPTANCE_SIGNATURE_MESSAGE = 'DepositFlow: the wallet returned a malformed acceptance signature; expected 65 bytes of 0x-prefixed hex';
|
|
25182
|
+
/**
|
|
25183
|
+
* Is this an EIP-191 personal sign, in the only shape the protocol accepts?
|
|
25184
|
+
*
|
|
25185
|
+
* 65 bytes — `r`, `s`, `v` — 0x-prefixed. Nothing downstream checks it: the
|
|
25186
|
+
* ABI coder takes any even-length hex as `bytes`, so `'0x'` and a 64-byte
|
|
25187
|
+
* string both encode happily into a `depositData` the agreements service then
|
|
25188
|
+
* cannot verify against anything. The check has to happen where the signature
|
|
25189
|
+
* is taken, which is here.
|
|
25190
|
+
*/
|
|
25191
|
+
function isPersonalSignature(signature) {
|
|
25192
|
+
return utils$2.isHexString(signature, 65);
|
|
25193
|
+
}
|
|
24966
25194
|
const INITIAL$1 = {
|
|
24967
25195
|
phase: 'idle',
|
|
24968
25196
|
step: null,
|
|
24969
25197
|
stepIndex: 0,
|
|
24970
25198
|
stepTotal: 4,
|
|
24971
25199
|
approvalRequired: true,
|
|
25200
|
+
batched: false,
|
|
24972
25201
|
contract: null,
|
|
24973
25202
|
failure: null,
|
|
24974
25203
|
};
|
|
25204
|
+
const ERC20 = IERC20MetadataAbi__factory.createInterface();
|
|
25205
|
+
const LENDING_POOL_MANAGER = ILendingPoolManagerAbi__factory.createInterface();
|
|
25206
|
+
/**
|
|
25207
|
+
* The batch path's two calls, encoded by the SDK so no consumer has to: the
|
|
25208
|
+
* EXACT-amount approve, then the very `requestDepositWithKyc` the default
|
|
25209
|
+
* `deposit` port sends — `swapData` `'0x'`, no value. Both read `amount` from
|
|
25210
|
+
* the same variable, so the batch cannot approve one figure and deposit
|
|
25211
|
+
* another.
|
|
25212
|
+
*/
|
|
25213
|
+
function encodeDepositBatch(args) {
|
|
25214
|
+
const { stableAsset, spender, input, depositData, kyc } = args;
|
|
25215
|
+
return [
|
|
25216
|
+
{
|
|
25217
|
+
to: stableAsset,
|
|
25218
|
+
data: ERC20.encodeFunctionData('approve', [spender, input.amount]),
|
|
25219
|
+
},
|
|
25220
|
+
{
|
|
25221
|
+
to: spender,
|
|
25222
|
+
data: LENDING_POOL_MANAGER.encodeFunctionData('requestDepositWithKyc', [
|
|
25223
|
+
input.poolId,
|
|
25224
|
+
input.trancheId,
|
|
25225
|
+
input.amount,
|
|
25226
|
+
'0x',
|
|
25227
|
+
input.fixedTermConfigId,
|
|
25228
|
+
depositData,
|
|
25229
|
+
{
|
|
25230
|
+
blockExpiration: kyc.blockExpiration,
|
|
25231
|
+
signature: kyc.signature,
|
|
25232
|
+
},
|
|
25233
|
+
]),
|
|
25234
|
+
},
|
|
25235
|
+
];
|
|
25236
|
+
}
|
|
24975
25237
|
/** 1-based badge position, with `approve` dropped when it is out of scope. */
|
|
24976
25238
|
function stepIndexOf(step, approvalRequired) {
|
|
24977
25239
|
const order = approvalRequired
|
|
@@ -24987,17 +25249,52 @@ function badgeFor(step, approvalRequired) {
|
|
|
24987
25249
|
};
|
|
24988
25250
|
}
|
|
24989
25251
|
/**
|
|
24990
|
-
* The request step
|
|
24991
|
-
*
|
|
24992
|
-
*
|
|
24993
|
-
*
|
|
25252
|
+
* The request step's extra outcomes, in the order the evidence supports.
|
|
25253
|
+
*
|
|
25254
|
+
* A revert is read for WHAT reverted before it is read as a shortfall.
|
|
25255
|
+
* `requestDepositWithKyc` reverts for a whole family of declared reasons —
|
|
25256
|
+
* `LendingPoolIsStopped`, `ClearingIsPending`, `UserNotKycd`, `UserBlocked`,
|
|
25257
|
+
* `UserNotInAllowList`, `InvalidTranche`, `BlockExpired` — and every one of
|
|
25258
|
+
* them used to arrive as `insufficient-balance`, which told a fully funded
|
|
25259
|
+
* lender to top up a wallet that was never short while their pool was simply
|
|
25260
|
+
* mid-clearing. So: a decoded protocol error is `reverted` and names itself.
|
|
25261
|
+
*
|
|
25262
|
+
* Only a token balance or allowance failure — or revert data nothing can
|
|
25263
|
+
* decode, on the `UNPREDICTABLE_GAS_LIMIT` ethers raises for a failed gas
|
|
25264
|
+
* estimate — is still `insufficient-balance`, which is the case that reason
|
|
25265
|
+
* was named for and the one where topping up is genuinely the answer.
|
|
24994
25266
|
*/
|
|
24995
25267
|
function classifyRequest(err) {
|
|
24996
|
-
|
|
25268
|
+
const revert = decodeRevert(err);
|
|
25269
|
+
if ((revert === null || revert === void 0 ? void 0 : revert.family) === 'protocol') {
|
|
25270
|
+
return {
|
|
25271
|
+
step: 'request',
|
|
25272
|
+
reason: 'reverted',
|
|
25273
|
+
revertError: revert.name,
|
|
25274
|
+
error: err,
|
|
25275
|
+
};
|
|
25276
|
+
}
|
|
25277
|
+
if (revert !== null || isUnpredictableGas(err)) {
|
|
24997
25278
|
return { step: 'request', reason: 'insufficient-balance', error: err };
|
|
24998
25279
|
}
|
|
24999
25280
|
return classifyWalletFailure('request', err);
|
|
25000
25281
|
}
|
|
25282
|
+
/**
|
|
25283
|
+
* A `depositBatch` rejection. A submitter that KNOWS the batch reverts says so
|
|
25284
|
+
* with `BatchRevertedError`; anything else is read exactly as a direct
|
|
25285
|
+
* deposit's throw is, so a non-wallet error can never become `cancelled`.
|
|
25286
|
+
*/
|
|
25287
|
+
function classifyBatch(err) {
|
|
25288
|
+
if (err instanceof BatchRevertedError) {
|
|
25289
|
+
return {
|
|
25290
|
+
step: 'request',
|
|
25291
|
+
reason: 'reverted',
|
|
25292
|
+
revertError: err.revertError,
|
|
25293
|
+
error: err,
|
|
25294
|
+
};
|
|
25295
|
+
}
|
|
25296
|
+
return classifyRequest(err);
|
|
25297
|
+
}
|
|
25001
25298
|
// ---------------------------------------------------------------------------
|
|
25002
25299
|
// The flow
|
|
25003
25300
|
// ---------------------------------------------------------------------------
|
|
@@ -25024,8 +25321,15 @@ class DepositFlow extends Flow {
|
|
|
25024
25321
|
* A stale token simply is not the current generation.
|
|
25025
25322
|
*/
|
|
25026
25323
|
this._acceptingFor = null;
|
|
25324
|
+
/**
|
|
25325
|
+
* The batch path's authorisation handshake. Same shape and lifetime as
|
|
25326
|
+
* `_accept`: the run parks on it, `authoriseTransfer`, `declineTransfer`
|
|
25327
|
+
* and `reset` settle it, and it is cleared the moment it settles.
|
|
25328
|
+
*/
|
|
25329
|
+
this._authorise = null;
|
|
25027
25330
|
this._ttlMs = (_a = opts === null || opts === void 0 ? void 0 : opts.contractTtlMs) !== null && _a !== void 0 ? _a : CONTRACT_TTL_MS;
|
|
25028
25331
|
this._defaultSpender = opts === null || opts === void 0 ? void 0 : opts.spender;
|
|
25332
|
+
this._stableAsset = opts === null || opts === void 0 ? void 0 : opts.stableAsset;
|
|
25029
25333
|
// Called through the ports object, never captured off it: a consumer
|
|
25030
25334
|
// whose clock is a method on its own object keeps its `this`.
|
|
25031
25335
|
this._now = () => { var _a, _b; return (_b = (_a = _ports.now) === null || _a === void 0 ? void 0 : _a.call(_ports)) !== null && _b !== void 0 ? _b : Date.now(); };
|
|
@@ -25045,6 +25349,18 @@ class DepositFlow extends Flow {
|
|
|
25045
25349
|
this._store.patch(Object.assign({ phase: 'accepting-sign' }, badgeFor('confirm', this._store.state.approvalRequired)), token);
|
|
25046
25350
|
try {
|
|
25047
25351
|
const signature = yield this._ports.signMessage(contract.contractMessage);
|
|
25352
|
+
// Checked HERE, not at the encoder: this is the signature the
|
|
25353
|
+
// agreements service verifies the deposit against, and a wallet
|
|
25354
|
+
// that returned something other than 65 bytes has not signed
|
|
25355
|
+
// anything. Failing the confirm step names the step that produced
|
|
25356
|
+
// it; letting it through would put an unverifiable blob on chain.
|
|
25357
|
+
if (!isPersonalSignature(signature)) {
|
|
25358
|
+
bridge.settle({
|
|
25359
|
+
kind: 'failed',
|
|
25360
|
+
error: new Error(INVALID_ACCEPTANCE_SIGNATURE_MESSAGE),
|
|
25361
|
+
});
|
|
25362
|
+
return;
|
|
25363
|
+
}
|
|
25048
25364
|
bridge.settle({ kind: 'accepted', signature });
|
|
25049
25365
|
}
|
|
25050
25366
|
catch (err) {
|
|
@@ -25075,6 +25391,33 @@ class DepositFlow extends Flow {
|
|
|
25075
25391
|
this._accept = null;
|
|
25076
25392
|
bridge.settle({ kind: 'declined' });
|
|
25077
25393
|
}
|
|
25394
|
+
/**
|
|
25395
|
+
* Batch path: authorise the single transaction that approves and deposits,
|
|
25396
|
+
* and resume the parked run. A no-op when nothing is parked on
|
|
25397
|
+
* `awaiting-authorise`, so a double tap cannot submit twice.
|
|
25398
|
+
*
|
|
25399
|
+
* The batch has no wallet prompt per call, so this is the lender's
|
|
25400
|
+
* explicit consent to the transfer — call it only from their action.
|
|
25401
|
+
*/
|
|
25402
|
+
authoriseTransfer() {
|
|
25403
|
+
const bridge = this._authorise;
|
|
25404
|
+
if (!bridge)
|
|
25405
|
+
return;
|
|
25406
|
+
this._authorise = null;
|
|
25407
|
+
bridge.settle({ kind: 'authorised' });
|
|
25408
|
+
}
|
|
25409
|
+
/**
|
|
25410
|
+
* Batch path: refuse the transfer. The run ends on `error` with `{ step:
|
|
25411
|
+
* 'request', reason: 'cancelled' }` and nothing is submitted. A no-op when
|
|
25412
|
+
* nothing is parked on `awaiting-authorise`.
|
|
25413
|
+
*/
|
|
25414
|
+
declineTransfer() {
|
|
25415
|
+
const bridge = this._authorise;
|
|
25416
|
+
if (!bridge)
|
|
25417
|
+
return;
|
|
25418
|
+
this._authorise = null;
|
|
25419
|
+
bridge.settle({ kind: 'declined' });
|
|
25420
|
+
}
|
|
25078
25421
|
/** True only while THIS generation is waiting on the acceptance signature. */
|
|
25079
25422
|
_isAccepting() {
|
|
25080
25423
|
return (this._acceptingFor !== null &&
|
|
@@ -25086,6 +25429,9 @@ class DepositFlow extends Flow {
|
|
|
25086
25429
|
this._accept = null;
|
|
25087
25430
|
this._acceptingFor = null;
|
|
25088
25431
|
bridge === null || bridge === void 0 ? void 0 : bridge.settle({ kind: 'abandoned' });
|
|
25432
|
+
const authorise = this._authorise;
|
|
25433
|
+
this._authorise = null;
|
|
25434
|
+
authorise === null || authorise === void 0 ? void 0 : authorise.settle({ kind: 'abandoned' });
|
|
25089
25435
|
}
|
|
25090
25436
|
// -----------------------------------------------------------------------
|
|
25091
25437
|
_run(input, token) {
|
|
@@ -25093,6 +25439,7 @@ class DepositFlow extends Flow {
|
|
|
25093
25439
|
var _a;
|
|
25094
25440
|
this._accept = null;
|
|
25095
25441
|
this._acceptingFor = null;
|
|
25442
|
+
this._authorise = null;
|
|
25096
25443
|
const ports = this._ports;
|
|
25097
25444
|
const owner = input.userAddress.toLowerCase();
|
|
25098
25445
|
// 0. The spender, from the input or from the chain config the facade
|
|
@@ -25113,21 +25460,32 @@ class DepositFlow extends Flow {
|
|
|
25113
25460
|
// live, never cached: an exact-amount approval is fully consumed by
|
|
25114
25461
|
// the deposit it paid for, so a stale allowance is exactly the value
|
|
25115
25462
|
// that would wrongly skip the approve and revert the deposit.
|
|
25116
|
-
let
|
|
25463
|
+
let allowanceShort = true;
|
|
25117
25464
|
try {
|
|
25118
25465
|
const allowance = yield ports.readAllowance(owner, spender);
|
|
25119
|
-
|
|
25466
|
+
allowanceShort = allowance.lt(input.amount);
|
|
25120
25467
|
}
|
|
25121
25468
|
catch (_b) {
|
|
25122
25469
|
// A read failure is not a reason to skip an approval. Assume one is
|
|
25123
25470
|
// needed: the cost is a redundant approve, the alternative is a
|
|
25124
25471
|
// reverted deposit.
|
|
25125
|
-
|
|
25472
|
+
allowanceShort = true;
|
|
25126
25473
|
}
|
|
25127
25474
|
if (!this._store.isCurrent(token))
|
|
25128
25475
|
return;
|
|
25476
|
+
// The path is chosen HERE, with the allowance, so the badge is right
|
|
25477
|
+
// from the first state the lender sees. Batch only when there is an
|
|
25478
|
+
// approval to fold in, a port to submit it, and a known token to
|
|
25479
|
+
// approve on — never a guessed one. A batched run never enters the
|
|
25480
|
+
// `approve` step, so every badge counts it as a three-step run.
|
|
25481
|
+
const stableAsset = this._stableAsset;
|
|
25482
|
+
const batched = allowanceShort &&
|
|
25483
|
+
typeof ports.depositBatch === 'function' &&
|
|
25484
|
+
!!stableAsset;
|
|
25485
|
+
const approvalRequired = allowanceShort && !batched;
|
|
25129
25486
|
// 2. Generate — sign the auth message.
|
|
25130
|
-
this._store.patch(Object.assign({ approvalRequired,
|
|
25487
|
+
this._store.patch(Object.assign({ approvalRequired,
|
|
25488
|
+
batched, phase: 'generating-sign' }, badgeFor('generate', approvalRequired)), token);
|
|
25131
25489
|
const timestamp = this._now();
|
|
25132
25490
|
const signedMessage = buildAuthMessage(input, owner, timestamp);
|
|
25133
25491
|
let signature;
|
|
@@ -25138,6 +25496,18 @@ class DepositFlow extends Flow {
|
|
|
25138
25496
|
this._fail(token, approvalRequired, classifyWalletFailure('generate', err));
|
|
25139
25497
|
return;
|
|
25140
25498
|
}
|
|
25499
|
+
// The same EIP-191 shape as the acceptance, and the same reason to
|
|
25500
|
+
// check it: kasu-backend verifies this one to decide whether to issue
|
|
25501
|
+
// an agreement at all, so a malformed signature is a 4xx that says
|
|
25502
|
+
// nothing about which step produced it. Named here instead.
|
|
25503
|
+
if (!isPersonalSignature(signature)) {
|
|
25504
|
+
this._fail(token, approvalRequired, {
|
|
25505
|
+
step: 'generate',
|
|
25506
|
+
reason: 'failed',
|
|
25507
|
+
error: new Error(INVALID_AUTH_SIGNATURE_MESSAGE),
|
|
25508
|
+
});
|
|
25509
|
+
return;
|
|
25510
|
+
}
|
|
25141
25511
|
if (!this._store.isCurrent(token))
|
|
25142
25512
|
return;
|
|
25143
25513
|
// 3. Generate — POST the request.
|
|
@@ -25194,12 +25564,41 @@ class DepositFlow extends Flow {
|
|
|
25194
25564
|
});
|
|
25195
25565
|
return;
|
|
25196
25566
|
}
|
|
25197
|
-
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
|
|
25201
|
-
|
|
25202
|
-
|
|
25567
|
+
// The acceptance signature is already known to be 65 bytes, but the
|
|
25568
|
+
// encoder also reads `timestamp`, `contractVersion` and
|
|
25569
|
+
// `contractType` off a response the SDK did not produce. `start()`
|
|
25570
|
+
// promises it does not reject, so anything that throws in here becomes
|
|
25571
|
+
// a failure the consumer can render rather than an unhandled rejection
|
|
25572
|
+
// in an application that was told it never had to catch one.
|
|
25573
|
+
let depositData;
|
|
25574
|
+
try {
|
|
25575
|
+
depositData = encodeDepositData({
|
|
25576
|
+
signature: outcome.signature,
|
|
25577
|
+
timestamp: contract.timestamp,
|
|
25578
|
+
contractVersion: contract.contractVersion,
|
|
25579
|
+
contractType: asContractType(contract.contractType),
|
|
25580
|
+
});
|
|
25581
|
+
}
|
|
25582
|
+
catch (err) {
|
|
25583
|
+
this._fail(token, approvalRequired, {
|
|
25584
|
+
step: 'request',
|
|
25585
|
+
reason: 'failed',
|
|
25586
|
+
error: err,
|
|
25587
|
+
});
|
|
25588
|
+
return;
|
|
25589
|
+
}
|
|
25590
|
+
if (batched && stableAsset) {
|
|
25591
|
+
yield this._runBatch({
|
|
25592
|
+
token,
|
|
25593
|
+
input,
|
|
25594
|
+
owner,
|
|
25595
|
+
spender,
|
|
25596
|
+
stableAsset,
|
|
25597
|
+
depositData,
|
|
25598
|
+
contract,
|
|
25599
|
+
});
|
|
25600
|
+
return;
|
|
25601
|
+
}
|
|
25203
25602
|
// 6. Approve — the EXACT amount, never `MaxUint256`. House rule: an
|
|
25204
25603
|
// unlimited allowance outlives the deposit it was granted for, and a
|
|
25205
25604
|
// later exploit of the spender would drain a wallet that has long
|
|
@@ -25263,6 +25662,108 @@ class DepositFlow extends Flow {
|
|
|
25263
25662
|
this._store.patch(Object.assign({ phase: 'success' }, badgeFor('request', approvalRequired)), token);
|
|
25264
25663
|
});
|
|
25265
25664
|
}
|
|
25665
|
+
/**
|
|
25666
|
+
* The batch path, from the accepted agreement to the receipt.
|
|
25667
|
+
*
|
|
25668
|
+
* 1. PARK on `awaiting-authorise`. A batch puts no wallet prompt in front
|
|
25669
|
+
* of each call, so the flow waits for an explicit authorisation before
|
|
25670
|
+
* any money moves. `declineTransfer()` ends it as `cancelled`.
|
|
25671
|
+
* 2. Re-check the TTL: the lender may have idled on the authorisation as
|
|
25672
|
+
* long as they did on the agreement.
|
|
25673
|
+
* 3. Only now fetch the KYC signature — it has a block expiration of its
|
|
25674
|
+
* own, and an authorisation left open must not spend it.
|
|
25675
|
+
* 4. Encode both calls and hand them to `depositBatch`; then the receipt.
|
|
25676
|
+
*/
|
|
25677
|
+
_runBatch(args) {
|
|
25678
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25679
|
+
const { token, input, owner, spender, stableAsset, depositData } = args;
|
|
25680
|
+
const ports = this._ports;
|
|
25681
|
+
// A batched run is a three-step run on every badge.
|
|
25682
|
+
const approvalRequired = false;
|
|
25683
|
+
// Every settler clears the handshake before settling it, so there is
|
|
25684
|
+
// nothing to clear here — and clearing it anyway could drop the
|
|
25685
|
+
// handshake of a NEWER run that `reset(); start()` already parked.
|
|
25686
|
+
const outcome = yield new Promise((resolve) => {
|
|
25687
|
+
this._authorise = { settle: resolve };
|
|
25688
|
+
this._store.patch(Object.assign({ phase: 'awaiting-authorise' }, badgeFor('request', approvalRequired)), token);
|
|
25689
|
+
});
|
|
25690
|
+
if (!this._store.isCurrent(token))
|
|
25691
|
+
return;
|
|
25692
|
+
if (outcome.kind === 'declined') {
|
|
25693
|
+
this._fail(token, approvalRequired, {
|
|
25694
|
+
step: 'request',
|
|
25695
|
+
reason: 'cancelled',
|
|
25696
|
+
});
|
|
25697
|
+
return;
|
|
25698
|
+
}
|
|
25699
|
+
if (outcome.kind !== 'authorised')
|
|
25700
|
+
return;
|
|
25701
|
+
if (this._now() > args.contract.timestamp + this._ttlMs) {
|
|
25702
|
+
this._fail(token, approvalRequired, {
|
|
25703
|
+
step: 'request',
|
|
25704
|
+
reason: 'contract-expired',
|
|
25705
|
+
});
|
|
25706
|
+
return;
|
|
25707
|
+
}
|
|
25708
|
+
this._store.patch(Object.assign({ phase: 'request-sign' }, badgeFor('request', approvalRequired)), token);
|
|
25709
|
+
// The consumer's backend, so `failed` — never `cancelled` — exactly as
|
|
25710
|
+
// on the two-transaction path.
|
|
25711
|
+
let kyc;
|
|
25712
|
+
try {
|
|
25713
|
+
const kycParams = yield ports.buildKycParams(owner);
|
|
25714
|
+
kyc = yield ports.getKycSignature(kycParams);
|
|
25715
|
+
}
|
|
25716
|
+
catch (err) {
|
|
25717
|
+
this._fail(token, approvalRequired, {
|
|
25718
|
+
step: 'request',
|
|
25719
|
+
reason: 'failed',
|
|
25720
|
+
error: err,
|
|
25721
|
+
});
|
|
25722
|
+
return;
|
|
25723
|
+
}
|
|
25724
|
+
if (!this._store.isCurrent(token))
|
|
25725
|
+
return;
|
|
25726
|
+
// Encoded from values a backend returned (the KYC signature), so a
|
|
25727
|
+
// shape the coder refuses is a failure the consumer can render, not a
|
|
25728
|
+
// rejection out of a `start()` that promises it has none.
|
|
25729
|
+
let calls;
|
|
25730
|
+
try {
|
|
25731
|
+
calls = encodeDepositBatch({
|
|
25732
|
+
stableAsset,
|
|
25733
|
+
spender,
|
|
25734
|
+
input,
|
|
25735
|
+
depositData,
|
|
25736
|
+
kyc,
|
|
25737
|
+
});
|
|
25738
|
+
}
|
|
25739
|
+
catch (err) {
|
|
25740
|
+
this._fail(token, approvalRequired, {
|
|
25741
|
+
step: 'request',
|
|
25742
|
+
reason: 'failed',
|
|
25743
|
+
error: err,
|
|
25744
|
+
});
|
|
25745
|
+
return;
|
|
25746
|
+
}
|
|
25747
|
+
try {
|
|
25748
|
+
// Called through the ports object, so a port that is a method
|
|
25749
|
+
// keeps its `this`. Its presence decided the path; a consumer
|
|
25750
|
+
// that removed it since gets a `failed`, not a crash.
|
|
25751
|
+
if (typeof ports.depositBatch !== 'function') {
|
|
25752
|
+
throw new Error('DepositFlow: the depositBatch port is gone');
|
|
25753
|
+
}
|
|
25754
|
+
const tx = yield ports.depositBatch(calls);
|
|
25755
|
+
this._store.patch(Object.assign({ phase: 'request-confirm' }, badgeFor('request', approvalRequired)), token);
|
|
25756
|
+
yield tx.wait();
|
|
25757
|
+
}
|
|
25758
|
+
catch (err) {
|
|
25759
|
+
this._fail(token, approvalRequired, classifyBatch(err));
|
|
25760
|
+
return;
|
|
25761
|
+
}
|
|
25762
|
+
if (!this._store.isCurrent(token))
|
|
25763
|
+
return;
|
|
25764
|
+
this._store.patch(Object.assign({ phase: 'success' }, badgeFor('request', approvalRequired)), token);
|
|
25765
|
+
});
|
|
25766
|
+
}
|
|
25266
25767
|
_fail(token, approvalRequired, failure) {
|
|
25267
25768
|
this._store.patch(Object.assign({ phase: 'error', failure }, badgeFor(failure.step, approvalRequired)), token);
|
|
25268
25769
|
}
|
|
@@ -25415,11 +25916,18 @@ class FlowsFacade {
|
|
|
25415
25916
|
* an address whose only wrong value grants an approval to the wrong
|
|
25416
25917
|
* contract.
|
|
25417
25918
|
*/
|
|
25418
|
-
_spender
|
|
25919
|
+
_spender,
|
|
25920
|
+
/**
|
|
25921
|
+
* This chain's stable token address — the target of the batch path's
|
|
25922
|
+
* approve. `undefined` for a hand-built config without `stableAsset`,
|
|
25923
|
+
* in which case a run never batches: it does not guess a token.
|
|
25924
|
+
*/
|
|
25925
|
+
_stableAsset) {
|
|
25419
25926
|
this._deposits = _deposits;
|
|
25420
25927
|
this._erc20 = _erc20;
|
|
25421
25928
|
this._isReadOnly = _isReadOnly;
|
|
25422
25929
|
this._spender = _spender;
|
|
25930
|
+
this._stableAsset = _stableAsset;
|
|
25423
25931
|
}
|
|
25424
25932
|
/**
|
|
25425
25933
|
* A deposit pipeline. `readAllowance`, `approve`, `deposit` and
|
|
@@ -25432,9 +25940,13 @@ class FlowsFacade {
|
|
|
25432
25940
|
* delete the default it was meant to keep, and
|
|
25433
25941
|
* `approve: sponsoredGas ? sponsoredApprove : undefined` is exactly how a
|
|
25434
25942
|
* consumer writes a conditional override.
|
|
25943
|
+
*
|
|
25944
|
+
* `depositBatch` has NO default: how several calls become one atomic
|
|
25945
|
+
* transaction is the application's business. Supplying it lets a run
|
|
25946
|
+
* whose allowance is short approve and deposit in one batch.
|
|
25435
25947
|
*/
|
|
25436
25948
|
deposit(ports, opts) {
|
|
25437
|
-
var _a, _b, _c, _d, _e;
|
|
25949
|
+
var _a, _b, _c, _d, _e, _f;
|
|
25438
25950
|
return new DepositFlow({
|
|
25439
25951
|
signMessage: ports.signMessage,
|
|
25440
25952
|
generateContract: ports.generateContract,
|
|
@@ -25449,12 +25961,14 @@ class FlowsFacade {
|
|
|
25449
25961
|
return yield this._erc20().approve(spender, amount);
|
|
25450
25962
|
})),
|
|
25451
25963
|
deposit: (_d = ports.deposit) !== null && _d !== void 0 ? _d : ((params) => this._deposits.deposit(params)),
|
|
25964
|
+
depositBatch: ports.depositBatch,
|
|
25452
25965
|
now: ports.now,
|
|
25453
25966
|
}, {
|
|
25454
25967
|
contractTtlMs: opts === null || opts === void 0 ? void 0 : opts.contractTtlMs,
|
|
25455
25968
|
// Per key here too, for the same reason the ports are: an
|
|
25456
25969
|
// explicit `spender: undefined` must not delete the default.
|
|
25457
25970
|
spender: (_e = opts === null || opts === void 0 ? void 0 : opts.spender) !== null && _e !== void 0 ? _e : this._spender,
|
|
25971
|
+
stableAsset: (_f = opts === null || opts === void 0 ? void 0 : opts.stableAsset) !== null && _f !== void 0 ? _f : this._stableAsset,
|
|
25458
25972
|
});
|
|
25459
25973
|
}
|
|
25460
25974
|
/**
|
|
@@ -26215,6 +26729,7 @@ class PortfolioFacade {
|
|
|
26215
26729
|
*/
|
|
26216
26730
|
class Kasu {
|
|
26217
26731
|
constructor(sdk, chainConfig, signerOrProvider, configOverrides) {
|
|
26732
|
+
var _a;
|
|
26218
26733
|
this._sdk = sdk;
|
|
26219
26734
|
this._chainConfig = chainConfig;
|
|
26220
26735
|
this._signerOrProvider = signerOrProvider;
|
|
@@ -26226,7 +26741,7 @@ class Kasu {
|
|
|
26226
26741
|
const isReadOnly = !Signer.isSigner(signerOrProvider);
|
|
26227
26742
|
this.deposits = new DepositsFacade(sdk.UserLending, chainConfig.chainId.toString(), isReadOnly);
|
|
26228
26743
|
this.portfolio = new PortfolioFacade(sdk.DataService, sdk.UserLending, sdk.Portfolio);
|
|
26229
|
-
this.flows = new FlowsFacade(this.deposits, () => erc20Of(chainConfig, signerOrProvider), isReadOnly, chainConfig.contracts.LendingPoolManager);
|
|
26744
|
+
this.flows = new FlowsFacade(this.deposits, () => erc20Of(chainConfig, signerOrProvider), isReadOnly, chainConfig.contracts.LendingPoolManager, (_a = stableAssetOf(chainConfig)) === null || _a === void 0 ? void 0 : _a.address);
|
|
26230
26745
|
}
|
|
26231
26746
|
/**
|
|
26232
26747
|
* Create a Kasu instance with built-in chain config.
|
|
@@ -26887,4 +27402,4 @@ function getTrancheDisplayName(trancheName, pool) {
|
|
|
26887
27402
|
: trancheName;
|
|
26888
27403
|
}
|
|
26889
27404
|
|
|
26890
|
-
export { APXIUM, AU_ALPHA3, AU_MIN_CUMULATIVE_BY_STABLE, CHAIN_CONFIGS, CLEARING_WINDOW_SECONDS, CONTRACT_TTL_MS, DepositFlow, DepositsFacade, EPOCHS_IN_YEAR, Flow, FlowStore, FlowsFacade, INVOICEMATE, Kasu, KasuSdk, MAX_LENDING_AMOUNT_FALLBACK, MIN_LENDING_AMOUNT_FALLBACK, MIN_TRANCHE_CAPACITY, NO_DIRECTUS_URL_MESSAGE, NO_KYC_PARAMS_MESSAGE, NO_SPENDER_MESSAGE, PortfolioFacade, READ_ONLY_MESSAGE, RIXON_CAPITAL, SdkConfig, StrategiesFacade, UPPER_MEZZANINE, WithdrawFlow, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, ceilToCents, classifyWalletFailure, compareTrancheSeniority, computeSettlementWindow, countSubmissions, deriveCycleDates, derivePoolStatus, deriveRequestState, encodeDepositData, epochRateToApy, fetchUnusedPoolIds, firstSubmissionTimestamp, floorToCents, formatSignTimestampUtc, getCreditOriginator, getInstitutionalLender, getTrancheDisplayName, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isUnpredictableGas, isUserRejected, lastEventTimestamp, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, poolAllTranchesFull, poolMaxApy, resolveBoundShortcuts, resolveDepositBounds, selectVisiblePools, submissionEvents, trancheApyBounds, trancheHasCapacity, trancheRiskRank };
|
|
27405
|
+
export { APXIUM, AU_ALPHA3, AU_MIN_CUMULATIVE_BY_STABLE, BatchRevertedError, CHAIN_CONFIGS, CLEARING_WINDOW_SECONDS, CONTRACT_TTL_MS, DepositFlow, DepositsFacade, EPOCHS_IN_YEAR, Flow, FlowStore, FlowsFacade, INVALID_ACCEPTANCE_SIGNATURE_MESSAGE, INVALID_AUTH_SIGNATURE_MESSAGE, INVOICEMATE, Kasu, KasuSdk, MAX_LENDING_AMOUNT_FALLBACK, MIN_LENDING_AMOUNT_FALLBACK, MIN_TRANCHE_CAPACITY, NO_DIRECTUS_URL_MESSAGE, NO_KYC_PARAMS_MESSAGE, NO_SPENDER_MESSAGE, PortfolioFacade, READ_ONLY_MESSAGE, RIXON_CAPITAL, SdkConfig, StrategiesFacade, UPPER_MEZZANINE, WithdrawFlow, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, ceilToCents, classifyWalletFailure, compareTrancheSeniority, computeSettlementWindow, countSubmissions, decodeRevert, deriveCycleDates, derivePoolStatus, deriveRequestState, encodeDepositData, epochRateToApy, extractRevertData, fetchUnusedPoolIds, firstSubmissionTimestamp, floorToCents, formatSignTimestampUtc, getCreditOriginator, getInstitutionalLender, getTrancheDisplayName, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isUnpredictableGas, isUserRejected, lastEventTimestamp, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, poolAllTranchesFull, poolMaxApy, resolveBoundShortcuts, resolveDepositBounds, selectVisiblePools, submissionEvents, trancheApyBounds, trancheHasCapacity, trancheRiskRank };
|