@gearbox-protocol/sdk 14.10.7 → 14.11.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/preview/index.js +26 -0
- package/dist/cjs/preview/package.json +1 -0
- package/dist/cjs/preview/parse/classifyInnerOperations.js +130 -0
- package/dist/cjs/preview/parse/errors.js +47 -0
- package/dist/cjs/preview/parse/index.js +32 -0
- package/dist/cjs/preview/parse/parseCreditFacadeOperation.js +111 -0
- package/dist/cjs/preview/parse/parsePoolOperation.js +62 -0
- package/dist/cjs/preview/parse/parseTransaction.js +46 -0
- package/dist/cjs/preview/parse/types.js +30 -0
- package/dist/cjs/preview/prerequisites/AllowancePrerequisite.js +78 -0
- package/dist/cjs/preview/prerequisites/BalancePrerequisite.js +77 -0
- package/dist/cjs/preview/prerequisites/Prerequisite.js +85 -0
- package/dist/cjs/preview/prerequisites/buildPrerequisites.js +141 -0
- package/dist/cjs/preview/prerequisites/index.js +32 -0
- package/dist/cjs/preview/prerequisites/runPrerequisites.js +71 -0
- package/dist/cjs/preview/prerequisites/types.js +16 -0
- package/dist/cjs/preview/simulate/decodeSimulationError.js +64 -0
- package/dist/cjs/preview/simulate/extractERC20Transfers.js +47 -0
- package/dist/cjs/preview/simulate/index.js +28 -0
- package/dist/cjs/preview/simulate/simulatePoolOperation.js +94 -0
- package/dist/cjs/preview/simulate/types.js +16 -0
- package/dist/esm/preview/index.js +3 -0
- package/dist/esm/preview/package.json +1 -0
- package/dist/esm/preview/parse/classifyInnerOperations.js +108 -0
- package/dist/esm/preview/parse/errors.js +22 -0
- package/dist/esm/preview/parse/index.js +6 -0
- package/dist/esm/preview/parse/parseCreditFacadeOperation.js +91 -0
- package/dist/esm/preview/parse/parsePoolOperation.js +38 -0
- package/dist/esm/preview/parse/parseTransaction.js +25 -0
- package/dist/esm/preview/parse/types.js +6 -0
- package/dist/esm/preview/prerequisites/AllowancePrerequisite.js +57 -0
- package/dist/esm/preview/prerequisites/BalancePrerequisite.js +56 -0
- package/dist/esm/preview/prerequisites/Prerequisite.js +63 -0
- package/dist/esm/preview/prerequisites/buildPrerequisites.js +117 -0
- package/dist/esm/preview/prerequisites/index.js +6 -0
- package/dist/esm/preview/prerequisites/runPrerequisites.js +47 -0
- package/dist/esm/preview/prerequisites/types.js +0 -0
- package/dist/esm/preview/simulate/decodeSimulationError.js +44 -0
- package/dist/esm/preview/simulate/extractERC20Transfers.js +23 -0
- package/dist/esm/preview/simulate/index.js +4 -0
- package/dist/esm/preview/simulate/simulatePoolOperation.js +70 -0
- package/dist/esm/preview/simulate/types.js +0 -0
- package/dist/types/preview/index.d.ts +3 -0
- package/dist/types/preview/parse/classifyInnerOperations.d.ts +21 -0
- package/dist/types/preview/parse/errors.d.ts +17 -0
- package/dist/types/preview/parse/index.d.ts +6 -0
- package/dist/types/preview/parse/parseCreditFacadeOperation.d.ts +18 -0
- package/dist/types/preview/parse/parsePoolOperation.d.ts +15 -0
- package/dist/types/preview/parse/parseTransaction.d.ts +23 -0
- package/dist/types/preview/parse/types.d.ts +78 -0
- package/dist/types/preview/prerequisites/AllowancePrerequisite.d.ts +24 -0
- package/dist/types/preview/prerequisites/BalancePrerequisite.d.ts +23 -0
- package/dist/types/preview/prerequisites/Prerequisite.d.ts +60 -0
- package/dist/types/preview/prerequisites/buildPrerequisites.d.ts +16 -0
- package/dist/types/preview/prerequisites/index.d.ts +6 -0
- package/dist/types/preview/prerequisites/runPrerequisites.d.ts +12 -0
- package/dist/types/preview/prerequisites/types.d.ts +78 -0
- package/dist/types/preview/simulate/decodeSimulationError.d.ts +18 -0
- package/dist/types/preview/simulate/extractERC20Transfers.d.ts +11 -0
- package/dist/types/preview/simulate/index.d.ts +4 -0
- package/dist/types/preview/simulate/simulatePoolOperation.d.ts +30 -0
- package/dist/types/preview/simulate/types.d.ts +43 -0
- package/package.json +6 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { isAddressEqual, parseEventLogs } from "viem";
|
|
2
|
+
import { ierc20Abi } from "../../abi/iERC20.js";
|
|
3
|
+
function extractERC20Transfers(logs, watch) {
|
|
4
|
+
const parsed = parseEventLogs({
|
|
5
|
+
abi: ierc20Abi,
|
|
6
|
+
eventName: "Transfer",
|
|
7
|
+
logs
|
|
8
|
+
});
|
|
9
|
+
const transfers = [];
|
|
10
|
+
for (const log of parsed) {
|
|
11
|
+
const { from, to, value } = log.args;
|
|
12
|
+
const involved = watch.some(
|
|
13
|
+
(address) => isAddressEqual(from, address) || isAddressEqual(to, address)
|
|
14
|
+
);
|
|
15
|
+
if (involved) {
|
|
16
|
+
transfers.push({ token: log.address, amount: value, from, to });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return transfers;
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
extractERC20Transfers
|
|
23
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { isAddressEqual } from "viem";
|
|
2
|
+
import { simulateCalls } from "viem/actions";
|
|
3
|
+
import { ierc20Abi } from "../../abi/iERC20.js";
|
|
4
|
+
import { decodeSimulationError } from "./decodeSimulationError.js";
|
|
5
|
+
import { extractERC20Transfers } from "./extractERC20Transfers.js";
|
|
6
|
+
async function simulatePoolOperation(input) {
|
|
7
|
+
const { sdk, operation, to, calldata, wallet, blockNumber } = input;
|
|
8
|
+
const { underlying, pool } = operation;
|
|
9
|
+
const receiverIsWallet = isAddressEqual(operation.receiver, wallet);
|
|
10
|
+
const holders = receiverIsWallet ? [wallet] : [wallet, operation.receiver];
|
|
11
|
+
const tokens = [underlying, pool];
|
|
12
|
+
const balanceOf = (token, holder) => ({
|
|
13
|
+
to: token,
|
|
14
|
+
abi: ierc20Abi,
|
|
15
|
+
functionName: "balanceOf",
|
|
16
|
+
args: [holder]
|
|
17
|
+
});
|
|
18
|
+
const balanceCalls = holders.flatMap(
|
|
19
|
+
(holder) => tokens.map((token) => balanceOf(token, holder))
|
|
20
|
+
);
|
|
21
|
+
const { results } = await simulateCalls(sdk.client, {
|
|
22
|
+
account: wallet,
|
|
23
|
+
// `undefined` lets viem simulate at `latest`; `blockNumber` is only set for
|
|
24
|
+
// testnet forks pinned to a specific block.
|
|
25
|
+
blockNumber,
|
|
26
|
+
calls: [...balanceCalls, { to, data: calldata }, ...balanceCalls]
|
|
27
|
+
});
|
|
28
|
+
const sim = results;
|
|
29
|
+
const txIndex = balanceCalls.length;
|
|
30
|
+
const afterOffset = txIndex + 1;
|
|
31
|
+
const txResult = sim[txIndex];
|
|
32
|
+
if (!txResult || txResult.status === "failure") {
|
|
33
|
+
return {
|
|
34
|
+
status: "failure",
|
|
35
|
+
error: decodeSimulationError({
|
|
36
|
+
error: txResult?.error,
|
|
37
|
+
data: txResult?.data
|
|
38
|
+
})
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const balanceChanges = [];
|
|
42
|
+
for (const [holderIndex, address] of holders.entries()) {
|
|
43
|
+
const changes = [];
|
|
44
|
+
for (const [tokenIndex, token] of tokens.entries()) {
|
|
45
|
+
const slot = holderIndex * tokens.length + tokenIndex;
|
|
46
|
+
const before = readBalance(sim[slot]);
|
|
47
|
+
const after = readBalance(sim[afterOffset + slot]);
|
|
48
|
+
const delta = after - before;
|
|
49
|
+
const magnitude = delta >= 0n ? delta : -delta;
|
|
50
|
+
if (magnitude > 1n) {
|
|
51
|
+
changes.push({ token, before, after, delta });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (changes.length > 0) {
|
|
55
|
+
balanceChanges.push({ address, changes });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
status: "success",
|
|
60
|
+
transfers: extractERC20Transfers(txResult.logs ?? [], holders),
|
|
61
|
+
balanceChanges,
|
|
62
|
+
gasUsed: txResult.gasUsed
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function readBalance(result) {
|
|
66
|
+
return result?.status === "success" ? result.result : 0n;
|
|
67
|
+
}
|
|
68
|
+
export {
|
|
69
|
+
simulatePoolOperation
|
|
70
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Address } from "viem";
|
|
2
|
+
import type { InnerOperation } from "../../history/index.js";
|
|
3
|
+
import type { OnchainSDK, ParsedCallV2 } from "../../sdk/index.js";
|
|
4
|
+
export interface ClassifyInnerOperationsProps {
|
|
5
|
+
sdk: OnchainSDK;
|
|
6
|
+
/** Underlying token of the credit manager, used for debt operations. */
|
|
7
|
+
underlying: Address;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Calldata-only counterpart of the SDK's `classifyMulticallOperations`.
|
|
11
|
+
*
|
|
12
|
+
* Maps each inner multicall entry to an {@link InnerOperation}:
|
|
13
|
+
* - adapter targets become an `Execute` {@link AdapterOperation};
|
|
14
|
+
* - credit-facade self-calls map to the matching inner facade operation;
|
|
15
|
+
* - unknown targets fall back to a generic `Execute`.
|
|
16
|
+
*
|
|
17
|
+
* Since raw calldata has no execution trace, `transfers` is always empty and
|
|
18
|
+
* `legacy` is a zeroed placeholder; protocol-level fields mirror the adapter
|
|
19
|
+
* call.
|
|
20
|
+
*/
|
|
21
|
+
export declare function classifyInnerOperations(calls: ParsedCallV2[], props: ClassifyInnerOperationsProps): InnerOperation[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown when the target of a transaction is neither a known Gearbox pool nor a
|
|
4
|
+
* credit facade.
|
|
5
|
+
*/
|
|
6
|
+
export declare class UnsupportedTargetError extends Error {
|
|
7
|
+
readonly target: Address;
|
|
8
|
+
constructor(target: Address);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Thrown when a pool call uses a function other than ERC4626 `deposit`/`redeem`.
|
|
12
|
+
*/
|
|
13
|
+
export declare class UnsupportedPoolFunctionError extends Error {
|
|
14
|
+
readonly pool: Address;
|
|
15
|
+
readonly functionName: string;
|
|
16
|
+
constructor(pool: Address, functionName: string);
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Hex } from "viem";
|
|
2
|
+
import type { OuterFacadeOperation } from "../../history/index.js";
|
|
3
|
+
import type { CreditFacadeV310Contract, OnchainSDK } from "../../sdk/index.js";
|
|
4
|
+
export interface ParseCreditFacadeOperationProps {
|
|
5
|
+
sdk: OnchainSDK;
|
|
6
|
+
/** Resolved credit facade contract for the transaction target. */
|
|
7
|
+
facade: CreditFacadeV310Contract;
|
|
8
|
+
calldata: Hex;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Decodes a credit-facade entry-point call into the matching
|
|
12
|
+
* {@link OuterFacadeOperation}.
|
|
13
|
+
*
|
|
14
|
+
* Metadata is partial: `txHash` is `zeroHash` and `timestamp` is `0` because
|
|
15
|
+
* those are only known once the transaction is mined. `creditAccount` is
|
|
16
|
+
* `zeroAddress` for `openCreditAccount` (the address is assigned on-chain).
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseCreditFacadeOperation(props: ParseCreditFacadeOperationProps): OuterFacadeOperation;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Hex } from "viem";
|
|
2
|
+
import type { OnchainSDK, PoolV310Contract } from "../../sdk/index.js";
|
|
3
|
+
import type { PoolOperation } from "./types.js";
|
|
4
|
+
export interface ParsePoolOperationProps {
|
|
5
|
+
sdk: OnchainSDK;
|
|
6
|
+
/** Resolved pool contract for the transaction target. */
|
|
7
|
+
pool: PoolV310Contract;
|
|
8
|
+
calldata: Hex;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Decodes ERC4626 `deposit`/`depositWithReferral`/`redeem` calldata on a
|
|
12
|
+
* Gearbox pool into a {@link PoolOperation}. Any other selector throws
|
|
13
|
+
* {@link UnsupportedPoolFunctionError}.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parsePoolOperation(props: ParsePoolOperationProps): PoolOperation;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Address, Hex } from "viem";
|
|
2
|
+
import { type PluginsMap } from "../../sdk/index.js";
|
|
3
|
+
import type { ParsedTransaction, SdkWithAdapters } from "./types.js";
|
|
4
|
+
export interface ParseTransactionInput<P extends PluginsMap = PluginsMap> {
|
|
5
|
+
/**
|
|
6
|
+
* Already-attached SDK; chain, RPC and block are baked in at attach time.
|
|
7
|
+
* Must be created with the adapters plugin (enforced at compile time) so
|
|
8
|
+
* adapter contracts resolve during multicall classification.
|
|
9
|
+
*/
|
|
10
|
+
sdk: SdkWithAdapters<P>;
|
|
11
|
+
to: Address;
|
|
12
|
+
calldata: Hex;
|
|
13
|
+
/** Transaction sender, contextual only. */
|
|
14
|
+
sender: Address;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Decodes raw transaction calldata into a {@link ParsedTransaction}.
|
|
18
|
+
*
|
|
19
|
+
* Routes by the resolved contract at `to`: a pool yields a deposit/redeem
|
|
20
|
+
* operation, a credit facade yields one facade operation. Anything else throws
|
|
21
|
+
* {@link UnsupportedTargetError}.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseTransaction<P extends PluginsMap>(input: ParseTransactionInput<P>): ParsedTransaction;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import type { OuterFacadeOperation } from "../../history/index.js";
|
|
3
|
+
import type { AdaptersPlugin, TokenTransfer } from "../../plugins/adapters/index.js";
|
|
4
|
+
import type { OnchainSDK, PluginsMap } from "../../sdk/index.js";
|
|
5
|
+
/**
|
|
6
|
+
* True when the plugin map `P` contains the {@link AdaptersPlugin} under any
|
|
7
|
+
* key. Matched nominally (the plugin's private fields make it non-structural),
|
|
8
|
+
* so unrelated plugins never satisfy it.
|
|
9
|
+
*/
|
|
10
|
+
export type HasAdaptersPlugin<P extends PluginsMap> = Extract<P[keyof P], AdaptersPlugin> extends never ? false : true;
|
|
11
|
+
/**
|
|
12
|
+
* Compile-time guard for the adapters plugin. Resolves to a no-op (`unknown`)
|
|
13
|
+
* when `P` includes the {@link AdaptersPlugin}, otherwise to an error-shaped
|
|
14
|
+
* type that makes the surrounding call fail to type-check.
|
|
15
|
+
*
|
|
16
|
+
* Intended to be intersected with a function argument so callers must pass an
|
|
17
|
+
* SDK whose adapter contracts are registered (required for multicall
|
|
18
|
+
* classification).
|
|
19
|
+
*/
|
|
20
|
+
export type RequireAdaptersPlugin<P extends PluginsMap> = HasAdaptersPlugin<P> extends true ? unknown : {
|
|
21
|
+
"OnchainSDK must be created with the AdaptersPlugin": never;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* {@link OnchainSDK} whose plugin map is guaranteed at compile time to include
|
|
25
|
+
* the {@link AdaptersPlugin}.
|
|
26
|
+
*/
|
|
27
|
+
export type SdkWithAdapters<P extends PluginsMap = PluginsMap> = OnchainSDK<P> & RequireAdaptersPlugin<P>;
|
|
28
|
+
/**
|
|
29
|
+
* ERC4626 `deposit` into a Gearbox pool.
|
|
30
|
+
* Token metadata (symbol/decimals) is intentionally omitted: consumers resolve
|
|
31
|
+
* it from `sdk.tokensMeta` using the token addresses below.
|
|
32
|
+
*/
|
|
33
|
+
export interface PoolDepositOperation {
|
|
34
|
+
operation: "Deposit";
|
|
35
|
+
pool: Address;
|
|
36
|
+
receiver: Address;
|
|
37
|
+
/** Underlying assets supplied to the pool. */
|
|
38
|
+
assets: bigint;
|
|
39
|
+
underlying: Address;
|
|
40
|
+
/** Referral code, present only for `depositWithReferral` calls. */
|
|
41
|
+
referralCode?: bigint;
|
|
42
|
+
/**
|
|
43
|
+
* ERC-20 transfers involving the wallet, recovered by simulating the call.
|
|
44
|
+
* Empty for the calldata-only parse; populated by the simulation stage.
|
|
45
|
+
*/
|
|
46
|
+
transfers: TokenTransfer[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* ERC4626 `redeem` from a Gearbox pool.
|
|
50
|
+
* Token metadata (symbol/decimals) is intentionally omitted: consumers resolve
|
|
51
|
+
* it from `sdk.tokensMeta` using the token addresses below.
|
|
52
|
+
*/
|
|
53
|
+
export interface PoolRedeemOperation {
|
|
54
|
+
operation: "Redeem";
|
|
55
|
+
pool: Address;
|
|
56
|
+
receiver: Address;
|
|
57
|
+
owner: Address;
|
|
58
|
+
/** Pool shares (diesel) burned. */
|
|
59
|
+
shares: bigint;
|
|
60
|
+
underlying: Address;
|
|
61
|
+
/**
|
|
62
|
+
* ERC-20 transfers involving the wallet, recovered by simulating the call.
|
|
63
|
+
* Empty for the calldata-only parse; populated by the simulation stage.
|
|
64
|
+
*/
|
|
65
|
+
transfers: TokenTransfer[];
|
|
66
|
+
}
|
|
67
|
+
export type PoolOperation = PoolDepositOperation | PoolRedeemOperation;
|
|
68
|
+
/**
|
|
69
|
+
* Narrows a {@link ParsedTransaction} to a {@link PoolOperation} (deposit or
|
|
70
|
+
* redeem). Used by the UI to decide whether a custom view exists for the parsed
|
|
71
|
+
* result; everything else falls back to the raw JSON view.
|
|
72
|
+
*/
|
|
73
|
+
export declare function isPoolOperation(tx: ParsedTransaction): tx is PoolOperation;
|
|
74
|
+
/**
|
|
75
|
+
* Result of decoding a single raw transaction calldata: either a pool
|
|
76
|
+
* deposit/redeem or one of the credit-facade operations from `sdk/history`.
|
|
77
|
+
*/
|
|
78
|
+
export type ParsedTransaction = PoolOperation | OuterFacadeOperation;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Address, type ContractFunctionParameters } from "viem";
|
|
2
|
+
import { type MulticallCallResult, Prerequisite } from "./Prerequisite.js";
|
|
3
|
+
import type { PrerequisiteDetail, PrerequisiteResult } from "./types.js";
|
|
4
|
+
export interface AllowancePrerequisiteProps {
|
|
5
|
+
token: Address;
|
|
6
|
+
owner: Address;
|
|
7
|
+
spender: Address;
|
|
8
|
+
required: bigint;
|
|
9
|
+
title?: string;
|
|
10
|
+
id?: string;
|
|
11
|
+
}
|
|
12
|
+
/** Checks that `owner` granted `spender` an ERC-20 allowance >= `required`. */
|
|
13
|
+
export declare class AllowancePrerequisite extends Prerequisite<"allowance"> {
|
|
14
|
+
private readonly _id;
|
|
15
|
+
private readonly _title;
|
|
16
|
+
private readonly _detail;
|
|
17
|
+
constructor(props: AllowancePrerequisiteProps);
|
|
18
|
+
get id(): string;
|
|
19
|
+
get kind(): "allowance";
|
|
20
|
+
get title(): string;
|
|
21
|
+
get detail(): PrerequisiteDetail<"allowance">;
|
|
22
|
+
calls(): ContractFunctionParameters[];
|
|
23
|
+
resolve(slice: MulticallCallResult[]): PrerequisiteResult<"allowance">;
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Address, type ContractFunctionParameters } from "viem";
|
|
2
|
+
import { type MulticallCallResult, Prerequisite } from "./Prerequisite.js";
|
|
3
|
+
import type { PrerequisiteDetail, PrerequisiteResult } from "./types.js";
|
|
4
|
+
export interface BalancePrerequisiteProps {
|
|
5
|
+
token: Address;
|
|
6
|
+
owner: Address;
|
|
7
|
+
required: bigint;
|
|
8
|
+
title?: string;
|
|
9
|
+
id?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Checks that `owner` holds an ERC-20 balance >= `required`. */
|
|
12
|
+
export declare class BalancePrerequisite extends Prerequisite<"balance"> {
|
|
13
|
+
private readonly _id;
|
|
14
|
+
private readonly _title;
|
|
15
|
+
private readonly _detail;
|
|
16
|
+
constructor(props: BalancePrerequisiteProps);
|
|
17
|
+
get id(): string;
|
|
18
|
+
get kind(): "balance";
|
|
19
|
+
get title(): string;
|
|
20
|
+
get detail(): PrerequisiteDetail<"balance">;
|
|
21
|
+
calls(): ContractFunctionParameters[];
|
|
22
|
+
resolve(slice: MulticallCallResult[]): PrerequisiteResult<"balance">;
|
|
23
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type ContractFunctionParameters } from "viem";
|
|
2
|
+
import type { PrerequisiteContext, PrerequisiteDetail, PrerequisiteError, PrerequisiteKind, PrerequisiteResult } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* One entry of a viem `multicall({ allowFailure: true })` response: either a
|
|
5
|
+
* decoded `result` or the `error` that the call reverted with.
|
|
6
|
+
*/
|
|
7
|
+
export type MulticallCallResult = {
|
|
8
|
+
status: "success";
|
|
9
|
+
result: unknown;
|
|
10
|
+
error?: undefined;
|
|
11
|
+
} | {
|
|
12
|
+
status: "failure";
|
|
13
|
+
result?: undefined;
|
|
14
|
+
error: Error;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Decodes an unknown error into a {@link PrerequisiteError} with a
|
|
18
|
+
* human-readable revert reason. Mirrors the SDK's `extractCallError`: walk the
|
|
19
|
+
* viem error chain for a {@link ContractFunctionRevertedError} and use its
|
|
20
|
+
* `errorName`, otherwise fall back to the error's short message / name.
|
|
21
|
+
*/
|
|
22
|
+
export declare function toPrerequisiteError(cause: unknown): PrerequisiteError;
|
|
23
|
+
/**
|
|
24
|
+
* A single verifiable prerequisite for a transaction. Subclasses describe the
|
|
25
|
+
* on-chain reads they need ({@link calls}) and how to turn the multicall slice
|
|
26
|
+
* into a {@link PrerequisiteResult} ({@link resolve}).
|
|
27
|
+
*
|
|
28
|
+
* Identity (`id`, `kind`, `title`) and build-time `detail` are exposed as
|
|
29
|
+
* read-only accessors; subclasses back them with private fields. The shared
|
|
30
|
+
* {@link satisfiedResult}/{@link errorResult} helpers are `protected` so each
|
|
31
|
+
* subclass builds results consistently.
|
|
32
|
+
*
|
|
33
|
+
* The same instance can be verified standalone via {@link verify} or batched
|
|
34
|
+
* together with others by `verifyPrerequisites`.
|
|
35
|
+
*/
|
|
36
|
+
export declare abstract class Prerequisite<K extends PrerequisiteKind> {
|
|
37
|
+
/** Stable identifier, used as a React key and for deduplication. */
|
|
38
|
+
abstract get id(): string;
|
|
39
|
+
/** Discriminant tying this check to its detail payload. */
|
|
40
|
+
abstract get kind(): K;
|
|
41
|
+
/** Human-readable label shown in the UI. */
|
|
42
|
+
abstract get title(): string;
|
|
43
|
+
/** Inputs known before reading the chain (no `actual` yet). */
|
|
44
|
+
abstract get detail(): PrerequisiteDetail<K>;
|
|
45
|
+
/** Contract reads this check needs (usually one). */
|
|
46
|
+
abstract calls(ctx: PrerequisiteContext): ContractFunctionParameters[];
|
|
47
|
+
/** Maps this check's slice of the multicall response into a result. */
|
|
48
|
+
abstract resolve(slice: MulticallCallResult[]): PrerequisiteResult<K>;
|
|
49
|
+
/**
|
|
50
|
+
* Verifies this prerequisite on its own using an `allowFailure` multicall.
|
|
51
|
+
* Prefer `verifyPrerequisites` to batch several checks into one round-trip.
|
|
52
|
+
*/
|
|
53
|
+
verify(ctx: PrerequisiteContext): Promise<PrerequisiteResult<K>>;
|
|
54
|
+
/** Builds a successful result; `detail` carries the on-chain `actual`. */
|
|
55
|
+
protected satisfiedResult(satisfied: boolean, detail: PrerequisiteDetail<K>): PrerequisiteResult<K>;
|
|
56
|
+
/** Builds a failed result from a decoded read error. */
|
|
57
|
+
protected errorResult(error: PrerequisiteError): PrerequisiteResult<K>;
|
|
58
|
+
}
|
|
59
|
+
/** Any prerequisite regardless of its kind, used for heterogeneous lists. */
|
|
60
|
+
export type AnyPrerequisite = Prerequisite<PrerequisiteKind>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ParsedTransaction } from "../parse/index.js";
|
|
2
|
+
import type { AnyPrerequisite } from "./Prerequisite.js";
|
|
3
|
+
import type { PrerequisiteContext } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Derives the on-chain prerequisites for a parsed transaction: the conditions
|
|
6
|
+
* that must hold for the call not to revert and that we can verify with the
|
|
7
|
+
* SDK (token approvals, wallet balances).
|
|
8
|
+
*
|
|
9
|
+
* Only *sender-actionable* prerequisites belong here: conditions the LP
|
|
10
|
+
* provider or borrower can fix themselves before retrying (e.g. approve a
|
|
11
|
+
* token, top up a balance). Non-actionable protocol/admin state (pool pause,
|
|
12
|
+
* available pool liquidity, health factor, liquidatability, degen NFT gating,
|
|
13
|
+
* bot permissions) is intentionally out of scope, since the user cannot
|
|
14
|
+
* resolve it. New {@link AnyPrerequisite} subclasses must follow the same rule.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildPrerequisites(tx: ParsedTransaction, ctx: PrerequisiteContext): AnyPrerequisite[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AnyPrerequisite } from "./Prerequisite.js";
|
|
2
|
+
import type { AnyPrerequisiteResult, PrerequisiteContext } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Verifies all prerequisites in a single resilient multicall.
|
|
5
|
+
*
|
|
6
|
+
* Every prereq contributes its reads to one `multicall({ allowFailure: true })`
|
|
7
|
+
* batch, then resolves its own slice of the response. A read that reverts
|
|
8
|
+
* isolates to that prerequisite (an `error` result) without affecting the
|
|
9
|
+
* others; if the whole round-trip fails (RPC/network), every prerequisite
|
|
10
|
+
* resolves to an `error` carrying that reason.
|
|
11
|
+
*/
|
|
12
|
+
export declare function verifyPrerequisites(prereqs: AnyPrerequisite[], ctx: PrerequisiteContext): Promise<AnyPrerequisiteResult[]>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import type { OnchainSDK } from "../../sdk/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Extension point that ties each prerequisite kind to its detail payload.
|
|
5
|
+
*
|
|
6
|
+
* Adding a new prerequisite kind only requires a new entry here: the generic
|
|
7
|
+
* machinery below and the UI renderer registry both key off this map, so TS
|
|
8
|
+
* forces every consumer to handle the new kind.
|
|
9
|
+
*
|
|
10
|
+
* IMPORTANT: only add prerequisites that are *actionable by the transaction
|
|
11
|
+
* sender* (the LP provider or borrower). A valid prerequisite is one the user
|
|
12
|
+
* can resolve themselves before retrying, e.g. approve a token (`allowance`)
|
|
13
|
+
* or acquire/free up funds (`balance`). Do NOT add protocol- or admin-level
|
|
14
|
+
* state the user cannot change, such as pool pause status or available pool
|
|
15
|
+
* liquidity; those are not actionable and must not be listed as prerequisites.
|
|
16
|
+
*/
|
|
17
|
+
export interface PrerequisiteDetailMap {
|
|
18
|
+
/** ERC-20 allowance from `owner` to `spender` must cover `required`. */
|
|
19
|
+
allowance: {
|
|
20
|
+
token: Address;
|
|
21
|
+
owner: Address;
|
|
22
|
+
spender: Address;
|
|
23
|
+
required: bigint;
|
|
24
|
+
/** On-chain allowance read; only present when the read succeeded. */
|
|
25
|
+
actual?: bigint;
|
|
26
|
+
};
|
|
27
|
+
/** ERC-20 balance of `owner` must cover `required`. */
|
|
28
|
+
balance: {
|
|
29
|
+
token: Address;
|
|
30
|
+
owner: Address;
|
|
31
|
+
required: bigint;
|
|
32
|
+
/** On-chain balance read; only present when the read succeeded. */
|
|
33
|
+
actual?: bigint;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export type PrerequisiteKind = keyof PrerequisiteDetailMap;
|
|
37
|
+
export type PrerequisiteDetail<K extends PrerequisiteKind = PrerequisiteKind> = PrerequisiteDetailMap[K];
|
|
38
|
+
/** Failure of the underlying on-chain read (revert, decode error, RPC error). */
|
|
39
|
+
export interface PrerequisiteError {
|
|
40
|
+
/** Decoded revert reason / error name, human-readable. */
|
|
41
|
+
reason: string;
|
|
42
|
+
/** Original error, kept for debugging. */
|
|
43
|
+
cause?: unknown;
|
|
44
|
+
}
|
|
45
|
+
export interface PrerequisiteBase<K extends PrerequisiteKind> {
|
|
46
|
+
id: string;
|
|
47
|
+
kind: K;
|
|
48
|
+
title: string;
|
|
49
|
+
detail: PrerequisiteDetail<K>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Outcome of verifying a single prerequisite: either the read succeeded (a
|
|
53
|
+
* `satisfied` boolean) or it reverted/failed (an `error` with the revert
|
|
54
|
+
* reason). The two variants are mutually exclusive.
|
|
55
|
+
*/
|
|
56
|
+
export type PrerequisiteResult<K extends PrerequisiteKind = PrerequisiteKind> = PrerequisiteBase<K> & ({
|
|
57
|
+
satisfied: boolean;
|
|
58
|
+
error?: undefined;
|
|
59
|
+
} | {
|
|
60
|
+
satisfied?: undefined;
|
|
61
|
+
error: PrerequisiteError;
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Discriminated union over every prerequisite kind. Switching on `kind`
|
|
65
|
+
* narrows `detail` to the matching payload, so React components can render
|
|
66
|
+
* kind-specific details with full type safety.
|
|
67
|
+
*/
|
|
68
|
+
export type AnyPrerequisiteResult = {
|
|
69
|
+
[K in PrerequisiteKind]: PrerequisiteResult<K>;
|
|
70
|
+
}[PrerequisiteKind];
|
|
71
|
+
/** Shared inputs for building and verifying prerequisites. */
|
|
72
|
+
export interface PrerequisiteContext {
|
|
73
|
+
sdk: OnchainSDK;
|
|
74
|
+
/** Address whose balances/allowances are checked (the tx sender). */
|
|
75
|
+
wallet: Address;
|
|
76
|
+
/** Block to read at; defaults to latest. Only set for testnet forks. */
|
|
77
|
+
blockNumber?: bigint;
|
|
78
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Hex } from "viem";
|
|
2
|
+
import type { SimulationError } from "./types.js";
|
|
3
|
+
/** Per-call slice of a `simulateCalls` failure we need to decode. */
|
|
4
|
+
export interface SimulationRevert {
|
|
5
|
+
error?: Error;
|
|
6
|
+
/** Raw revert return data, when present. */
|
|
7
|
+
data?: Hex;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Decodes a simulated transaction revert into a {@link SimulationError}.
|
|
11
|
+
*
|
|
12
|
+
* The simulated call is raw calldata (no ABI), so viem cannot decode the revert
|
|
13
|
+
* itself. We first try to decode the raw return bytes against the SDK's
|
|
14
|
+
* {@link errorAbis} (Gearbox protocol exceptions plus standard ERC-20 custom
|
|
15
|
+
* errors); failing that, we walk viem's error chain for a
|
|
16
|
+
* {@link ContractFunctionRevertedError} (covers `Error(string)` / `Panic`).
|
|
17
|
+
*/
|
|
18
|
+
export declare function decodeSimulationError(revert: SimulationRevert): SimulationError;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Address, type Log } from "viem";
|
|
2
|
+
import type { TokenTransfer } from "../../plugins/adapters/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parses ERC-20 `Transfer` logs and keeps only those involving one of the
|
|
5
|
+
* watched addresses (as sender or receiver). A log that touches several watched
|
|
6
|
+
* addresses is still emitted once.
|
|
7
|
+
*
|
|
8
|
+
* @param logs - raw logs from the simulated call
|
|
9
|
+
* @param watch - addresses whose transfers we care about (e.g. wallet + recipient)
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractERC20Transfers(logs: Log[], watch: Address[]): TokenTransfer[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Address, type Hex } from "viem";
|
|
2
|
+
import type { OnchainSDK } from "../../sdk/index.js";
|
|
3
|
+
import type { PoolOperation } from "../parse/index.js";
|
|
4
|
+
import type { PoolSimulationResult } from "./types.js";
|
|
5
|
+
export interface SimulatePoolOperationInput {
|
|
6
|
+
/** Only `client` is used, so any OnchainSDK works. */
|
|
7
|
+
sdk: OnchainSDK;
|
|
8
|
+
/** Parsed operation, used to resolve the underlying and pool tokens. */
|
|
9
|
+
operation: PoolOperation;
|
|
10
|
+
/** Target contract the calldata is sent to (the pool). */
|
|
11
|
+
to: Address;
|
|
12
|
+
/** Raw deposit/redeem calldata to simulate. */
|
|
13
|
+
calldata: Hex;
|
|
14
|
+
/** Wallet whose balance changes and transfers we track. */
|
|
15
|
+
wallet: Address;
|
|
16
|
+
/** Block to simulate at; defaults to latest. Only set for testnet forks. */
|
|
17
|
+
blockNumber?: bigint;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Simulates a pool deposit/redeem by sandwiching the raw calldata between
|
|
21
|
+
* `balanceOf(wallet)` reads of the underlying and pool (share) tokens.
|
|
22
|
+
*
|
|
23
|
+
* On success, returns the ERC-20 transfers emitted by the call that involve the
|
|
24
|
+
* wallet or the operation recipient (for merging into the parsed operation) and
|
|
25
|
+
* the balance changes grouped by watched address (wallet, plus the recipient
|
|
26
|
+
* when distinct); on revert, returns the decoded reason. Simulation runs against
|
|
27
|
+
* real chain state (no overrides), so an unmet prerequisite surfaces here as a
|
|
28
|
+
* failure.
|
|
29
|
+
*/
|
|
30
|
+
export declare function simulatePoolOperation(input: SimulatePoolOperationInput): Promise<PoolSimulationResult>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
import type { TokenTransfer } from "../../plugins/adapters/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Change in an address's balance of a single token over the simulated call.
|
|
5
|
+
* `delta` is `after - before` (negative when the address spent the token).
|
|
6
|
+
*/
|
|
7
|
+
export interface TokenBalanceChange {
|
|
8
|
+
token: Address;
|
|
9
|
+
before: bigint;
|
|
10
|
+
after: bigint;
|
|
11
|
+
delta: bigint;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Balance changes for a single watched address (e.g. the wallet or the
|
|
15
|
+
* operation recipient). Keyed purely by address; UI labeling is resolved
|
|
16
|
+
* separately by the presentation layer.
|
|
17
|
+
*/
|
|
18
|
+
export interface AddressBalanceChanges {
|
|
19
|
+
address: Address;
|
|
20
|
+
changes: TokenBalanceChange[];
|
|
21
|
+
}
|
|
22
|
+
/** Decoded revert of the simulated transaction. */
|
|
23
|
+
export interface SimulationError {
|
|
24
|
+
/** Human-readable revert reason / error name. */
|
|
25
|
+
reason: string;
|
|
26
|
+
/** Original error, kept for debugging. */
|
|
27
|
+
cause?: unknown;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Outcome of simulating a pool operation. On success it carries the
|
|
31
|
+
* wallet-filtered ERC-20 transfers (to merge into the parsed operation) and the
|
|
32
|
+
* balance changes grouped by watched address; on failure it carries the decoded
|
|
33
|
+
* revert reason.
|
|
34
|
+
*/
|
|
35
|
+
export type PoolSimulationResult = {
|
|
36
|
+
status: "success";
|
|
37
|
+
transfers: TokenTransfer[];
|
|
38
|
+
balanceChanges: AddressBalanceChanges[];
|
|
39
|
+
gasUsed: bigint;
|
|
40
|
+
} | {
|
|
41
|
+
status: "failure";
|
|
42
|
+
error: SimulationError;
|
|
43
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gearbox-protocol/sdk",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.11.0-next.1",
|
|
4
4
|
"description": "Gearbox SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -44,6 +44,11 @@
|
|
|
44
44
|
"import": "./dist/esm/permissionless/index.js",
|
|
45
45
|
"default": "./dist/cjs/permissionless/index.js"
|
|
46
46
|
},
|
|
47
|
+
"./preview": {
|
|
48
|
+
"types": "./dist/types/preview/index.d.ts",
|
|
49
|
+
"import": "./dist/esm/preview/index.js",
|
|
50
|
+
"default": "./dist/cjs/preview/index.js"
|
|
51
|
+
},
|
|
47
52
|
"./common-utils": {
|
|
48
53
|
"types": "./dist/types/common-utils/index.d.ts",
|
|
49
54
|
"import": "./dist/esm/common-utils/index.js",
|