@carrot-protocol/clend-vaults-rpc 0.0.2 → 0.0.3-pub2-dev-be4bd59
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/addresses.d.ts +4 -0
- package/dist/addresses.js +14 -0
- package/dist/addresses.js.map +1 -0
- package/dist/idl/clend_vaults.d.ts +1556 -0
- package/dist/idl/clend_vaults.js +3 -0
- package/dist/idl/clend_vaults.js.map +1 -0
- package/dist/idl/clend_vaults.json +1550 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/math.d.ts +38 -0
- package/dist/math.js +79 -0
- package/dist/math.js.map +1 -0
- package/dist/program.d.ts +27 -0
- package/dist/program.js +294 -0
- package/dist/program.js.map +1 -0
- package/dist/rpc.d.ts +56 -0
- package/dist/rpc.js +685 -0
- package/dist/rpc.js.map +1 -0
- package/dist/state.d.ts +48 -0
- package/dist/state.js +108 -0
- package/dist/state.js.map +1 -0
- package/dist/swapper.d.ts +58 -0
- package/dist/swapper.js +109 -0
- package/dist/swapper.js.map +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +10 -0
- package/dist/utils.js.map +1 -0
- package/package.json +7 -2
- package/.prettierignore +0 -2
- package/makefile +0 -18
- package/src/addresses.ts +0 -19
- package/src/idl/clend_vaults.json +0 -1550
- package/src/idl/clend_vaults.ts +0 -1556
- package/src/math.ts +0 -103
- package/src/program.ts +0 -551
- package/src/rpc.ts +0 -1354
- package/src/state.ts +0 -188
- package/src/swapper.ts +0 -221
- package/src/utils.ts +0 -7
- package/tsconfig.json +0 -18
- /package/{src/index.ts → dist/index.d.ts} +0 -0
package/src/state.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { BN, web3 } from "@coral-xyz/anchor";
|
|
2
|
-
import { ClendVaultsProgram } from "./program";
|
|
3
|
-
import { getMint, Mint, unpackMint } from "@solana/spl-token";
|
|
4
|
-
|
|
5
|
-
export interface Vault {
|
|
6
|
-
address: web3.PublicKey;
|
|
7
|
-
sharesMint: web3.PublicKey;
|
|
8
|
-
sharesDecimals: number;
|
|
9
|
-
sharesSupply: BN;
|
|
10
|
-
manager: web3.PublicKey;
|
|
11
|
-
assets: VaultAsset[];
|
|
12
|
-
clendAccounts: VaultClendAccount[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface VaultAsset {
|
|
16
|
-
mint: VaultAssetMint;
|
|
17
|
-
oracle: web3.PublicKey;
|
|
18
|
-
reserve: VaultAssetReserve;
|
|
19
|
-
status: number;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface VaultAssetMint {
|
|
23
|
-
address: web3.PublicKey;
|
|
24
|
-
decimals: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface VaultAssetReserve {
|
|
28
|
-
address: web3.PublicKey;
|
|
29
|
-
amount: BN;
|
|
30
|
-
amountUi: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface VaultClendAccount {
|
|
34
|
-
address: web3.PublicKey;
|
|
35
|
-
status: number;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface VaultEquity {
|
|
39
|
-
// vault address
|
|
40
|
-
address: web3.PublicKey;
|
|
41
|
-
|
|
42
|
-
// total vault equity in usd
|
|
43
|
-
vaultEquity: number;
|
|
44
|
-
|
|
45
|
-
// equity in each clend account in usd
|
|
46
|
-
clendAccountEquity: {
|
|
47
|
-
address: web3.PublicKey;
|
|
48
|
-
equity: number;
|
|
49
|
-
}[];
|
|
50
|
-
|
|
51
|
-
// equity in each reserve in usd
|
|
52
|
-
reserveEquity: {
|
|
53
|
-
address: web3.PublicKey;
|
|
54
|
-
equity: number;
|
|
55
|
-
}[];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export async function parseVaultAccount(
|
|
59
|
-
address: web3.PublicKey,
|
|
60
|
-
vaultAccountInfo: web3.AccountInfo<Buffer>,
|
|
61
|
-
connection: web3.Connection,
|
|
62
|
-
): Promise<Vault> {
|
|
63
|
-
const program = new ClendVaultsProgram();
|
|
64
|
-
const vaultDataRaw = program.program.coder.accounts.decode(
|
|
65
|
-
"vault",
|
|
66
|
-
vaultAccountInfo.data,
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
// filter out unused slots
|
|
70
|
-
// presuming equal amounts of each asset type
|
|
71
|
-
const reserves = vaultDataRaw.assets
|
|
72
|
-
.map((asset: any) => parsePk(asset.reserve))
|
|
73
|
-
.filter((r: web3.PublicKey) => !r.equals(web3.PublicKey.default));
|
|
74
|
-
const mints = vaultDataRaw.assets
|
|
75
|
-
.map((asset: any) => parsePk(asset.mint))
|
|
76
|
-
.filter((m: web3.PublicKey) => !m.equals(web3.PublicKey.default));
|
|
77
|
-
const oracles = vaultDataRaw.assets
|
|
78
|
-
.map((asset: any) => parsePk(asset.oracle))
|
|
79
|
-
.filter((o: web3.PublicKey) => !o.equals(web3.PublicKey.default));
|
|
80
|
-
|
|
81
|
-
const vaultReserveData: VaultAssetReserve[] = await getReserves(
|
|
82
|
-
reserves,
|
|
83
|
-
connection,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const assets: VaultAsset[] = [];
|
|
87
|
-
for (let i = 0; i < mints.length; i++) {
|
|
88
|
-
const asset = vaultDataRaw.assets[i];
|
|
89
|
-
const reserve = vaultReserveData.find((r) =>
|
|
90
|
-
r.address.equals(reserves[i]),
|
|
91
|
-
)!;
|
|
92
|
-
const oracle = oracles[i];
|
|
93
|
-
const mint = mints[i];
|
|
94
|
-
let mintDecimals: number | undefined = undefined;
|
|
95
|
-
try {
|
|
96
|
-
const mintState = await getMintState(mint, connection);
|
|
97
|
-
mintDecimals = parseNumber(mintState.decimals);
|
|
98
|
-
} catch (e) {
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
assets.push({
|
|
102
|
-
mint: {
|
|
103
|
-
address: mint,
|
|
104
|
-
decimals: mintDecimals,
|
|
105
|
-
},
|
|
106
|
-
oracle,
|
|
107
|
-
reserve,
|
|
108
|
-
status: parseNumber(asset.status),
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const clendAccounts: VaultClendAccount[] = vaultDataRaw.clendAccounts
|
|
113
|
-
.map((clendAccount: any) => ({
|
|
114
|
-
address: parsePk(clendAccount.address),
|
|
115
|
-
status: parseNumber(clendAccount.status),
|
|
116
|
-
}))
|
|
117
|
-
.filter(
|
|
118
|
-
(ca: VaultClendAccount) => !ca.address.equals(web3.PublicKey.default),
|
|
119
|
-
);
|
|
120
|
-
const sharesMint = parsePk(vaultDataRaw.shares);
|
|
121
|
-
const sharesMintState = await getMintState(sharesMint, connection);
|
|
122
|
-
|
|
123
|
-
const vaultData: Vault = {
|
|
124
|
-
address,
|
|
125
|
-
sharesMint,
|
|
126
|
-
sharesDecimals: parseNumber(sharesMintState.decimals),
|
|
127
|
-
sharesSupply: new BN(sharesMintState.supply.toString()),
|
|
128
|
-
manager: parsePk(vaultDataRaw.manager),
|
|
129
|
-
clendAccounts,
|
|
130
|
-
assets,
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
return vaultData;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export async function getReserves(
|
|
137
|
-
reserves: web3.PublicKey[],
|
|
138
|
-
connection: web3.Connection,
|
|
139
|
-
): Promise<VaultAssetReserve[]> {
|
|
140
|
-
const reservesData: VaultAssetReserve[] = [];
|
|
141
|
-
for (const reserve of reserves) {
|
|
142
|
-
const tokenAccountBalanceResponse =
|
|
143
|
-
await connection.getTokenAccountBalance(reserve);
|
|
144
|
-
const r = parseReserve(reserve, tokenAccountBalanceResponse.value);
|
|
145
|
-
reservesData.push(r);
|
|
146
|
-
}
|
|
147
|
-
return reservesData;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
export function parseReserve(
|
|
151
|
-
address: web3.PublicKey,
|
|
152
|
-
tokenAmount: web3.TokenAmount,
|
|
153
|
-
): VaultAssetReserve {
|
|
154
|
-
return {
|
|
155
|
-
address,
|
|
156
|
-
amount: new BN(tokenAmount.amount),
|
|
157
|
-
amountUi: parseNumber(tokenAmount.uiAmount!),
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export async function getMintState(
|
|
162
|
-
mint: web3.PublicKey,
|
|
163
|
-
connection: web3.Connection,
|
|
164
|
-
): Promise<Mint> {
|
|
165
|
-
const mintAccountInfo = await connection.getAccountInfo(mint);
|
|
166
|
-
if (!mintAccountInfo) {
|
|
167
|
-
throw new Error(`Mint account not found: ${mint.toString()}`);
|
|
168
|
-
}
|
|
169
|
-
return unpackMint(mint, mintAccountInfo, mintAccountInfo.owner);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function parseNumber(value: any): number {
|
|
173
|
-
const n = Number(value);
|
|
174
|
-
if (isNaN(n)) {
|
|
175
|
-
throw new Error(`Error Parsing Number: inputValue: ${value}, error: ${n}`);
|
|
176
|
-
}
|
|
177
|
-
return n;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export function parsePk(value: any): web3.PublicKey {
|
|
181
|
-
try {
|
|
182
|
-
return new web3.PublicKey(value);
|
|
183
|
-
} catch (e) {
|
|
184
|
-
throw new Error(
|
|
185
|
-
`Error Parsing Public Key: inputValue: ${value}, error: ${e}`,
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
}
|
package/src/swapper.ts
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import { ISwapper } from "@carrot-protocol/clend-rpc";
|
|
2
|
-
import { AnchorProvider, BN, Wallet, web3 } from "@coral-xyz/anchor";
|
|
3
|
-
import {
|
|
4
|
-
createJupiterApiClient,
|
|
5
|
-
QuoteResponse as JupQuoteResponse,
|
|
6
|
-
Instruction,
|
|
7
|
-
} from "@jup-ag/api";
|
|
8
|
-
import { JUPITER_SWAP_PROGRAM_ID } from "./addresses";
|
|
9
|
-
import { TOKEN_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token";
|
|
10
|
-
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
|
|
11
|
-
import { ClendVaultsClient } from "./rpc";
|
|
12
|
-
import { parseVaultAccount, Vault } from "./state";
|
|
13
|
-
import { ClendVaultsProgram } from "./program";
|
|
14
|
-
|
|
15
|
-
const QUOTE_URL = "https://api.jup.ag/swap/v1/quote";
|
|
16
|
-
|
|
17
|
-
type ClendVaultsJupSwapperData = {
|
|
18
|
-
quoteResponse: JupQuoteResponse;
|
|
19
|
-
vault: web3.PublicKey;
|
|
20
|
-
inputMint: web3.PublicKey;
|
|
21
|
-
outputMint: web3.PublicKey;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export class ClendVaultsJupSwapper implements ISwapper {
|
|
25
|
-
private readonly jupiterApi;
|
|
26
|
-
private readonly connection: web3.Connection;
|
|
27
|
-
private readonly clendVaultsProgram: ClendVaultsProgram;
|
|
28
|
-
|
|
29
|
-
constructor(connection: web3.Connection, apiKey?: string) {
|
|
30
|
-
this.jupiterApi = createJupiterApiClient({
|
|
31
|
-
basePath: QUOTE_URL,
|
|
32
|
-
apiKey,
|
|
33
|
-
});
|
|
34
|
-
this.connection = connection;
|
|
35
|
-
this.clendVaultsProgram = new ClendVaultsProgram();
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Implements the getQuote method from the ISwapper interface.
|
|
40
|
-
* It takes a standardized QuoteRequest and returns a standardized SwapQuote.
|
|
41
|
-
*/
|
|
42
|
-
async getQuote(request: QuoteRequest): Promise<SwapQuote> {
|
|
43
|
-
const { inputMint, outputMint, inputAmount, swapMode, slippageBps, payer } =
|
|
44
|
-
request;
|
|
45
|
-
|
|
46
|
-
const quoteResponse: JupQuoteResponse = await this.jupiterApi.quoteGet({
|
|
47
|
-
inputMint: inputMint.toBase58(),
|
|
48
|
-
outputMint: outputMint.toBase58(),
|
|
49
|
-
amount: inputAmount.toNumber(),
|
|
50
|
-
slippageBps,
|
|
51
|
-
swapMode,
|
|
52
|
-
onlyDirectRoutes: true,
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
// Populate the standardized SwapQuote object
|
|
56
|
-
return {
|
|
57
|
-
payer,
|
|
58
|
-
inAmount: new BN(quoteResponse.inAmount),
|
|
59
|
-
outAmount: new BN(quoteResponse.outAmount),
|
|
60
|
-
otherAmountThreshold: new BN(quoteResponse.otherAmountThreshold),
|
|
61
|
-
swapperData: {
|
|
62
|
-
quoteResponse,
|
|
63
|
-
inputMint,
|
|
64
|
-
outputMint,
|
|
65
|
-
vault: payer,
|
|
66
|
-
} as ClendVaultsJupSwapperData,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Implements the getSwapIxns method from the ISwapper interface.
|
|
72
|
-
* It takes a standardized SwapQuote and returns standardized SwapIxns.
|
|
73
|
-
*/
|
|
74
|
-
async getSwapIxns(quote: SwapQuote): Promise<SwapIxns> {
|
|
75
|
-
// Cast the swapperData object back to its specific type
|
|
76
|
-
const { inputMint, outputMint, vault, quoteResponse } =
|
|
77
|
-
quote.swapperData as ClendVaultsJupSwapperData;
|
|
78
|
-
|
|
79
|
-
const {
|
|
80
|
-
swapInstruction,
|
|
81
|
-
addressLookupTableAddresses,
|
|
82
|
-
setupInstructions,
|
|
83
|
-
cleanupInstruction,
|
|
84
|
-
} = await this.jupiterApi.swapInstructionsPost({
|
|
85
|
-
swapRequest: {
|
|
86
|
-
userPublicKey: vault.toBase58(),
|
|
87
|
-
payer: quote.payer.toBase58(),
|
|
88
|
-
quoteResponse: quoteResponse,
|
|
89
|
-
computeUnitPriceMicroLamports: 1,
|
|
90
|
-
wrapAndUnwrapSol: false, // TODO: may need to change this
|
|
91
|
-
destinationTokenAccount: undefined,
|
|
92
|
-
useSharedAccounts: false,
|
|
93
|
-
feeAccount: undefined,
|
|
94
|
-
skipUserAccountsRpcCalls: true,
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const swapIx = transformResponseIx(swapInstruction);
|
|
99
|
-
|
|
100
|
-
const swapRemainingAccounts: web3.AccountMeta[] = swapIx.keys.map(
|
|
101
|
-
(key) => ({
|
|
102
|
-
pubkey: key.pubkey,
|
|
103
|
-
// If the account is the vault PDA, mark it as NOT a signer for the client transaction.
|
|
104
|
-
isSigner: key.pubkey.equals(vault) ? false : key.isSigner,
|
|
105
|
-
isWritable: key.isWritable,
|
|
106
|
-
}),
|
|
107
|
-
);
|
|
108
|
-
const swapData = swapIx.data;
|
|
109
|
-
|
|
110
|
-
const vaultAssetInReserve = getAssociatedTokenAddressSync(
|
|
111
|
-
inputMint,
|
|
112
|
-
vault,
|
|
113
|
-
true,
|
|
114
|
-
TOKEN_PROGRAM_ID,
|
|
115
|
-
);
|
|
116
|
-
const vaultAssetOutReserve = getAssociatedTokenAddressSync(
|
|
117
|
-
outputMint,
|
|
118
|
-
vault,
|
|
119
|
-
true,
|
|
120
|
-
TOKEN_PROGRAM_ID,
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
const vaultAccountInfo = await this.connection.getAccountInfo(vault);
|
|
124
|
-
if (!vaultAccountInfo) {
|
|
125
|
-
throw new Error(`Vault account not found: ${vault.toString()}`);
|
|
126
|
-
}
|
|
127
|
-
const vaultState = await parseVaultAccount(
|
|
128
|
-
vault,
|
|
129
|
-
vaultAccountInfo,
|
|
130
|
-
this.connection,
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
const ixns = await this.clendVaultsProgram.swap(
|
|
134
|
-
vault,
|
|
135
|
-
vaultState.manager,
|
|
136
|
-
inputMint,
|
|
137
|
-
outputMint,
|
|
138
|
-
vaultAssetInReserve,
|
|
139
|
-
vaultAssetOutReserve,
|
|
140
|
-
swapData,
|
|
141
|
-
swapRemainingAccounts,
|
|
142
|
-
JUPITER_SWAP_PROGRAM_ID,
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
const allIxs = [...ixns];
|
|
146
|
-
|
|
147
|
-
// Populate the standardized SwapIxns object
|
|
148
|
-
return {
|
|
149
|
-
ixns: allIxs,
|
|
150
|
-
luts: addressLookupTableAddresses.map((key) => new web3.PublicKey(key)),
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Helper functions remain the same
|
|
156
|
-
function transformResponseIxs(
|
|
157
|
-
instructions: Instruction[],
|
|
158
|
-
): web3.TransactionInstruction[] {
|
|
159
|
-
return instructions.map(transformResponseIx);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function transformResponseIx(
|
|
163
|
-
instruction: Instruction,
|
|
164
|
-
): web3.TransactionInstruction {
|
|
165
|
-
return new web3.TransactionInstruction({
|
|
166
|
-
programId: new web3.PublicKey(instruction.programId),
|
|
167
|
-
keys: instruction.accounts.map((account) => ({
|
|
168
|
-
pubkey: new web3.PublicKey(account.pubkey),
|
|
169
|
-
isSigner: account.isSigner,
|
|
170
|
-
isWritable: account.isWritable,
|
|
171
|
-
})),
|
|
172
|
-
data: Buffer.from(instruction.data, "base64"),
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
type SwapMode = "ExactIn" | "ExactOut";
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* A standardized request object for getting a swap quote.
|
|
180
|
-
*/
|
|
181
|
-
interface QuoteRequest {
|
|
182
|
-
payer: web3.PublicKey;
|
|
183
|
-
inputMint: web3.PublicKey;
|
|
184
|
-
inputMintDecimals: number;
|
|
185
|
-
outputMint: web3.PublicKey;
|
|
186
|
-
outputMintDecimals: number;
|
|
187
|
-
inputAmount: BN;
|
|
188
|
-
swapMode: SwapMode;
|
|
189
|
-
slippageBps: number;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* A standardized response from a getQuote call.
|
|
194
|
-
*/
|
|
195
|
-
interface SwapQuote {
|
|
196
|
-
/** The public key of the account swapping. */
|
|
197
|
-
payer: web3.PublicKey;
|
|
198
|
-
|
|
199
|
-
/** The final amount of the input token, considering fees or adjustments. */
|
|
200
|
-
inAmount: BN;
|
|
201
|
-
|
|
202
|
-
/** The optimistic expected amount of the output token. */
|
|
203
|
-
outAmount: BN;
|
|
204
|
-
|
|
205
|
-
/** The minimum output or maximum input amount after applying slippage. */
|
|
206
|
-
otherAmountThreshold: BN;
|
|
207
|
-
|
|
208
|
-
/** A generic property for the swapper to pass its own specific data
|
|
209
|
-
* (e.g., the full Jupiter API response) from its getQuote method
|
|
210
|
-
* to its getSwapIxns method.
|
|
211
|
-
*/
|
|
212
|
-
swapperData: any;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* The standardized set of instructions and lookup tables returned by a swapper.
|
|
217
|
-
*/
|
|
218
|
-
interface SwapIxns {
|
|
219
|
-
ixns: web3.TransactionInstruction[];
|
|
220
|
-
luts: web3.PublicKey[];
|
|
221
|
-
}
|
package/src/utils.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { AnchorProvider, Wallet, web3 } from "@coral-xyz/anchor";
|
|
2
|
-
|
|
3
|
-
export function getDummyProvider(): AnchorProvider {
|
|
4
|
-
const connection = new web3.Connection("http://localhost:8899");
|
|
5
|
-
const wallet = new Wallet(web3.Keypair.generate());
|
|
6
|
-
return new AnchorProvider(connection, wallet, {});
|
|
7
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"outDir": "./dist",
|
|
4
|
-
"rootDir": "./src",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"module": "commonjs",
|
|
7
|
-
"target": "es2020",
|
|
8
|
-
"moduleResolution": "node",
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"sourceMap": true,
|
|
14
|
-
"resolveJsonModule": true
|
|
15
|
-
},
|
|
16
|
-
"include": ["src/**/*"]
|
|
17
|
-
}
|
|
18
|
-
|
|
File without changes
|