@kasufinance/kasu-sdk 2.10.1 → 2.10.3
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/dist/bundle.cjs.js +155 -23
- package/dist/bundle.esm.js +154 -24
- package/dist/domain/batch-proof.js +19 -12
- package/dist/domain/batch-proof.js.map +1 -1
- package/dist/domain/index.d.ts +1 -1
- package/dist/domain/index.js +1 -1
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/sponsored-calls.d.ts +34 -6
- package/dist/domain/sponsored-calls.js +65 -7
- package/dist/domain/sponsored-calls.js.map +1 -1
- package/dist/facade/strategies.js +12 -0
- package/dist/facade/strategies.js.map +1 -1
- package/dist/facade/types.d.ts +10 -0
- package/dist/flows/batch-submission.d.ts +21 -4
- package/dist/flows/batch-submission.js +59 -5
- package/dist/flows/batch-submission.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/batch-proof.ts +18 -12
- package/src/domain/index.ts +1 -0
- package/src/domain/sponsored-calls.ts +79 -13
- package/src/facade/strategies.ts +13 -0
- package/src/facade/types.ts +15 -1
- package/src/flows/batch-submission.ts +63 -6
- package/src/flows/index.ts +1 -0
package/dist/bundle.cjs.js
CHANGED
|
@@ -24219,9 +24219,10 @@ class SdkConfig {
|
|
|
24219
24219
|
}
|
|
24220
24220
|
|
|
24221
24221
|
/**
|
|
24222
|
-
* The single-call
|
|
24223
|
-
*
|
|
24224
|
-
*
|
|
24222
|
+
* The single-call requests a sponsored relay may carry — the four
|
|
24223
|
+
* `LendingPoolManager` requests, plus the stable asset's own `transfer` (P2P
|
|
24224
|
+
* Send) — encoded by the SDK so no application hand-builds calldata or
|
|
24225
|
+
* hand-maps the relay's `kind` for them.
|
|
24225
24226
|
*
|
|
24226
24227
|
* Every function here is PURE: addresses and ids in, `{ kind, call }` out.
|
|
24227
24228
|
* Reading the chain (the shares a withdrawal is for) is the facade's job —
|
|
@@ -24249,6 +24250,11 @@ const SPONSORED_CALL_KINDS = [
|
|
|
24249
24250
|
'cancel_withdrawal',
|
|
24250
24251
|
/** `LendingPoolManager.requestFixedTermDepositWithdrawal(pool, lockId)`. */
|
|
24251
24252
|
'withdraw_at_expiry',
|
|
24253
|
+
/**
|
|
24254
|
+
* `stableAsset.transfer(to, amount)` — P2P Send, to the chain's stable
|
|
24255
|
+
* asset rather than the manager. See {@link encodeStableTransfer}.
|
|
24256
|
+
*/
|
|
24257
|
+
'transfer',
|
|
24252
24258
|
];
|
|
24253
24259
|
/**
|
|
24254
24260
|
* Widened to the plain `Interface`: the typechain one overloads
|
|
@@ -24256,7 +24262,9 @@ const SPONSORED_CALL_KINDS = [
|
|
|
24256
24262
|
* `FUNCTION_OF`.
|
|
24257
24263
|
*/
|
|
24258
24264
|
const LENDING_POOL_MANAGER$2 = ILendingPoolManagerAbi__factory.createInterface();
|
|
24259
|
-
/** The `
|
|
24265
|
+
/** The generated ERC-20 interface — the `transfer` kind's one function. */
|
|
24266
|
+
const ERC20$2 = IERC20MetadataAbi__factory.createInterface();
|
|
24267
|
+
/** The `LendingPoolManager` function behind each manager kind. */
|
|
24260
24268
|
const FUNCTION_OF = Object.freeze({
|
|
24261
24269
|
withdrawal: 'requestWithdrawal',
|
|
24262
24270
|
cancel_deposit: 'cancelDepositRequest',
|
|
@@ -24265,14 +24273,16 @@ const FUNCTION_OF = Object.freeze({
|
|
|
24265
24273
|
});
|
|
24266
24274
|
/**
|
|
24267
24275
|
* The 4-byte selector of each kind's function, DERIVED from the generated
|
|
24268
|
-
* `ILendingPoolManager`
|
|
24269
|
-
* it and the cross-check spec
|
|
24276
|
+
* ABIs (`ILendingPoolManager`, and `IERC20Metadata` for `transfer`) — never
|
|
24277
|
+
* typed in by hand, so an ABI change moves it and the cross-check spec
|
|
24278
|
+
* against the relay's own pins goes red.
|
|
24270
24279
|
*/
|
|
24271
24280
|
const SPONSORED_CALL_SELECTORS = Object.freeze({
|
|
24272
24281
|
withdrawal: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.withdrawal),
|
|
24273
24282
|
cancel_deposit: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.cancel_deposit),
|
|
24274
24283
|
cancel_withdrawal: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.cancel_withdrawal),
|
|
24275
24284
|
withdraw_at_expiry: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.withdraw_at_expiry),
|
|
24285
|
+
transfer: ERC20$2.getSighash('transfer'),
|
|
24276
24286
|
});
|
|
24277
24287
|
/**
|
|
24278
24288
|
* What an encoder throws for an input it will not encode. `code` names the
|
|
@@ -24371,6 +24381,53 @@ function encodeWithdrawAtExpiryCall(lendingPoolManager, poolId, fixedTermDeposit
|
|
|
24371
24381
|
toUint256(fixedTermDepositId, 'lock-id'),
|
|
24372
24382
|
]);
|
|
24373
24383
|
}
|
|
24384
|
+
/**
|
|
24385
|
+
* `stableAsset.transfer(to, amount)` — `transfer`: P2P Send of the chain's
|
|
24386
|
+
* stable asset from the sender's own account (`msg.sender`) to `to`.
|
|
24387
|
+
*
|
|
24388
|
+
* `amount` is in the token's BASE units (6 decimals for USDC), and must be
|
|
24389
|
+
* greater than zero. `to` must be a well-formed, non-zero address (a
|
|
24390
|
+
* mixed-case one with a valid EIP-55 checksum). That is
|
|
24391
|
+
* ALL this encoder judges, because it is all a pure function can know.
|
|
24392
|
+
*
|
|
24393
|
+
* The recipient POLICY is the relay's job and is deliberately not restated
|
|
24394
|
+
* here: it refuses the sender's own account, the stable asset, the
|
|
24395
|
+
* `LendingPoolManager`, the precompile range, any address with contract code
|
|
24396
|
+
* (read on chain at submission), a sender our identity store does not hold
|
|
24397
|
+
* as verified, and anything over the sender's daily count and amount caps.
|
|
24398
|
+
* A call this encoder accepts can therefore still be refused — the app maps
|
|
24399
|
+
* the relay's refusal codes to its own words.
|
|
24400
|
+
*
|
|
24401
|
+
* Pass `stableAsset` from the chain config (`CHAIN_CONFIGS[chain].stableAsset
|
|
24402
|
+
* .address`) — the relay compares `to` against its own configured token and
|
|
24403
|
+
* refuses any other contract.
|
|
24404
|
+
*/
|
|
24405
|
+
function encodeStableTransfer(input) {
|
|
24406
|
+
assertAddress(input.stableAsset, 'stable-asset');
|
|
24407
|
+
assertAddress(input.to, 'recipient');
|
|
24408
|
+
// A mixed-case recipient carries an EIP-55 checksum, and one that does not
|
|
24409
|
+
// match is a mistyped address: refuse it as `recipient` here rather than
|
|
24410
|
+
// let the ABI coder throw its own error at the encode below.
|
|
24411
|
+
try {
|
|
24412
|
+
ethers.utils.getAddress(input.to);
|
|
24413
|
+
}
|
|
24414
|
+
catch (_a) {
|
|
24415
|
+
throw new SponsoredCallInputError('recipient');
|
|
24416
|
+
}
|
|
24417
|
+
if (ethers.BigNumber.from(input.to).isZero()) {
|
|
24418
|
+
throw new SponsoredCallInputError('zero-recipient');
|
|
24419
|
+
}
|
|
24420
|
+
const amount = toUint256(input.amount, 'amount');
|
|
24421
|
+
if (amount.isZero())
|
|
24422
|
+
throw new SponsoredCallInputError('zero-amount');
|
|
24423
|
+
return {
|
|
24424
|
+
kind: 'transfer',
|
|
24425
|
+
call: {
|
|
24426
|
+
to: input.stableAsset,
|
|
24427
|
+
data: ERC20$2.encodeFunctionData('transfer', [input.to, amount]),
|
|
24428
|
+
},
|
|
24429
|
+
};
|
|
24430
|
+
}
|
|
24374
24431
|
|
|
24375
24432
|
const ADDRESS_RE$1 = /^0x[0-9a-fA-F]{40}$/;
|
|
24376
24433
|
/**
|
|
@@ -25102,26 +25159,33 @@ function sameAmount(a, b) {
|
|
|
25102
25159
|
* this run's deposit.
|
|
25103
25160
|
*/
|
|
25104
25161
|
function decodeCanonical(iface, name, data, code) {
|
|
25105
|
-
|
|
25106
|
-
|
|
25107
|
-
|
|
25108
|
-
|
|
25109
|
-
|
|
25110
|
-
|
|
25111
|
-
|
|
25112
|
-
|
|
25113
|
-
|
|
25162
|
+
// Decode AND re-encode against the interface's OWN fragment for `name`,
|
|
25163
|
+
// never through `parseTransaction`. ethers v5's `TransactionDescription`
|
|
25164
|
+
// deep-copies its fields, and a fragment whose `inputs` array is not
|
|
25165
|
+
// frozen comes out as a plain object. Under the CommonJS build (Node,
|
|
25166
|
+
// jest) that copy still carries `format()`, because ES5 prototype methods
|
|
25167
|
+
// are enumerable; under the ES-module build a browser bundler resolves
|
|
25168
|
+
// (`lib.esm`, real classes) it carries no methods at all, so re-encoding
|
|
25169
|
+
// `parsed.functionFragment` threw and EVERY batch was refused as
|
|
25170
|
+
// `approve-call` in the browser (2.10.0, 2.10.1). With no description in
|
|
25171
|
+
// the path, nothing here depends on which copied fields survive.
|
|
25172
|
+
//
|
|
25173
|
+
// `decodeFunctionData` refuses data whose selector is not this
|
|
25174
|
+
// fragment's, so a call to any other function is `code`, as before.
|
|
25175
|
+
let args;
|
|
25114
25176
|
let canonical;
|
|
25115
25177
|
try {
|
|
25116
|
-
|
|
25178
|
+
const fragment = iface.getFunction(name);
|
|
25179
|
+
args = iface.decodeFunctionData(fragment, data);
|
|
25180
|
+
canonical = iface.encodeFunctionData(fragment, args);
|
|
25117
25181
|
}
|
|
25118
|
-
catch (
|
|
25182
|
+
catch (_a) {
|
|
25119
25183
|
return mismatch(code);
|
|
25120
25184
|
}
|
|
25121
25185
|
if (canonical.toLowerCase() !== data.toLowerCase()) {
|
|
25122
25186
|
return mismatch('non-canonical-encoding');
|
|
25123
25187
|
}
|
|
25124
|
-
return
|
|
25188
|
+
return args;
|
|
25125
25189
|
}
|
|
25126
25190
|
/**
|
|
25127
25191
|
* Pin a deposit batch to the run that produced it — PURE; throws a
|
|
@@ -25595,7 +25659,10 @@ function checkBatchOutcome(transactionId, expect, ports) {
|
|
|
25595
25659
|
}
|
|
25596
25660
|
if (read.kind === 'reverted')
|
|
25597
25661
|
return 'not-deposited';
|
|
25598
|
-
|
|
25662
|
+
// An empty hash is not an answer — `waitForMined` reads it the same way.
|
|
25663
|
+
if (read.kind !== 'mined' ||
|
|
25664
|
+
typeof read.txHash !== 'string' ||
|
|
25665
|
+
read.txHash === '') {
|
|
25599
25666
|
return 'unknown';
|
|
25600
25667
|
}
|
|
25601
25668
|
try {
|
|
@@ -25612,10 +25679,60 @@ function checkBatchOutcome(transactionId, expect, ports) {
|
|
|
25612
25679
|
}
|
|
25613
25680
|
});
|
|
25614
25681
|
}
|
|
25682
|
+
// ---------------------------------------------------------------------------
|
|
25683
|
+
// One sponsored call — withdraw, cancel, withdraw at expiry, transfer
|
|
25684
|
+
// ---------------------------------------------------------------------------
|
|
25685
|
+
/**
|
|
25686
|
+
* `checkBatchOutcome` for ONE sponsored call — ONE status read, no polling —
|
|
25687
|
+
* for an app's guard against sending the same request twice (a P2P transfer
|
|
25688
|
+
* whose earlier submission ended PENDING, say):
|
|
25689
|
+
*
|
|
25690
|
+
* - `executed` — mined, and the receipt proves the sender's operation
|
|
25691
|
+
* succeeded (`proveUserOperationInReceipt`);
|
|
25692
|
+
* - `not-executed` — definitively reverted (vendor status or the operation's
|
|
25693
|
+
* own flag);
|
|
25694
|
+
* - `unknown` — anything else, including a read or receipt that failed, or a
|
|
25695
|
+
* receipt that does not show the sender's operation.
|
|
25696
|
+
*
|
|
25697
|
+
* Only `not-executed` may let a new attempt proceed unprompted; `executed`
|
|
25698
|
+
* means the earlier one landed and the user should be told.
|
|
25699
|
+
*/
|
|
25700
|
+
function checkSponsoredCallOutcome(transactionId, expect, ports) {
|
|
25701
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25702
|
+
var _a;
|
|
25703
|
+
let read;
|
|
25704
|
+
try {
|
|
25705
|
+
read = yield ports.getStatus(transactionId);
|
|
25706
|
+
}
|
|
25707
|
+
catch (_b) {
|
|
25708
|
+
return 'unknown';
|
|
25709
|
+
}
|
|
25710
|
+
if (read.kind === 'reverted')
|
|
25711
|
+
return 'not-executed';
|
|
25712
|
+
// An empty hash is not an answer — `waitForMined` reads it the same way.
|
|
25713
|
+
if (read.kind !== 'mined' ||
|
|
25714
|
+
typeof read.txHash !== 'string' ||
|
|
25715
|
+
read.txHash === '') {
|
|
25716
|
+
return 'unknown';
|
|
25717
|
+
}
|
|
25718
|
+
try {
|
|
25719
|
+
const receipt = yield ports.getReceipt(read.txHash);
|
|
25720
|
+
const proof = proveUserOperationInReceipt(receipt, Object.assign(Object.assign({}, expect), { userOperationHash: (_a = read.userOperationHash) !== null && _a !== void 0 ? _a : null }));
|
|
25721
|
+
if (proof.kind === 'executed')
|
|
25722
|
+
return 'executed';
|
|
25723
|
+
if (proof.kind === 'reverted')
|
|
25724
|
+
return 'not-executed';
|
|
25725
|
+
return 'unknown';
|
|
25726
|
+
}
|
|
25727
|
+
catch (_c) {
|
|
25728
|
+
return 'unknown';
|
|
25729
|
+
}
|
|
25730
|
+
});
|
|
25731
|
+
}
|
|
25615
25732
|
/**
|
|
25616
|
-
* `submitBatch` for ONE sponsored
|
|
25617
|
-
* `
|
|
25618
|
-
*
|
|
25733
|
+
* `submitBatch` for ONE sponsored call — the body of a `WithdrawFlow`
|
|
25734
|
+
* `submitCall` port, of an app's cancel or withdraw-at-expiry action, and of
|
|
25735
|
+
* a P2P transfer (`encodeStableTransfer`). Same post, same polling policy, same outcome
|
|
25619
25736
|
* table; the proof is `proveUserOperationInReceipt` (the sender's operation
|
|
25620
25737
|
* succeeded) instead of the deposit proof, and an unproven receipt is
|
|
25621
25738
|
* `call_unproven:<reason>`.
|
|
@@ -25631,7 +25748,8 @@ function checkBatchOutcome(transactionId, expect, ports) {
|
|
|
25631
25748
|
* The call is checked against its kind before anything is posted — a known
|
|
25632
25749
|
* kind, exactly `{ to, data }`, and `data` opening with that kind's selector —
|
|
25633
25750
|
* and a mismatch is `BatchSubmissionError('call_mismatch', 'failed')`: nothing
|
|
25634
|
-
* was sent. Build calls with `kasu.calls
|
|
25751
|
+
* was sent. Build calls with `kasu.calls` (or `encodeStableTransfer`), and
|
|
25752
|
+
* this never fires.
|
|
25635
25753
|
*
|
|
25636
25754
|
* As on the deposit path, nothing after the post ever produces `failed`.
|
|
25637
25755
|
*/
|
|
@@ -27610,7 +27728,9 @@ class StrategiesFacade {
|
|
|
27610
27728
|
return {
|
|
27611
27729
|
id: pool.id,
|
|
27612
27730
|
name: pool.poolName,
|
|
27731
|
+
subheading: nonEmptyOrUndefined(pool.subheading),
|
|
27613
27732
|
description: pool.description,
|
|
27733
|
+
liteDescription: nonEmptyOrUndefined(pool.liteDescription),
|
|
27614
27734
|
isActive: pool.isActive,
|
|
27615
27735
|
apy: pool.apy,
|
|
27616
27736
|
tvl: pool.totalValueLocked,
|
|
@@ -27625,6 +27745,16 @@ class StrategiesFacade {
|
|
|
27625
27745
|
};
|
|
27626
27746
|
}
|
|
27627
27747
|
}
|
|
27748
|
+
/**
|
|
27749
|
+
* A CMS text field as a string, or `undefined` when it is absent, not a
|
|
27750
|
+
* string, or empty (blank included) — the CMS stores an emptied field as `''`, and an empty
|
|
27751
|
+
* subheading must read as "none", not render an empty line.
|
|
27752
|
+
*/
|
|
27753
|
+
function nonEmptyOrUndefined(value) {
|
|
27754
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
27755
|
+
? value
|
|
27756
|
+
: undefined;
|
|
27757
|
+
}
|
|
27628
27758
|
/**
|
|
27629
27759
|
* A CMS "numeric" field as a finite number, or `null`. An empty or blank
|
|
27630
27760
|
* string is UNAUTHORED, not zero.
|
|
@@ -29025,6 +29155,7 @@ exports.buildLoanAgreementSignMessage = buildLoanAgreementSignMessage;
|
|
|
29025
29155
|
exports.cancelDeadline = cancelDeadline;
|
|
29026
29156
|
exports.ceilToCents = ceilToCents;
|
|
29027
29157
|
exports.checkBatchOutcome = checkBatchOutcome;
|
|
29158
|
+
exports.checkSponsoredCallOutcome = checkSponsoredCallOutcome;
|
|
29028
29159
|
exports.classifyWalletFailure = classifyWalletFailure;
|
|
29029
29160
|
exports.compareTrancheSeniority = compareTrancheSeniority;
|
|
29030
29161
|
exports.computeSettlementWindow = computeSettlementWindow;
|
|
@@ -29038,6 +29169,7 @@ exports.encodeCancelDepositCall = encodeCancelDepositCall;
|
|
|
29038
29169
|
exports.encodeCancelWithdrawalCall = encodeCancelWithdrawalCall;
|
|
29039
29170
|
exports.encodeDepositData = encodeDepositData;
|
|
29040
29171
|
exports.encodeRequestWithdrawalCall = encodeRequestWithdrawalCall;
|
|
29172
|
+
exports.encodeStableTransfer = encodeStableTransfer;
|
|
29041
29173
|
exports.encodeWithdrawAtExpiryCall = encodeWithdrawAtExpiryCall;
|
|
29042
29174
|
exports.epochRateToApy = epochRateToApy;
|
|
29043
29175
|
exports.explorerAddressUrl = explorerAddressUrl;
|
package/dist/bundle.esm.js
CHANGED
|
@@ -24217,9 +24217,10 @@ class SdkConfig {
|
|
|
24217
24217
|
}
|
|
24218
24218
|
|
|
24219
24219
|
/**
|
|
24220
|
-
* The single-call
|
|
24221
|
-
*
|
|
24222
|
-
*
|
|
24220
|
+
* The single-call requests a sponsored relay may carry — the four
|
|
24221
|
+
* `LendingPoolManager` requests, plus the stable asset's own `transfer` (P2P
|
|
24222
|
+
* Send) — encoded by the SDK so no application hand-builds calldata or
|
|
24223
|
+
* hand-maps the relay's `kind` for them.
|
|
24223
24224
|
*
|
|
24224
24225
|
* Every function here is PURE: addresses and ids in, `{ kind, call }` out.
|
|
24225
24226
|
* Reading the chain (the shares a withdrawal is for) is the facade's job —
|
|
@@ -24247,6 +24248,11 @@ const SPONSORED_CALL_KINDS = [
|
|
|
24247
24248
|
'cancel_withdrawal',
|
|
24248
24249
|
/** `LendingPoolManager.requestFixedTermDepositWithdrawal(pool, lockId)`. */
|
|
24249
24250
|
'withdraw_at_expiry',
|
|
24251
|
+
/**
|
|
24252
|
+
* `stableAsset.transfer(to, amount)` — P2P Send, to the chain's stable
|
|
24253
|
+
* asset rather than the manager. See {@link encodeStableTransfer}.
|
|
24254
|
+
*/
|
|
24255
|
+
'transfer',
|
|
24250
24256
|
];
|
|
24251
24257
|
/**
|
|
24252
24258
|
* Widened to the plain `Interface`: the typechain one overloads
|
|
@@ -24254,7 +24260,9 @@ const SPONSORED_CALL_KINDS = [
|
|
|
24254
24260
|
* `FUNCTION_OF`.
|
|
24255
24261
|
*/
|
|
24256
24262
|
const LENDING_POOL_MANAGER$2 = ILendingPoolManagerAbi__factory.createInterface();
|
|
24257
|
-
/** The `
|
|
24263
|
+
/** The generated ERC-20 interface — the `transfer` kind's one function. */
|
|
24264
|
+
const ERC20$2 = IERC20MetadataAbi__factory.createInterface();
|
|
24265
|
+
/** The `LendingPoolManager` function behind each manager kind. */
|
|
24258
24266
|
const FUNCTION_OF = Object.freeze({
|
|
24259
24267
|
withdrawal: 'requestWithdrawal',
|
|
24260
24268
|
cancel_deposit: 'cancelDepositRequest',
|
|
@@ -24263,14 +24271,16 @@ const FUNCTION_OF = Object.freeze({
|
|
|
24263
24271
|
});
|
|
24264
24272
|
/**
|
|
24265
24273
|
* The 4-byte selector of each kind's function, DERIVED from the generated
|
|
24266
|
-
* `ILendingPoolManager`
|
|
24267
|
-
* it and the cross-check spec
|
|
24274
|
+
* ABIs (`ILendingPoolManager`, and `IERC20Metadata` for `transfer`) — never
|
|
24275
|
+
* typed in by hand, so an ABI change moves it and the cross-check spec
|
|
24276
|
+
* against the relay's own pins goes red.
|
|
24268
24277
|
*/
|
|
24269
24278
|
const SPONSORED_CALL_SELECTORS = Object.freeze({
|
|
24270
24279
|
withdrawal: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.withdrawal),
|
|
24271
24280
|
cancel_deposit: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.cancel_deposit),
|
|
24272
24281
|
cancel_withdrawal: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.cancel_withdrawal),
|
|
24273
24282
|
withdraw_at_expiry: LENDING_POOL_MANAGER$2.getSighash(FUNCTION_OF.withdraw_at_expiry),
|
|
24283
|
+
transfer: ERC20$2.getSighash('transfer'),
|
|
24274
24284
|
});
|
|
24275
24285
|
/**
|
|
24276
24286
|
* What an encoder throws for an input it will not encode. `code` names the
|
|
@@ -24369,6 +24379,53 @@ function encodeWithdrawAtExpiryCall(lendingPoolManager, poolId, fixedTermDeposit
|
|
|
24369
24379
|
toUint256(fixedTermDepositId, 'lock-id'),
|
|
24370
24380
|
]);
|
|
24371
24381
|
}
|
|
24382
|
+
/**
|
|
24383
|
+
* `stableAsset.transfer(to, amount)` — `transfer`: P2P Send of the chain's
|
|
24384
|
+
* stable asset from the sender's own account (`msg.sender`) to `to`.
|
|
24385
|
+
*
|
|
24386
|
+
* `amount` is in the token's BASE units (6 decimals for USDC), and must be
|
|
24387
|
+
* greater than zero. `to` must be a well-formed, non-zero address (a
|
|
24388
|
+
* mixed-case one with a valid EIP-55 checksum). That is
|
|
24389
|
+
* ALL this encoder judges, because it is all a pure function can know.
|
|
24390
|
+
*
|
|
24391
|
+
* The recipient POLICY is the relay's job and is deliberately not restated
|
|
24392
|
+
* here: it refuses the sender's own account, the stable asset, the
|
|
24393
|
+
* `LendingPoolManager`, the precompile range, any address with contract code
|
|
24394
|
+
* (read on chain at submission), a sender our identity store does not hold
|
|
24395
|
+
* as verified, and anything over the sender's daily count and amount caps.
|
|
24396
|
+
* A call this encoder accepts can therefore still be refused — the app maps
|
|
24397
|
+
* the relay's refusal codes to its own words.
|
|
24398
|
+
*
|
|
24399
|
+
* Pass `stableAsset` from the chain config (`CHAIN_CONFIGS[chain].stableAsset
|
|
24400
|
+
* .address`) — the relay compares `to` against its own configured token and
|
|
24401
|
+
* refuses any other contract.
|
|
24402
|
+
*/
|
|
24403
|
+
function encodeStableTransfer(input) {
|
|
24404
|
+
assertAddress(input.stableAsset, 'stable-asset');
|
|
24405
|
+
assertAddress(input.to, 'recipient');
|
|
24406
|
+
// A mixed-case recipient carries an EIP-55 checksum, and one that does not
|
|
24407
|
+
// match is a mistyped address: refuse it as `recipient` here rather than
|
|
24408
|
+
// let the ABI coder throw its own error at the encode below.
|
|
24409
|
+
try {
|
|
24410
|
+
utils$2.getAddress(input.to);
|
|
24411
|
+
}
|
|
24412
|
+
catch (_a) {
|
|
24413
|
+
throw new SponsoredCallInputError('recipient');
|
|
24414
|
+
}
|
|
24415
|
+
if (BigNumber.from(input.to).isZero()) {
|
|
24416
|
+
throw new SponsoredCallInputError('zero-recipient');
|
|
24417
|
+
}
|
|
24418
|
+
const amount = toUint256(input.amount, 'amount');
|
|
24419
|
+
if (amount.isZero())
|
|
24420
|
+
throw new SponsoredCallInputError('zero-amount');
|
|
24421
|
+
return {
|
|
24422
|
+
kind: 'transfer',
|
|
24423
|
+
call: {
|
|
24424
|
+
to: input.stableAsset,
|
|
24425
|
+
data: ERC20$2.encodeFunctionData('transfer', [input.to, amount]),
|
|
24426
|
+
},
|
|
24427
|
+
};
|
|
24428
|
+
}
|
|
24372
24429
|
|
|
24373
24430
|
const ADDRESS_RE$1 = /^0x[0-9a-fA-F]{40}$/;
|
|
24374
24431
|
/**
|
|
@@ -25100,26 +25157,33 @@ function sameAmount(a, b) {
|
|
|
25100
25157
|
* this run's deposit.
|
|
25101
25158
|
*/
|
|
25102
25159
|
function decodeCanonical(iface, name, data, code) {
|
|
25103
|
-
|
|
25104
|
-
|
|
25105
|
-
|
|
25106
|
-
|
|
25107
|
-
|
|
25108
|
-
|
|
25109
|
-
|
|
25110
|
-
|
|
25111
|
-
|
|
25160
|
+
// Decode AND re-encode against the interface's OWN fragment for `name`,
|
|
25161
|
+
// never through `parseTransaction`. ethers v5's `TransactionDescription`
|
|
25162
|
+
// deep-copies its fields, and a fragment whose `inputs` array is not
|
|
25163
|
+
// frozen comes out as a plain object. Under the CommonJS build (Node,
|
|
25164
|
+
// jest) that copy still carries `format()`, because ES5 prototype methods
|
|
25165
|
+
// are enumerable; under the ES-module build a browser bundler resolves
|
|
25166
|
+
// (`lib.esm`, real classes) it carries no methods at all, so re-encoding
|
|
25167
|
+
// `parsed.functionFragment` threw and EVERY batch was refused as
|
|
25168
|
+
// `approve-call` in the browser (2.10.0, 2.10.1). With no description in
|
|
25169
|
+
// the path, nothing here depends on which copied fields survive.
|
|
25170
|
+
//
|
|
25171
|
+
// `decodeFunctionData` refuses data whose selector is not this
|
|
25172
|
+
// fragment's, so a call to any other function is `code`, as before.
|
|
25173
|
+
let args;
|
|
25112
25174
|
let canonical;
|
|
25113
25175
|
try {
|
|
25114
|
-
|
|
25176
|
+
const fragment = iface.getFunction(name);
|
|
25177
|
+
args = iface.decodeFunctionData(fragment, data);
|
|
25178
|
+
canonical = iface.encodeFunctionData(fragment, args);
|
|
25115
25179
|
}
|
|
25116
|
-
catch (
|
|
25180
|
+
catch (_a) {
|
|
25117
25181
|
return mismatch(code);
|
|
25118
25182
|
}
|
|
25119
25183
|
if (canonical.toLowerCase() !== data.toLowerCase()) {
|
|
25120
25184
|
return mismatch('non-canonical-encoding');
|
|
25121
25185
|
}
|
|
25122
|
-
return
|
|
25186
|
+
return args;
|
|
25123
25187
|
}
|
|
25124
25188
|
/**
|
|
25125
25189
|
* Pin a deposit batch to the run that produced it — PURE; throws a
|
|
@@ -25593,7 +25657,10 @@ function checkBatchOutcome(transactionId, expect, ports) {
|
|
|
25593
25657
|
}
|
|
25594
25658
|
if (read.kind === 'reverted')
|
|
25595
25659
|
return 'not-deposited';
|
|
25596
|
-
|
|
25660
|
+
// An empty hash is not an answer — `waitForMined` reads it the same way.
|
|
25661
|
+
if (read.kind !== 'mined' ||
|
|
25662
|
+
typeof read.txHash !== 'string' ||
|
|
25663
|
+
read.txHash === '') {
|
|
25597
25664
|
return 'unknown';
|
|
25598
25665
|
}
|
|
25599
25666
|
try {
|
|
@@ -25610,10 +25677,60 @@ function checkBatchOutcome(transactionId, expect, ports) {
|
|
|
25610
25677
|
}
|
|
25611
25678
|
});
|
|
25612
25679
|
}
|
|
25680
|
+
// ---------------------------------------------------------------------------
|
|
25681
|
+
// One sponsored call — withdraw, cancel, withdraw at expiry, transfer
|
|
25682
|
+
// ---------------------------------------------------------------------------
|
|
25683
|
+
/**
|
|
25684
|
+
* `checkBatchOutcome` for ONE sponsored call — ONE status read, no polling —
|
|
25685
|
+
* for an app's guard against sending the same request twice (a P2P transfer
|
|
25686
|
+
* whose earlier submission ended PENDING, say):
|
|
25687
|
+
*
|
|
25688
|
+
* - `executed` — mined, and the receipt proves the sender's operation
|
|
25689
|
+
* succeeded (`proveUserOperationInReceipt`);
|
|
25690
|
+
* - `not-executed` — definitively reverted (vendor status or the operation's
|
|
25691
|
+
* own flag);
|
|
25692
|
+
* - `unknown` — anything else, including a read or receipt that failed, or a
|
|
25693
|
+
* receipt that does not show the sender's operation.
|
|
25694
|
+
*
|
|
25695
|
+
* Only `not-executed` may let a new attempt proceed unprompted; `executed`
|
|
25696
|
+
* means the earlier one landed and the user should be told.
|
|
25697
|
+
*/
|
|
25698
|
+
function checkSponsoredCallOutcome(transactionId, expect, ports) {
|
|
25699
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25700
|
+
var _a;
|
|
25701
|
+
let read;
|
|
25702
|
+
try {
|
|
25703
|
+
read = yield ports.getStatus(transactionId);
|
|
25704
|
+
}
|
|
25705
|
+
catch (_b) {
|
|
25706
|
+
return 'unknown';
|
|
25707
|
+
}
|
|
25708
|
+
if (read.kind === 'reverted')
|
|
25709
|
+
return 'not-executed';
|
|
25710
|
+
// An empty hash is not an answer — `waitForMined` reads it the same way.
|
|
25711
|
+
if (read.kind !== 'mined' ||
|
|
25712
|
+
typeof read.txHash !== 'string' ||
|
|
25713
|
+
read.txHash === '') {
|
|
25714
|
+
return 'unknown';
|
|
25715
|
+
}
|
|
25716
|
+
try {
|
|
25717
|
+
const receipt = yield ports.getReceipt(read.txHash);
|
|
25718
|
+
const proof = proveUserOperationInReceipt(receipt, Object.assign(Object.assign({}, expect), { userOperationHash: (_a = read.userOperationHash) !== null && _a !== void 0 ? _a : null }));
|
|
25719
|
+
if (proof.kind === 'executed')
|
|
25720
|
+
return 'executed';
|
|
25721
|
+
if (proof.kind === 'reverted')
|
|
25722
|
+
return 'not-executed';
|
|
25723
|
+
return 'unknown';
|
|
25724
|
+
}
|
|
25725
|
+
catch (_c) {
|
|
25726
|
+
return 'unknown';
|
|
25727
|
+
}
|
|
25728
|
+
});
|
|
25729
|
+
}
|
|
25613
25730
|
/**
|
|
25614
|
-
* `submitBatch` for ONE sponsored
|
|
25615
|
-
* `
|
|
25616
|
-
*
|
|
25731
|
+
* `submitBatch` for ONE sponsored call — the body of a `WithdrawFlow`
|
|
25732
|
+
* `submitCall` port, of an app's cancel or withdraw-at-expiry action, and of
|
|
25733
|
+
* a P2P transfer (`encodeStableTransfer`). Same post, same polling policy, same outcome
|
|
25617
25734
|
* table; the proof is `proveUserOperationInReceipt` (the sender's operation
|
|
25618
25735
|
* succeeded) instead of the deposit proof, and an unproven receipt is
|
|
25619
25736
|
* `call_unproven:<reason>`.
|
|
@@ -25629,7 +25746,8 @@ function checkBatchOutcome(transactionId, expect, ports) {
|
|
|
25629
25746
|
* The call is checked against its kind before anything is posted — a known
|
|
25630
25747
|
* kind, exactly `{ to, data }`, and `data` opening with that kind's selector —
|
|
25631
25748
|
* and a mismatch is `BatchSubmissionError('call_mismatch', 'failed')`: nothing
|
|
25632
|
-
* was sent. Build calls with `kasu.calls
|
|
25749
|
+
* was sent. Build calls with `kasu.calls` (or `encodeStableTransfer`), and
|
|
25750
|
+
* this never fires.
|
|
25633
25751
|
*
|
|
25634
25752
|
* As on the deposit path, nothing after the post ever produces `failed`.
|
|
25635
25753
|
*/
|
|
@@ -27608,7 +27726,9 @@ class StrategiesFacade {
|
|
|
27608
27726
|
return {
|
|
27609
27727
|
id: pool.id,
|
|
27610
27728
|
name: pool.poolName,
|
|
27729
|
+
subheading: nonEmptyOrUndefined(pool.subheading),
|
|
27611
27730
|
description: pool.description,
|
|
27731
|
+
liteDescription: nonEmptyOrUndefined(pool.liteDescription),
|
|
27612
27732
|
isActive: pool.isActive,
|
|
27613
27733
|
apy: pool.apy,
|
|
27614
27734
|
tvl: pool.totalValueLocked,
|
|
@@ -27623,6 +27743,16 @@ class StrategiesFacade {
|
|
|
27623
27743
|
};
|
|
27624
27744
|
}
|
|
27625
27745
|
}
|
|
27746
|
+
/**
|
|
27747
|
+
* A CMS text field as a string, or `undefined` when it is absent, not a
|
|
27748
|
+
* string, or empty (blank included) — the CMS stores an emptied field as `''`, and an empty
|
|
27749
|
+
* subheading must read as "none", not render an empty line.
|
|
27750
|
+
*/
|
|
27751
|
+
function nonEmptyOrUndefined(value) {
|
|
27752
|
+
return typeof value === 'string' && value.trim().length > 0
|
|
27753
|
+
? value
|
|
27754
|
+
: undefined;
|
|
27755
|
+
}
|
|
27626
27756
|
/**
|
|
27627
27757
|
* A CMS "numeric" field as a finite number, or `null`. An empty or blank
|
|
27628
27758
|
* string is UNAUTHORED, not zero.
|
|
@@ -28963,4 +29093,4 @@ function weightedAverageApy(slices) {
|
|
|
28963
29093
|
return weighted / totalBalance;
|
|
28964
29094
|
}
|
|
28965
29095
|
|
|
28966
|
-
export { APXIUM, AU_ALPHA3, AU_MIN_CUMULATIVE_BY_STABLE, BatchPendingError, BatchRevertedError, BatchSubmissionError, CHAIN_CONFIGS, CLEARING_WINDOW_SECONDS, CONTRACT_TTL_MS, CallsFacade, DAYS_PER_EPOCH, DAYS_PER_MONTH, DEFAULT_BATCH_POLLING_POLICY, DepositBatchMismatchError, DepositFlow, DepositsFacade, ENTRY_POINT_V07, EPOCHS_IN_YEAR, Flow, FlowStore, FlowsFacade, INVALID_ACCEPTANCE_SIGNATURE_MESSAGE, INVALID_AUTH_SIGNATURE_MESSAGE, INVOICEMATE, Kasu, KasuSdk, MAX_LENDING_AMOUNT_FALLBACK, MIN_DAYS_FOR_MONTHS, MIN_LENDING_AMOUNT_FALLBACK, MIN_TRANCHE_CAPACITY, NOT_A_WITHDRAWAL_CALL_MESSAGE, NO_DIRECTUS_URL_MESSAGE, NO_KYC_PARAMS_MESSAGE, NO_SPENDER_MESSAGE, NO_WITHDRAWAL_ENCODER_MESSAGE, PortfolioFacade, READ_ONLY_MESSAGE, RIXON_CAPITAL, SECONDS_PER_WEEK, SPONSORED_CALL_KINDS, SPONSORED_CALL_SELECTORS, SdkConfig, SponsoredCallInputError, StrategiesFacade, UPPER_MEZZANINE, WithdrawFlow, accruedInterest, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, availableFixedTermConfigs, batchOutcomeOf, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, cancelDeadline, ceilToCents, checkBatchOutcome, classifyWalletFailure, compareTrancheSeniority, computeSettlementWindow, countSubmissions, dailyInterest, decodeRevert, deriveCycleDates, derivePoolStatus, deriveRequestState, encodeCancelDepositCall, encodeCancelWithdrawalCall, encodeDepositData, encodeRequestWithdrawalCall, encodeWithdrawAtExpiryCall, epochRateToApy, explorerAddressUrl, explorerTxUrl, extractRevertData, fetchUnusedPoolIds, firstSubmissionTimestamp, floorToCents, formatSignTimestampUtc, getCreditOriginator, getInstitutionalLender, getStrategyRegion, getTrancheDisplayName, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isDefinitivelyNotSubmitted, isFixedTermConfigId, isUnpredictableGas, isUserRejected, lastEventTimestamp, lockDurationDays, lockDurationMonths, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, poolAllTranchesFull, poolMaxApy, projectedAnnualEarnings, proveDepositInReceipt, proveUserOperationInReceipt, resolveBoundShortcuts, resolveDepositBounds, selectVisiblePools, submissionEvents, submitBatch, submitSponsoredCall, trancheApyBounds, trancheHasCapacity, trancheRiskRank, validateDepositBatchCalls, weeklyInterest, weightedAverageApy };
|
|
29096
|
+
export { APXIUM, AU_ALPHA3, AU_MIN_CUMULATIVE_BY_STABLE, BatchPendingError, BatchRevertedError, BatchSubmissionError, CHAIN_CONFIGS, CLEARING_WINDOW_SECONDS, CONTRACT_TTL_MS, CallsFacade, DAYS_PER_EPOCH, DAYS_PER_MONTH, DEFAULT_BATCH_POLLING_POLICY, DepositBatchMismatchError, DepositFlow, DepositsFacade, ENTRY_POINT_V07, EPOCHS_IN_YEAR, Flow, FlowStore, FlowsFacade, INVALID_ACCEPTANCE_SIGNATURE_MESSAGE, INVALID_AUTH_SIGNATURE_MESSAGE, INVOICEMATE, Kasu, KasuSdk, MAX_LENDING_AMOUNT_FALLBACK, MIN_DAYS_FOR_MONTHS, MIN_LENDING_AMOUNT_FALLBACK, MIN_TRANCHE_CAPACITY, NOT_A_WITHDRAWAL_CALL_MESSAGE, NO_DIRECTUS_URL_MESSAGE, NO_KYC_PARAMS_MESSAGE, NO_SPENDER_MESSAGE, NO_WITHDRAWAL_ENCODER_MESSAGE, PortfolioFacade, READ_ONLY_MESSAGE, RIXON_CAPITAL, SECONDS_PER_WEEK, SPONSORED_CALL_KINDS, SPONSORED_CALL_SELECTORS, SdkConfig, SponsoredCallInputError, StrategiesFacade, UPPER_MEZZANINE, WithdrawFlow, accruedInterest, apyToEpochRate, asContractType, auMinimumRemaining, auThresholdFor, availableFixedTermConfigs, batchOutcomeOf, buildContractVersionType, buildFullNameRequestMessage, buildLegacyContractRequestMessage, buildLoanAgreementSignMessage, cancelDeadline, ceilToCents, checkBatchOutcome, checkSponsoredCallOutcome, classifyWalletFailure, compareTrancheSeniority, computeSettlementWindow, countSubmissions, dailyInterest, decodeRevert, deriveCycleDates, derivePoolStatus, deriveRequestState, encodeCancelDepositCall, encodeCancelWithdrawalCall, encodeDepositData, encodeRequestWithdrawalCall, encodeStableTransfer, encodeWithdrawAtExpiryCall, epochRateToApy, explorerAddressUrl, explorerTxUrl, extractRevertData, fetchUnusedPoolIds, firstSubmissionTimestamp, floorToCents, formatSignTimestampUtc, getCreditOriginator, getInstitutionalLender, getStrategyRegion, getTrancheDisplayName, isAuMinimumExempt, isAustralianKyc, isBelowMinimumCapacity, isCycleClosed, isDefinitivelyNotSubmitted, isFixedTermConfigId, isUnpredictableGas, isUserRejected, lastEventTimestamp, lockDurationDays, lockDurationMonths, maxNetRateCeiling, netEffectiveApy, netTrancheApyBounds, nextCycleBoundary, parseFormattedMessage, parseMinorUnits, parseTrancheBound, pickDefaultTrancheId, pickHighestYieldTranche, poolAllTranchesFull, poolMaxApy, projectedAnnualEarnings, proveDepositInReceipt, proveUserOperationInReceipt, resolveBoundShortcuts, resolveDepositBounds, selectVisiblePools, submissionEvents, submitBatch, submitSponsoredCall, trancheApyBounds, trancheHasCapacity, trancheRiskRank, validateDepositBatchCalls, weeklyInterest, weightedAverageApy };
|
|
@@ -98,26 +98,33 @@ function sameAmount(a, b) {
|
|
|
98
98
|
* this run's deposit.
|
|
99
99
|
*/
|
|
100
100
|
function decodeCanonical(iface, name, data, code) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
101
|
+
// Decode AND re-encode against the interface's OWN fragment for `name`,
|
|
102
|
+
// never through `parseTransaction`. ethers v5's `TransactionDescription`
|
|
103
|
+
// deep-copies its fields, and a fragment whose `inputs` array is not
|
|
104
|
+
// frozen comes out as a plain object. Under the CommonJS build (Node,
|
|
105
|
+
// jest) that copy still carries `format()`, because ES5 prototype methods
|
|
106
|
+
// are enumerable; under the ES-module build a browser bundler resolves
|
|
107
|
+
// (`lib.esm`, real classes) it carries no methods at all, so re-encoding
|
|
108
|
+
// `parsed.functionFragment` threw and EVERY batch was refused as
|
|
109
|
+
// `approve-call` in the browser (2.10.0, 2.10.1). With no description in
|
|
110
|
+
// the path, nothing here depends on which copied fields survive.
|
|
111
|
+
//
|
|
112
|
+
// `decodeFunctionData` refuses data whose selector is not this
|
|
113
|
+
// fragment's, so a call to any other function is `code`, as before.
|
|
114
|
+
let args;
|
|
110
115
|
let canonical;
|
|
111
116
|
try {
|
|
112
|
-
|
|
117
|
+
const fragment = iface.getFunction(name);
|
|
118
|
+
args = iface.decodeFunctionData(fragment, data);
|
|
119
|
+
canonical = iface.encodeFunctionData(fragment, args);
|
|
113
120
|
}
|
|
114
|
-
catch (
|
|
121
|
+
catch (_a) {
|
|
115
122
|
return mismatch(code);
|
|
116
123
|
}
|
|
117
124
|
if (canonical.toLowerCase() !== data.toLowerCase()) {
|
|
118
125
|
return mismatch('non-canonical-encoding');
|
|
119
126
|
}
|
|
120
|
-
return
|
|
127
|
+
return args;
|
|
121
128
|
}
|
|
122
129
|
/**
|
|
123
130
|
* Pin a deposit batch to the run that produced it — PURE; throws a
|