@kasufinance/kasu-sdk 2.8.0 → 2.10.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 +120 -9
- package/dist/bundle.cjs.js +2068 -478
- package/dist/bundle.esm.js +2030 -480
- package/dist/domain/batch-proof.d.ts +210 -0
- package/dist/domain/batch-proof.js +384 -0
- package/dist/domain/batch-proof.js.map +1 -0
- package/dist/domain/explorer-urls.d.ts +33 -0
- package/dist/domain/explorer-urls.js +38 -0
- package/dist/domain/explorer-urls.js.map +1 -0
- package/dist/domain/fixed-term.d.ts +74 -0
- package/dist/domain/fixed-term.js +86 -0
- package/dist/domain/fixed-term.js.map +1 -0
- package/dist/domain/index.d.ts +12 -2
- package/dist/domain/index.js +7 -2
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/partners.d.ts +29 -0
- package/dist/domain/partners.js +20 -0
- package/dist/domain/partners.js.map +1 -1
- package/dist/domain/requests.d.ts +24 -0
- package/dist/domain/requests.js +33 -0
- package/dist/domain/requests.js.map +1 -1
- package/dist/domain/sponsored-calls.d.ts +74 -0
- package/dist/domain/sponsored-calls.js +156 -0
- package/dist/domain/sponsored-calls.js.map +1 -0
- package/dist/domain/yields.d.ts +121 -0
- package/dist/domain/yields.js +151 -0
- package/dist/domain/yields.js.map +1 -0
- package/dist/facade/calls.d.ts +59 -0
- package/dist/facade/calls.js +89 -0
- package/dist/facade/calls.js.map +1 -0
- package/dist/facade/chain-configs.js +5 -0
- package/dist/facade/chain-configs.js.map +1 -1
- package/dist/facade/flows.d.ts +24 -3
- package/dist/facade/flows.js +22 -2
- package/dist/facade/flows.js.map +1 -1
- package/dist/facade/index.d.ts +3 -1
- package/dist/facade/index.js +1 -0
- package/dist/facade/index.js.map +1 -1
- package/dist/facade/kasu.d.ts +8 -2
- package/dist/facade/kasu.js +17 -5
- package/dist/facade/kasu.js.map +1 -1
- package/dist/facade/strategies.d.ts +43 -2
- package/dist/facade/strategies.js +80 -4
- package/dist/facade/strategies.js.map +1 -1
- package/dist/facade/types.d.ts +18 -0
- package/dist/flows/batch-errors.d.ts +74 -0
- package/dist/flows/batch-errors.js +83 -0
- package/dist/flows/batch-errors.js.map +1 -0
- package/dist/flows/batch-submission.d.ts +223 -0
- package/dist/flows/batch-submission.js +321 -0
- package/dist/flows/batch-submission.js.map +1 -0
- package/dist/flows/deposit-flow.d.ts +13 -20
- package/dist/flows/deposit-flow.js +14 -25
- package/dist/flows/deposit-flow.js.map +1 -1
- package/dist/flows/index.d.ts +6 -2
- package/dist/flows/index.js +4 -2
- package/dist/flows/index.js.map +1 -1
- package/dist/flows/withdraw-flow.d.ts +95 -4
- package/dist/flows/withdraw-flow.js +107 -2
- package/dist/flows/withdraw-flow.js.map +1 -1
- package/dist/services/DataService/queries.js +1 -0
- package/dist/services/DataService/queries.js.map +1 -1
- package/dist/services/UserLending/user-lending.d.ts +13 -0
- package/dist/services/UserLending/user-lending.js +25 -4
- package/dist/services/UserLending/user-lending.js.map +1 -1
- package/package.json +1 -1
- package/src/domain/batch-proof.ts +576 -0
- package/src/domain/explorer-urls.ts +74 -0
- package/src/domain/fixed-term.ts +115 -0
- package/src/domain/index.ts +56 -0
- package/src/domain/partners.ts +35 -0
- package/src/domain/requests.ts +37 -0
- package/src/domain/sponsored-calls.ts +213 -0
- package/src/domain/yields.ts +189 -0
- package/src/facade/calls.ts +135 -0
- package/src/facade/chain-configs.ts +5 -0
- package/src/facade/flows.ts +23 -2
- package/src/facade/index.ts +3 -0
- package/src/facade/kasu.ts +31 -2
- package/src/facade/strategies.ts +98 -7
- package/src/facade/types.ts +19 -0
- package/src/flows/batch-errors.ts +118 -0
- package/src/flows/batch-submission.ts +511 -0
- package/src/flows/deposit-flow.ts +27 -33
- package/src/flows/index.ts +33 -2
- package/src/flows/withdraw-flow.ts +219 -10
- package/src/services/DataService/queries.ts +1 -0
- package/src/services/UserLending/user-lending.ts +38 -10
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { BigNumber, constants } from 'ethers';
|
|
2
|
+
import { ILendingPoolManagerAbi__factory } from '../contracts/factories/ILendingPoolManagerAbi__factory';
|
|
3
|
+
/**
|
|
4
|
+
* The single-call `LendingPoolManager` requests a sponsored relay may carry,
|
|
5
|
+
* encoded by the SDK so no application hand-builds calldata or hand-maps the
|
|
6
|
+
* relay's `kind` for them.
|
|
7
|
+
*
|
|
8
|
+
* Every function here is PURE: addresses and ids in, `{ kind, call }` out.
|
|
9
|
+
* Reading the chain (the shares a withdrawal is for) is the facade's job —
|
|
10
|
+
* `kasu.calls` — and sending is the application's.
|
|
11
|
+
*
|
|
12
|
+
* Each call is `{ to, data }` and nothing else: no `value` (none of these
|
|
13
|
+
* functions is payable), no `from` (the manager acts for `msg.sender`, the
|
|
14
|
+
* lender's own account, which is why none of them takes a user argument).
|
|
15
|
+
* `data` is ethers' ABI encoding, which is canonical by construction — the
|
|
16
|
+
* relay re-encodes what it decodes and refuses anything that differs, so a
|
|
17
|
+
* hand-tweaked blob never gets through, and an SDK-built one always matches.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* The relay's name for each shape. Carried beside the call so the app posts
|
|
21
|
+
* `kind` from the SDK, never from a table of its own — a request declaring the
|
|
22
|
+
* wrong kind is refused (`invalid_calls`), so a hand-mapped table that drifts
|
|
23
|
+
* turns into a lender who cannot withdraw.
|
|
24
|
+
*/
|
|
25
|
+
export const SPONSORED_CALL_KINDS = [
|
|
26
|
+
/** `LendingPoolManager.requestWithdrawal(pool, tranche, shares)`. */
|
|
27
|
+
'withdrawal',
|
|
28
|
+
/** `LendingPoolManager.cancelDepositRequest(pool, dNftID)`. */
|
|
29
|
+
'cancel_deposit',
|
|
30
|
+
/** `LendingPoolManager.cancelWithdrawalRequest(pool, wNftID)`. */
|
|
31
|
+
'cancel_withdrawal',
|
|
32
|
+
/** `LendingPoolManager.requestFixedTermDepositWithdrawal(pool, lockId)`. */
|
|
33
|
+
'withdraw_at_expiry',
|
|
34
|
+
];
|
|
35
|
+
/**
|
|
36
|
+
* Widened to the plain `Interface`: the typechain one overloads
|
|
37
|
+
* `encodeFunctionData` per literal name, and the name here comes from
|
|
38
|
+
* `FUNCTION_OF`.
|
|
39
|
+
*/
|
|
40
|
+
const LENDING_POOL_MANAGER = ILendingPoolManagerAbi__factory.createInterface();
|
|
41
|
+
/** The `LendingPoolManager` function behind each kind. */
|
|
42
|
+
const FUNCTION_OF = Object.freeze({
|
|
43
|
+
withdrawal: 'requestWithdrawal',
|
|
44
|
+
cancel_deposit: 'cancelDepositRequest',
|
|
45
|
+
cancel_withdrawal: 'cancelWithdrawalRequest',
|
|
46
|
+
withdraw_at_expiry: 'requestFixedTermDepositWithdrawal',
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* The 4-byte selector of each kind's function, DERIVED from the generated
|
|
50
|
+
* `ILendingPoolManager` ABI — never typed in by hand, so an ABI change moves
|
|
51
|
+
* it and the cross-check spec against the relay's own pins goes red.
|
|
52
|
+
*/
|
|
53
|
+
export const SPONSORED_CALL_SELECTORS = Object.freeze({
|
|
54
|
+
withdrawal: LENDING_POOL_MANAGER.getSighash(FUNCTION_OF.withdrawal),
|
|
55
|
+
cancel_deposit: LENDING_POOL_MANAGER.getSighash(FUNCTION_OF.cancel_deposit),
|
|
56
|
+
cancel_withdrawal: LENDING_POOL_MANAGER.getSighash(FUNCTION_OF.cancel_withdrawal),
|
|
57
|
+
withdraw_at_expiry: LENDING_POOL_MANAGER.getSighash(FUNCTION_OF.withdraw_at_expiry),
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* What an encoder throws for an input it will not encode. `code` names the
|
|
61
|
+
* argument; the message names no party, so a wallet-rejection classifier can
|
|
62
|
+
* never read it as something the lender did. Nothing has been sent when this
|
|
63
|
+
* is thrown.
|
|
64
|
+
*/
|
|
65
|
+
export class SponsoredCallInputError extends Error {
|
|
66
|
+
constructor(code) {
|
|
67
|
+
super(`Sponsored call input refused (${code})`);
|
|
68
|
+
this.name = 'SponsoredCallInputError';
|
|
69
|
+
this.code = code;
|
|
70
|
+
Object.setPrototypeOf(this, SponsoredCallInputError.prototype);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
74
|
+
function assertAddress(value, code) {
|
|
75
|
+
if (typeof value !== 'string' || !ADDRESS_RE.test(value)) {
|
|
76
|
+
throw new SponsoredCallInputError(code);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** A uint256 — an NFT or lock id. Zero is a valid id as far as encoding goes. */
|
|
80
|
+
function toUint256(value, code) {
|
|
81
|
+
let parsed;
|
|
82
|
+
try {
|
|
83
|
+
parsed = BigNumber.from(value);
|
|
84
|
+
}
|
|
85
|
+
catch (_a) {
|
|
86
|
+
throw new SponsoredCallInputError(code);
|
|
87
|
+
}
|
|
88
|
+
if (parsed.isNegative() || parsed.gt(constants.MaxUint256)) {
|
|
89
|
+
throw new SponsoredCallInputError(code);
|
|
90
|
+
}
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
function encode(kind, lendingPoolManager, args) {
|
|
94
|
+
return {
|
|
95
|
+
kind,
|
|
96
|
+
call: {
|
|
97
|
+
to: lendingPoolManager,
|
|
98
|
+
data: LENDING_POOL_MANAGER.encodeFunctionData(FUNCTION_OF[kind], args),
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* `requestWithdrawal(poolId, trancheId, shares)` — `withdrawal`.
|
|
104
|
+
*
|
|
105
|
+
* `shares` are tranche SHARES, not assets: `kasu.calls.requestWithdrawal`
|
|
106
|
+
* converts an asset amount (or `'max'`) into them exactly as
|
|
107
|
+
* `UserLending.requestWithdrawalInAsset` / `requestWithdrawalMax` do. Zero
|
|
108
|
+
* shares is refused here: the contract reverts on it
|
|
109
|
+
* (`RequestWithdrawSharesAreZero`) and the relay refuses it before that.
|
|
110
|
+
*/
|
|
111
|
+
export function encodeRequestWithdrawalCall(lendingPoolManager, poolId, trancheId, shares) {
|
|
112
|
+
assertAddress(lendingPoolManager, 'lending-pool-manager');
|
|
113
|
+
assertAddress(poolId, 'pool');
|
|
114
|
+
assertAddress(trancheId, 'tranche');
|
|
115
|
+
const amount = toUint256(shares, 'shares');
|
|
116
|
+
if (amount.isZero())
|
|
117
|
+
throw new SponsoredCallInputError('zero-shares');
|
|
118
|
+
return encode('withdrawal', lendingPoolManager, [
|
|
119
|
+
poolId,
|
|
120
|
+
trancheId,
|
|
121
|
+
amount,
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
124
|
+
/** `cancelDepositRequest(poolId, dNftId)` — `cancel_deposit`. */
|
|
125
|
+
export function encodeCancelDepositCall(lendingPoolManager, poolId, dNftId) {
|
|
126
|
+
assertAddress(lendingPoolManager, 'lending-pool-manager');
|
|
127
|
+
assertAddress(poolId, 'pool');
|
|
128
|
+
return encode('cancel_deposit', lendingPoolManager, [
|
|
129
|
+
poolId,
|
|
130
|
+
toUint256(dNftId, 'nft-id'),
|
|
131
|
+
]);
|
|
132
|
+
}
|
|
133
|
+
/** `cancelWithdrawalRequest(poolId, wNftId)` — `cancel_withdrawal`. */
|
|
134
|
+
export function encodeCancelWithdrawalCall(lendingPoolManager, poolId, wNftId) {
|
|
135
|
+
assertAddress(lendingPoolManager, 'lending-pool-manager');
|
|
136
|
+
assertAddress(poolId, 'pool');
|
|
137
|
+
return encode('cancel_withdrawal', lendingPoolManager, [
|
|
138
|
+
poolId,
|
|
139
|
+
toUint256(wNftId, 'nft-id'),
|
|
140
|
+
]);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* `requestFixedTermDepositWithdrawal(poolId, fixedTermDepositId)` —
|
|
144
|
+
* `withdraw_at_expiry`. The contract function takes the pool and the LOCK id
|
|
145
|
+
* only (no tranche): the manager forwards to the fixed-term contract on the
|
|
146
|
+
* lender's behalf, which knows the lock's tranche.
|
|
147
|
+
*/
|
|
148
|
+
export function encodeWithdrawAtExpiryCall(lendingPoolManager, poolId, fixedTermDepositId) {
|
|
149
|
+
assertAddress(lendingPoolManager, 'lending-pool-manager');
|
|
150
|
+
assertAddress(poolId, 'pool');
|
|
151
|
+
return encode('withdraw_at_expiry', lendingPoolManager, [
|
|
152
|
+
poolId,
|
|
153
|
+
toUint256(fixedTermDepositId, 'lock-id'),
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=sponsored-calls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sponsored-calls.js","sourceRoot":"","sources":["../../src/domain/sponsored-calls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forward-looking interest on a lender's CURRENT balances — the figures a
|
|
3
|
+
* portfolio shows as "weekly", "daily" and the moving part of "lifetime"
|
|
4
|
+
* interest, and the "≈ $Y a year" line beside a lend amount.
|
|
5
|
+
*
|
|
6
|
+
* Every figure is NET of the platform performance fee, the way the chain
|
|
7
|
+
* credits it: `LendingPool._applyTrancheInterest` mints the lender
|
|
8
|
+
* `interest × (1 − performanceFee)` at each cycle close, and only that net
|
|
9
|
+
* amount ever reaches the balance. A gross projection would out-run what the
|
|
10
|
+
* next close actually credits.
|
|
11
|
+
*
|
|
12
|
+
* Units: balances and results are display units of the deployment's stable
|
|
13
|
+
* asset (not base units); rates are 0..1 fractions; `feePercent` is a
|
|
14
|
+
* PERCENTAGE IN 0..100 — see `netEffectiveApy`.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Seconds in one epoch's nominal week. The per-epoch rate covers exactly this
|
|
18
|
+
* window, and the accrual spreads an epoch's interest across it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SECONDS_PER_WEEK = 604800;
|
|
21
|
+
/** One slice of a position that earns at a single rate. */
|
|
22
|
+
export interface InterestSlice {
|
|
23
|
+
/** The lender's current balance in this slice, in stable display units. */
|
|
24
|
+
balance: number;
|
|
25
|
+
/**
|
|
26
|
+
* The RAW per-epoch rate the chain applies to this slice at each close,
|
|
27
|
+
* as a 0..1 fraction (`0.00285` ≈ 0.285% an epoch) — the subgraph's
|
|
28
|
+
* `TrancheData.interestRate` or a fixed-term config's
|
|
29
|
+
* `epochInterestRate`. Never derived from an APY.
|
|
30
|
+
*
|
|
31
|
+
* NON-FINITE means UNKNOWN, not zero. A zero is a genuinely zero
|
|
32
|
+
* configured rate and contributes a real 0; the two must stay
|
|
33
|
+
* distinguishable.
|
|
34
|
+
*/
|
|
35
|
+
epochRate: number;
|
|
36
|
+
}
|
|
37
|
+
/** One pool's contribution to the current cycle's accrual. */
|
|
38
|
+
export interface PoolAccrual {
|
|
39
|
+
/** That pool's projected net interest for one epoch (`weeklyInterest`). */
|
|
40
|
+
weeklyInterest: number;
|
|
41
|
+
/** Unix SECONDS at which THAT pool last cleared a cycle. */
|
|
42
|
+
clearingTimestamp: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Interest the slices accrue over ONE epoch, net of the fee.
|
|
46
|
+
*
|
|
47
|
+
* ```
|
|
48
|
+
* weekly = Σ(slice.balance × slice.epochRate) × (1 − feePercent / 100)
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* **The rate is the raw per-epoch one, never the APY.** An APY is that rate
|
|
52
|
+
* already compounded over `EPOCHS_IN_YEAR`; dividing it by 365 charges a day
|
|
53
|
+
* of compounded annual growth to a single day and overstates it.
|
|
54
|
+
*
|
|
55
|
+
* FAILS CLOSED, returning `null` rather than a wrong number:
|
|
56
|
+
* - a `null`, non-finite or out-of-domain fee — a fee-less projection dressed
|
|
57
|
+
* up as the lender's net earnings is the failure this guards;
|
|
58
|
+
* - any slice with a POSITIVE balance and a non-finite rate — skipping it
|
|
59
|
+
* would return a silently partial total, quietly missing that slice.
|
|
60
|
+
*
|
|
61
|
+
* Non-finite and non-positive BALANCES are skipped: a slice with nothing in it
|
|
62
|
+
* earns nothing whatever its rate, so it cannot hide earnings. A portfolio
|
|
63
|
+
* with nothing lent is therefore a legitimate `0`, never `null`.
|
|
64
|
+
*/
|
|
65
|
+
export declare function weeklyInterest(slices: readonly InterestSlice[], feePercent: number | null): number | null;
|
|
66
|
+
/**
|
|
67
|
+
* A day's share of the epoch's net interest: a seventh of it, NOT a
|
|
68
|
+
* de-compounded daily rate. The chain mints interest once per epoch, so
|
|
69
|
+
* nothing compounds within the cycle and the accrual is linear across it.
|
|
70
|
+
*
|
|
71
|
+
* Fails closed with its input: `null` or non-finite → `null`.
|
|
72
|
+
*/
|
|
73
|
+
export declare function dailyInterest(weekly: number | null): number | null;
|
|
74
|
+
/**
|
|
75
|
+
* Interest accrued since each pool's OWN last cycle close — the moving part
|
|
76
|
+
* of lifetime interest (lifetime = settled on chain + this).
|
|
77
|
+
*
|
|
78
|
+
* ```
|
|
79
|
+
* accrued = Σ_pool weekly_pool × clamp(now − clearing_pool, 0, 604 800) / 604 800
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* **Per pool, because pools clear independently.** One shared anchor accrues
|
|
83
|
+
* a stale pool's share from a close it never had, and when another pool
|
|
84
|
+
* clears it drops the total by the stale pool's whole weekly share. Anchored
|
|
85
|
+
* per pool, the total is monotonic across any single pool's clearing: that
|
|
86
|
+
* pool swaps its accrued share for a capitalised one, and no other term moves.
|
|
87
|
+
*
|
|
88
|
+
* **The one-epoch cap is load-bearing.** Clearings are not exactly weekly,
|
|
89
|
+
* and `weeklyInterest` is per EPOCH, so extrapolating past seven days would
|
|
90
|
+
* promise interest the close will not credit; a late clearing under-reports
|
|
91
|
+
* instead. The low clamp makes a close ahead of the local clock zero, never
|
|
92
|
+
* negative.
|
|
93
|
+
*
|
|
94
|
+
* A non-finite term contributes nothing; a non-finite `nowSeconds` accrues
|
|
95
|
+
* nothing. Callers fail closed upstream by not offering an accrual for a pool
|
|
96
|
+
* whose weekly interest or anchor is unknown.
|
|
97
|
+
*/
|
|
98
|
+
export declare function accruedInterest(accruals: readonly PoolAccrual[], nowSeconds: number): number;
|
|
99
|
+
/**
|
|
100
|
+
* What `amount` earns in a year at a NET rate — the "≈ $Y a year" line.
|
|
101
|
+
* Feed it `netEffectiveApy(...)`, never a gross APY: the result is a lender's
|
|
102
|
+
* earnings, so the fee must already be off the rate.
|
|
103
|
+
*
|
|
104
|
+
* FAILS CLOSED: a non-finite or negative amount or rate returns `NaN`, which
|
|
105
|
+
* the consumer renders as "no figure" — exactly what `netEffectiveApy`
|
|
106
|
+
* returns when the fee is unknown, so that state carries straight through.
|
|
107
|
+
*
|
|
108
|
+
* @param amount display units of the stable asset.
|
|
109
|
+
* @param netApy the net effective annual rate as a 0..1 fraction.
|
|
110
|
+
*/
|
|
111
|
+
export declare function projectedAnnualEarnings(amount: number, netApy: number): number;
|
|
112
|
+
/**
|
|
113
|
+
* Balance-weighted average APY across slices, skipping non-finite and
|
|
114
|
+
* non-positive balances and non-finite rates; `0` when nothing carries a
|
|
115
|
+
* positive balance. Whatever basis goes in comes out — feed it NET rates for
|
|
116
|
+
* an average effective (net) rate.
|
|
117
|
+
*/
|
|
118
|
+
export declare function weightedAverageApy(slices: readonly {
|
|
119
|
+
balance: number;
|
|
120
|
+
apy: number;
|
|
121
|
+
}[]): number;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forward-looking interest on a lender's CURRENT balances — the figures a
|
|
3
|
+
* portfolio shows as "weekly", "daily" and the moving part of "lifetime"
|
|
4
|
+
* interest, and the "≈ $Y a year" line beside a lend amount.
|
|
5
|
+
*
|
|
6
|
+
* Every figure is NET of the platform performance fee, the way the chain
|
|
7
|
+
* credits it: `LendingPool._applyTrancheInterest` mints the lender
|
|
8
|
+
* `interest × (1 − performanceFee)` at each cycle close, and only that net
|
|
9
|
+
* amount ever reaches the balance. A gross projection would out-run what the
|
|
10
|
+
* next close actually credits.
|
|
11
|
+
*
|
|
12
|
+
* Units: balances and results are display units of the deployment's stable
|
|
13
|
+
* asset (not base units); rates are 0..1 fractions; `feePercent` is a
|
|
14
|
+
* PERCENTAGE IN 0..100 — see `netEffectiveApy`.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Seconds in one epoch's nominal week. The per-epoch rate covers exactly this
|
|
18
|
+
* window, and the accrual spreads an epoch's interest across it.
|
|
19
|
+
*/
|
|
20
|
+
export const SECONDS_PER_WEEK = 604800;
|
|
21
|
+
function isUsableFeePercent(feePercent) {
|
|
22
|
+
return (feePercent !== null &&
|
|
23
|
+
Number.isFinite(feePercent) &&
|
|
24
|
+
feePercent >= 0 &&
|
|
25
|
+
feePercent <= 100);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Interest the slices accrue over ONE epoch, net of the fee.
|
|
29
|
+
*
|
|
30
|
+
* ```
|
|
31
|
+
* weekly = Σ(slice.balance × slice.epochRate) × (1 − feePercent / 100)
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* **The rate is the raw per-epoch one, never the APY.** An APY is that rate
|
|
35
|
+
* already compounded over `EPOCHS_IN_YEAR`; dividing it by 365 charges a day
|
|
36
|
+
* of compounded annual growth to a single day and overstates it.
|
|
37
|
+
*
|
|
38
|
+
* FAILS CLOSED, returning `null` rather than a wrong number:
|
|
39
|
+
* - a `null`, non-finite or out-of-domain fee — a fee-less projection dressed
|
|
40
|
+
* up as the lender's net earnings is the failure this guards;
|
|
41
|
+
* - any slice with a POSITIVE balance and a non-finite rate — skipping it
|
|
42
|
+
* would return a silently partial total, quietly missing that slice.
|
|
43
|
+
*
|
|
44
|
+
* Non-finite and non-positive BALANCES are skipped: a slice with nothing in it
|
|
45
|
+
* earns nothing whatever its rate, so it cannot hide earnings. A portfolio
|
|
46
|
+
* with nothing lent is therefore a legitimate `0`, never `null`.
|
|
47
|
+
*/
|
|
48
|
+
export function weeklyInterest(slices, feePercent) {
|
|
49
|
+
if (!isUsableFeePercent(feePercent))
|
|
50
|
+
return null;
|
|
51
|
+
let gross = 0;
|
|
52
|
+
for (const slice of slices) {
|
|
53
|
+
if (!Number.isFinite(slice.balance) || slice.balance <= 0)
|
|
54
|
+
continue;
|
|
55
|
+
if (!Number.isFinite(slice.epochRate))
|
|
56
|
+
return null;
|
|
57
|
+
gross += slice.balance * slice.epochRate;
|
|
58
|
+
}
|
|
59
|
+
return gross * (1 - feePercent / 100);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A day's share of the epoch's net interest: a seventh of it, NOT a
|
|
63
|
+
* de-compounded daily rate. The chain mints interest once per epoch, so
|
|
64
|
+
* nothing compounds within the cycle and the accrual is linear across it.
|
|
65
|
+
*
|
|
66
|
+
* Fails closed with its input: `null` or non-finite → `null`.
|
|
67
|
+
*/
|
|
68
|
+
export function dailyInterest(weekly) {
|
|
69
|
+
if (weekly === null || !Number.isFinite(weekly))
|
|
70
|
+
return null;
|
|
71
|
+
return weekly / 7;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Interest accrued since each pool's OWN last cycle close — the moving part
|
|
75
|
+
* of lifetime interest (lifetime = settled on chain + this).
|
|
76
|
+
*
|
|
77
|
+
* ```
|
|
78
|
+
* accrued = Σ_pool weekly_pool × clamp(now − clearing_pool, 0, 604 800) / 604 800
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* **Per pool, because pools clear independently.** One shared anchor accrues
|
|
82
|
+
* a stale pool's share from a close it never had, and when another pool
|
|
83
|
+
* clears it drops the total by the stale pool's whole weekly share. Anchored
|
|
84
|
+
* per pool, the total is monotonic across any single pool's clearing: that
|
|
85
|
+
* pool swaps its accrued share for a capitalised one, and no other term moves.
|
|
86
|
+
*
|
|
87
|
+
* **The one-epoch cap is load-bearing.** Clearings are not exactly weekly,
|
|
88
|
+
* and `weeklyInterest` is per EPOCH, so extrapolating past seven days would
|
|
89
|
+
* promise interest the close will not credit; a late clearing under-reports
|
|
90
|
+
* instead. The low clamp makes a close ahead of the local clock zero, never
|
|
91
|
+
* negative.
|
|
92
|
+
*
|
|
93
|
+
* A non-finite term contributes nothing; a non-finite `nowSeconds` accrues
|
|
94
|
+
* nothing. Callers fail closed upstream by not offering an accrual for a pool
|
|
95
|
+
* whose weekly interest or anchor is unknown.
|
|
96
|
+
*/
|
|
97
|
+
export function accruedInterest(accruals, nowSeconds) {
|
|
98
|
+
if (!Number.isFinite(nowSeconds))
|
|
99
|
+
return 0;
|
|
100
|
+
let accrued = 0;
|
|
101
|
+
for (const { weeklyInterest: weekly, clearingTimestamp } of accruals) {
|
|
102
|
+
if (!Number.isFinite(weekly) || !Number.isFinite(clearingTimestamp)) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const elapsed = Math.min(Math.max(nowSeconds - clearingTimestamp, 0), SECONDS_PER_WEEK);
|
|
106
|
+
accrued += (weekly * elapsed) / SECONDS_PER_WEEK;
|
|
107
|
+
}
|
|
108
|
+
return accrued;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* What `amount` earns in a year at a NET rate — the "≈ $Y a year" line.
|
|
112
|
+
* Feed it `netEffectiveApy(...)`, never a gross APY: the result is a lender's
|
|
113
|
+
* earnings, so the fee must already be off the rate.
|
|
114
|
+
*
|
|
115
|
+
* FAILS CLOSED: a non-finite or negative amount or rate returns `NaN`, which
|
|
116
|
+
* the consumer renders as "no figure" — exactly what `netEffectiveApy`
|
|
117
|
+
* returns when the fee is unknown, so that state carries straight through.
|
|
118
|
+
*
|
|
119
|
+
* @param amount display units of the stable asset.
|
|
120
|
+
* @param netApy the net effective annual rate as a 0..1 fraction.
|
|
121
|
+
*/
|
|
122
|
+
export function projectedAnnualEarnings(amount, netApy) {
|
|
123
|
+
if (!Number.isFinite(amount) || amount < 0)
|
|
124
|
+
return NaN;
|
|
125
|
+
if (!Number.isFinite(netApy) || netApy < 0)
|
|
126
|
+
return NaN;
|
|
127
|
+
return amount * netApy;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Balance-weighted average APY across slices, skipping non-finite and
|
|
131
|
+
* non-positive balances and non-finite rates; `0` when nothing carries a
|
|
132
|
+
* positive balance. Whatever basis goes in comes out — feed it NET rates for
|
|
133
|
+
* an average effective (net) rate.
|
|
134
|
+
*/
|
|
135
|
+
export function weightedAverageApy(slices) {
|
|
136
|
+
let totalBalance = 0;
|
|
137
|
+
let weighted = 0;
|
|
138
|
+
for (const slice of slices) {
|
|
139
|
+
if (!Number.isFinite(slice.balance) || !Number.isFinite(slice.apy)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (slice.balance <= 0)
|
|
143
|
+
continue;
|
|
144
|
+
totalBalance += slice.balance;
|
|
145
|
+
weighted += slice.balance * slice.apy;
|
|
146
|
+
}
|
|
147
|
+
if (totalBalance <= 0)
|
|
148
|
+
return 0;
|
|
149
|
+
return weighted / totalBalance;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=yields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yields.js","sourceRoot":"","sources":["../../src/domain/yields.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { BigNumber, BigNumberish } from 'ethers';
|
|
2
|
+
import { SponsoredCall } from '../domain/sponsored-calls';
|
|
3
|
+
import { UserLending } from '../services/UserLending/user-lending';
|
|
4
|
+
/** What `kasu.calls.requestWithdrawal` takes — `WithdrawFlowInput`'s shape. */
|
|
5
|
+
export interface RequestWithdrawalCallParams {
|
|
6
|
+
poolId: string;
|
|
7
|
+
trancheId: string;
|
|
8
|
+
/**
|
|
9
|
+
* Base units of the stable asset, or `'max'` for every share the lender
|
|
10
|
+
* holds in the tranche. Same code as `WithdrawFlowInput.amount`.
|
|
11
|
+
*/
|
|
12
|
+
amount: BigNumber | 'max';
|
|
13
|
+
/** The lender — whose shares `'max'` reads. The relay sends as them. */
|
|
14
|
+
userAddress: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Encoded, ready-to-sponsor `LendingPoolManager` calls — read, then encode,
|
|
18
|
+
* NEVER send. Each returns `{ kind, call }`: post `kind` and `[call]` to a
|
|
19
|
+
* sponsored relay (or `submitSponsoredCall`), unchanged.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* const { kind, call } = kasu.calls.cancelDepositRequest(poolId, dNftId);
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* `call.to` is always THIS chain's `LendingPoolManager`, from the chain
|
|
26
|
+
* config — the same address the deposit flow approves and calls — so no app
|
|
27
|
+
* supplies the one argument whose wrong value the relay refuses outright.
|
|
28
|
+
*
|
|
29
|
+
* Works on a read-only instance: the only chain access is the share read a
|
|
30
|
+
* withdrawal needs, and nothing is signed or sent here.
|
|
31
|
+
*/
|
|
32
|
+
export declare class CallsFacade {
|
|
33
|
+
private readonly _userLending;
|
|
34
|
+
private readonly _lendingPoolManager;
|
|
35
|
+
constructor(_userLending: UserLending, _lendingPoolManager: string);
|
|
36
|
+
/**
|
|
37
|
+
* `requestWithdrawal(pool, tranche, shares)` for an asset amount or
|
|
38
|
+
* `'max'`, converted into shares exactly as the direct path does it
|
|
39
|
+
* (`UserLending.requestWithdrawalInAsset` / `requestWithdrawalMax`): the
|
|
40
|
+
* tranche's `convertToShares(amount)`, or the lender's whole
|
|
41
|
+
* `balanceOf(userAddress)`, read now.
|
|
42
|
+
*
|
|
43
|
+
* Rejects with `SponsoredCallInputError` — before anything is sent — for
|
|
44
|
+
* a non-positive amount, a malformed address, or a conversion that comes
|
|
45
|
+
* to ZERO shares (an empty position, or dust below one share), which the
|
|
46
|
+
* contract would revert and the relay refuses.
|
|
47
|
+
*/
|
|
48
|
+
requestWithdrawal(params: RequestWithdrawalCallParams): Promise<SponsoredCall>;
|
|
49
|
+
/** `cancelDepositRequest(pool, dNftId)` — the pending deposit's NFT id. */
|
|
50
|
+
cancelDepositRequest(poolId: string, dNftId: BigNumberish): SponsoredCall;
|
|
51
|
+
/** `cancelWithdrawalRequest(pool, wNftId)` — the pending withdrawal's NFT id. */
|
|
52
|
+
cancelWithdrawalRequest(poolId: string, wNftId: BigNumberish): SponsoredCall;
|
|
53
|
+
/**
|
|
54
|
+
* `requestFixedTermDepositWithdrawal(pool, fixedTermDepositId)` — what
|
|
55
|
+
* `UserLending.withdrawAtExpiry(pool, lockId)` sends: the pool and the
|
|
56
|
+
* LOCK id, no tranche.
|
|
57
|
+
*/
|
|
58
|
+
withdrawAtExpiry(poolId: string, fixedTermDepositId: BigNumberish): SponsoredCall;
|
|
59
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { BigNumber } from 'ethers';
|
|
11
|
+
import { encodeCancelDepositCall, encodeCancelWithdrawalCall, encodeRequestWithdrawalCall, encodeWithdrawAtExpiryCall, SponsoredCallInputError, } from '../domain/sponsored-calls';
|
|
12
|
+
const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
13
|
+
/**
|
|
14
|
+
* Encoded, ready-to-sponsor `LendingPoolManager` calls — read, then encode,
|
|
15
|
+
* NEVER send. Each returns `{ kind, call }`: post `kind` and `[call]` to a
|
|
16
|
+
* sponsored relay (or `submitSponsoredCall`), unchanged.
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const { kind, call } = kasu.calls.cancelDepositRequest(poolId, dNftId);
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* `call.to` is always THIS chain's `LendingPoolManager`, from the chain
|
|
23
|
+
* config — the same address the deposit flow approves and calls — so no app
|
|
24
|
+
* supplies the one argument whose wrong value the relay refuses outright.
|
|
25
|
+
*
|
|
26
|
+
* Works on a read-only instance: the only chain access is the share read a
|
|
27
|
+
* withdrawal needs, and nothing is signed or sent here.
|
|
28
|
+
*/
|
|
29
|
+
export class CallsFacade {
|
|
30
|
+
constructor(_userLending, _lendingPoolManager) {
|
|
31
|
+
this._userLending = _userLending;
|
|
32
|
+
this._lendingPoolManager = _lendingPoolManager;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* `requestWithdrawal(pool, tranche, shares)` for an asset amount or
|
|
36
|
+
* `'max'`, converted into shares exactly as the direct path does it
|
|
37
|
+
* (`UserLending.requestWithdrawalInAsset` / `requestWithdrawalMax`): the
|
|
38
|
+
* tranche's `convertToShares(amount)`, or the lender's whole
|
|
39
|
+
* `balanceOf(userAddress)`, read now.
|
|
40
|
+
*
|
|
41
|
+
* Rejects with `SponsoredCallInputError` — before anything is sent — for
|
|
42
|
+
* a non-positive amount, a malformed address, or a conversion that comes
|
|
43
|
+
* to ZERO shares (an empty position, or dust below one share), which the
|
|
44
|
+
* contract would revert and the relay refuses.
|
|
45
|
+
*/
|
|
46
|
+
requestWithdrawal(params) {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
const { poolId, trancheId, amount, userAddress } = params;
|
|
49
|
+
if (typeof userAddress !== 'string' || !ADDRESS_RE.test(userAddress)) {
|
|
50
|
+
throw new SponsoredCallInputError('user');
|
|
51
|
+
}
|
|
52
|
+
if (typeof poolId !== 'string' || !ADDRESS_RE.test(poolId)) {
|
|
53
|
+
throw new SponsoredCallInputError('pool');
|
|
54
|
+
}
|
|
55
|
+
if (typeof trancheId !== 'string' || !ADDRESS_RE.test(trancheId)) {
|
|
56
|
+
throw new SponsoredCallInputError('tranche');
|
|
57
|
+
}
|
|
58
|
+
let shares;
|
|
59
|
+
if (amount === 'max') {
|
|
60
|
+
// Lowercased, as `WithdrawFlow` hands `withdrawMax` the address.
|
|
61
|
+
shares = yield this._userLending.getWithdrawalSharesMax(trancheId, userAddress.toLowerCase());
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
if (!BigNumber.isBigNumber(amount) || amount.lte(0)) {
|
|
65
|
+
throw new SponsoredCallInputError('non-positive-amount');
|
|
66
|
+
}
|
|
67
|
+
shares = yield this._userLending.getWithdrawalSharesForAssets(trancheId, amount);
|
|
68
|
+
}
|
|
69
|
+
return encodeRequestWithdrawalCall(this._lendingPoolManager, poolId, trancheId, shares);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/** `cancelDepositRequest(pool, dNftId)` — the pending deposit's NFT id. */
|
|
73
|
+
cancelDepositRequest(poolId, dNftId) {
|
|
74
|
+
return encodeCancelDepositCall(this._lendingPoolManager, poolId, dNftId);
|
|
75
|
+
}
|
|
76
|
+
/** `cancelWithdrawalRequest(pool, wNftId)` — the pending withdrawal's NFT id. */
|
|
77
|
+
cancelWithdrawalRequest(poolId, wNftId) {
|
|
78
|
+
return encodeCancelWithdrawalCall(this._lendingPoolManager, poolId, wNftId);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* `requestFixedTermDepositWithdrawal(pool, fixedTermDepositId)` — what
|
|
82
|
+
* `UserLending.withdrawAtExpiry(pool, lockId)` sends: the pool and the
|
|
83
|
+
* LOCK id, no tranche.
|
|
84
|
+
*/
|
|
85
|
+
withdrawAtExpiry(poolId, fixedTermDepositId) {
|
|
86
|
+
return encodeWithdrawAtExpiryCall(this._lendingPoolManager, poolId, fixedTermDepositId);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=calls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"calls.js","sourceRoot":"","sources":["../../src/facade/calls.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAgB,MAAM,QAAQ,CAAC;AAEjD,OAAO,EACH,uBAAuB,EACvB,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAE1B,uBAAuB,GAC1B,MAAM,2BAA2B,CAAC;AAGnC,MAAM,UAAU,GAAG,qBAAqB,CAAC;AAezC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,WAAW;IACpB,YACqB,YAAyB,EACzB,mBAA2B;QAD3B,iBAAY,GAAZ,YAAY,CAAa;QACzB,wBAAmB,GAAnB,mBAAmB,CAAQ;IAC7C,CAAC;IAEJ;;;;;;;;;;;OAWG;IACG,iBAAiB,CACnB,MAAmC;;YAEnC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;YAC1D,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;gBACnE,MAAM,IAAI,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAC9C,CAAC;YACD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzD,MAAM,IAAI,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAC9C,CAAC;YACD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/D,MAAM,IAAI,uBAAuB,CAAC,SAAS,CAAC,CAAC;YACjD,CAAC;YACD,IAAI,MAAiB,CAAC;YACtB,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACnB,iEAAiE;gBACjE,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,sBAAsB,CACnD,SAAS,EACT,WAAW,CAAC,WAAW,EAAE,CAC5B,CAAC;YACN,CAAC;iBAAM,CAAC;gBACJ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBAClD,MAAM,IAAI,uBAAuB,CAAC,qBAAqB,CAAC,CAAC;gBAC7D,CAAC;gBACD,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,4BAA4B,CACzD,SAAS,EACT,MAAM,CACT,CAAC;YACN,CAAC;YACD,OAAO,2BAA2B,CAC9B,IAAI,CAAC,mBAAmB,EACxB,MAAM,EACN,SAAS,EACT,MAAM,CACT,CAAC;QACN,CAAC;KAAA;IAED,2EAA2E;IAC3E,oBAAoB,CAAC,MAAc,EAAE,MAAoB;QACrD,OAAO,uBAAuB,CAC1B,IAAI,CAAC,mBAAmB,EACxB,MAAM,EACN,MAAM,CACT,CAAC;IACN,CAAC;IAED,iFAAiF;IACjF,uBAAuB,CACnB,MAAc,EACd,MAAoB;QAEpB,OAAO,0BAA0B,CAC7B,IAAI,CAAC,mBAAmB,EACxB,MAAM,EACN,MAAM,CACT,CAAC;IACN,CAAC;IAED;;;;OAIG;IACH,gBAAgB,CACZ,MAAc,EACd,kBAAgC;QAEhC,OAAO,0BAA0B,CAC7B,IAAI,CAAC,mBAAmB,EACxB,MAAM,EACN,kBAAkB,CACrB,CAAC;IACN,CAAC;CACJ"}
|
|
@@ -55,6 +55,7 @@ export const CHAIN_CONFIGS = {
|
|
|
55
55
|
'https://base-rpc.publicnode.com',
|
|
56
56
|
'https://mainnet.base.org',
|
|
57
57
|
],
|
|
58
|
+
blockExplorerUrl: 'https://basescan.org',
|
|
58
59
|
},
|
|
59
60
|
xdc: {
|
|
60
61
|
chainId: 50,
|
|
@@ -90,6 +91,7 @@ export const CHAIN_CONFIGS = {
|
|
|
90
91
|
currencyCode: 'AUD',
|
|
91
92
|
},
|
|
92
93
|
rpcUrls: XDC_RPC_URLS,
|
|
94
|
+
blockExplorerUrl: 'https://xdcscan.com',
|
|
93
95
|
},
|
|
94
96
|
'xdc-usdc': {
|
|
95
97
|
chainId: 50,
|
|
@@ -121,6 +123,7 @@ export const CHAIN_CONFIGS = {
|
|
|
121
123
|
currencyCode: 'USD',
|
|
122
124
|
},
|
|
123
125
|
rpcUrls: XDC_RPC_URLS,
|
|
126
|
+
blockExplorerUrl: 'https://xdcscan.com',
|
|
124
127
|
},
|
|
125
128
|
plume: {
|
|
126
129
|
chainId: 98866,
|
|
@@ -161,6 +164,8 @@ export const CHAIN_CONFIGS = {
|
|
|
161
164
|
// pointing at an endpoint nobody maintains. Pass your own
|
|
162
165
|
// `signerOrProvider` to read the frozen history.
|
|
163
166
|
rpcUrls: [],
|
|
167
|
+
// The explorer still serves the frozen history.
|
|
168
|
+
blockExplorerUrl: 'https://explorer.plume.org',
|
|
164
169
|
retired: true,
|
|
165
170
|
},
|
|
166
171
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain-configs.js","sourceRoot":"","sources":["../../src/facade/chain-configs.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,YAAY,GAAa;IAC3B,0BAA0B;IAC1B,wBAAwB;IACxB,4BAA4B;IAC5B,+BAA+B;CAClC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,aAAa,GAAoE;IAC1F,IAAI,EAAE;QACF,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,cAAc;QACpB,gBAAgB,EAAE,KAAK;QACvB,SAAS,EAAE;YACP,QAAQ,EAAE,4CAA4C;YACtD,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,kBAAkB,EAAE,4CAA4C;YAChE,WAAW,EAAE,4CAA4C;YACzD,aAAa,EAAE,4CAA4C;YAC3D,eAAe,EAAE,4CAA4C;YAC7D,QAAQ,EAAE,4CAA4C;YACtD,kBAAkB,EAAE,4CAA4C;YAChE,mBAAmB,EAAE,4CAA4C;YACjE,QAAQ,EAAE,4CAA4C;YACtD,WAAW,EAAE,4CAA4C;SAC5D;QACD,WAAW,EACP,qGAAqG;QACzG,WAAW,EAAE,oCAAoC;QACjD,aAAa,EAAE,EAAE;QACjB,mBAAmB,EAAE,SAAS;QAC9B,WAAW,EAAE;YACT,OAAO,EAAE,4CAA4C;YACrD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,CAAC;YACX,YAAY,EAAE,KAAK;SACtB;QACD,OAAO,EAAE;YACL,iCAAiC;YACjC,0BAA0B;SAC7B;
|
|
1
|
+
{"version":3,"file":"chain-configs.js","sourceRoot":"","sources":["../../src/facade/chain-configs.ts"],"names":[],"mappings":"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"}
|