Skip to content

Commit ec936ad

Browse files
committed
Enhance Moolah SDK with holdings functionality and improve API parameter handling. Added support for fetching user holdings by type (vault or market) and updated market and vault list methods to accept multi-chain parameters. Updated tests to cover new holdings functionality.
1 parent 19bad2d commit ec936ad

10 files changed

Lines changed: 405 additions & 63 deletions

File tree

packages/moolah-lending-sdk/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# @lista-dao/moolah-lending-sdk
22

3+
## 1.0.3
4+
5+
### Patch Changes
6+
7+
- Enhance Moolah SDK with holdings functionality and improve API parameter handling
8+
- Updated dependencies
9+
- @lista-dao/moolah-sdk-core@1.0.4
10+
311
## 1.0.2
412

513
### Patch Changes

packages/moolah-lending-sdk/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ const chain = sdk.getApiChain(chainId); // "bsc" or "ethereum"
123123

124124
// Market list with filters
125125
const markets = await sdk.getMarketList({
126-
chain,
126+
chain: [chain, "ethereum"], // also supports single string
127127
page: 1,
128128
pageSize: 20,
129129
sort: "rate", // Sort field
@@ -133,11 +133,12 @@ const markets = await sdk.getMarketList({
133133
loans: ["USDT"], // Filter by loan tokens
134134
collaterals: ["ETH"], // Filter by collateral tokens
135135
termType: 0, // 0 = flexible, 1 = fixed
136+
smartLendingChecked: true, // Optional smart lending filter
136137
});
137138

138139
// Vault list with filters
139140
const vaults = await sdk.getVaultList({
140-
chain,
141+
chain: [chain, "ethereum"], // also supports single string
141142
page: 1,
142143
pageSize: 20,
143144
sort: "apy",
@@ -154,6 +155,12 @@ const marketInfo = await sdk.getMarketInfo(chainId, marketId);
154155
// Vault metadata
155156
const vaultMeta = await sdk.getVaultMetadata(vaultAddress);
156157

158+
// User holdings by type ("vault" | "market")
159+
const vaultHoldings = await sdk.getHoldings({
160+
userAddress: walletAddress,
161+
type: "vault",
162+
});
163+
157164
// Vaults for a market
158165
const marketVaults = await sdk.getMarketVaultDetails(marketId, {
159166
page: 1,

packages/moolah-lending-sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lista-dao/moolah-lending-sdk",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"type": "module",
55
"main": "./dist/index.js",
66
"module": "./dist/index.js",

packages/moolah-lending-sdk/src/MoolahSDK.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ import type {
2323
ApiVaultInfo,
2424
ApiMarketList,
2525
ApiMarketVaultList,
26+
ApiHoldingsParams,
27+
ApiHoldingsData,
28+
ApiVaultHoldingsData,
29+
ApiMarketHoldingsData,
2630
ApiTableParams,
31+
ApiVaultListParams,
32+
ApiMarketListParams,
2733
NetworkName,
2834
NetworkContracts,
2935
WriteMarketConfig,
@@ -312,31 +318,38 @@ export class MoolahSDK {
312318
return this.apiClient.getMarketInfo(marketId);
313319
}
314320

315-
async getVaultList(
316-
params: ApiTableParams & {
317-
assets?: string[];
318-
curators?: string[];
319-
chain: string;
320-
},
321-
): Promise<ApiVaultList> {
321+
async getVaultList(params: ApiVaultListParams): Promise<ApiVaultList> {
322322
return this.apiClient.getVaultList(params);
323323
}
324324

325325
async getVaultMetadata(address: Address): Promise<ApiVaultInfo> {
326326
return this.apiClient.getVaultInfo(address);
327327
}
328328

329-
async getMarketList(
330-
params: ApiTableParams & {
331-
loans?: string[];
332-
collaterals?: string[];
333-
termType?: number;
334-
chain: string;
335-
},
336-
): Promise<ApiMarketList> {
329+
async getMarketList(params: ApiMarketListParams): Promise<ApiMarketList> {
337330
return this.apiClient.getMarketList(params);
338331
}
339332

333+
async getHoldings(
334+
params: Omit<ApiHoldingsParams, "type"> & { type: "vault" },
335+
): Promise<ApiVaultHoldingsData>;
336+
async getHoldings(
337+
params: Omit<ApiHoldingsParams, "type"> & { type: "market" },
338+
): Promise<ApiMarketHoldingsData>;
339+
async getHoldings(params: ApiHoldingsParams): Promise<ApiHoldingsData>;
340+
async getHoldings(params: ApiHoldingsParams): Promise<ApiHoldingsData> {
341+
if (params.type === "vault") {
342+
return this.apiClient.getHoldings({
343+
userAddress: params.userAddress,
344+
type: "vault",
345+
});
346+
}
347+
return this.apiClient.getHoldings({
348+
userAddress: params.userAddress,
349+
type: "market",
350+
});
351+
}
352+
340353
async getMarketVaultDetails(
341354
marketId: Address,
342355
params?: Omit<ApiTableParams, "zone">,

packages/moolah-lending-sdk/src/__tests__/MoolahSDK.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ vi.mock("@lista-dao/moolah-sdk-core", async (importOriginal) => {
145145
address: "0x1111111111111111111111111111111111111111",
146146
}),
147147
getMarketList: vi.fn().mockResolvedValue({ list: [], total: 0 }),
148+
getHoldings: vi.fn().mockImplementation((params: { type: string }) => {
149+
if (params.type === "market") {
150+
return Promise.resolve({ objs: [], cdps: [], type: "market" });
151+
}
152+
return Promise.resolve({ objs: [], cdps: [], type: "vault" });
153+
}),
148154
getMarketVaultDetails: vi.fn().mockResolvedValue({ list: [], total: 0 }),
149155
})),
150156
};
@@ -283,6 +289,26 @@ describe("MoolahSDK", () => {
283289
expect(result.list).toBeDefined();
284290
});
285291

292+
it("should get holdings from API", async () => {
293+
const result = await sdk.getHoldings({
294+
userAddress: WALLET,
295+
type: "vault",
296+
});
297+
expect(result).toBeDefined();
298+
expect(Array.isArray(result.objs)).toBe(true);
299+
expect(result.type).toBe("vault");
300+
});
301+
302+
it("should get market holdings from API", async () => {
303+
const result = await sdk.getHoldings({
304+
userAddress: WALLET,
305+
type: "market",
306+
});
307+
expect(result).toBeDefined();
308+
expect(Array.isArray(result.objs)).toBe(true);
309+
expect(result.type).toBe("market");
310+
});
311+
286312
it("should get market vault details from API", async () => {
287313
const result = await sdk.getMarketVaultDetails(MARKET_ID);
288314
expect(result).toBeDefined();

packages/moolah-sdk-core/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# @lista-dao/moolah-sdk-core
22

3+
## 1.0.4
4+
5+
### Patch Changes
6+
7+
- Enhance Moolah SDK with holdings functionality and improve API parameter handling
8+
39
## 1.0.3
410

511
### Patch Changes

packages/moolah-sdk-core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lista-dao/moolah-sdk-core",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"type": "module",
55
"main": "./dist/index.js",
66
"module": "./dist/index.js",
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { MoolahApiClient } from "../api/client";
3+
4+
function makeSuccessResponse<T>(data: T): Response {
5+
return {
6+
ok: true,
7+
status: 200,
8+
statusText: "OK",
9+
json: async () => ({ code: "000000000", msg: "ok", data }),
10+
} as unknown as Response;
11+
}
12+
13+
describe("MoolahApiClient list query serialization", () => {
14+
let fetchMock: ReturnType<typeof vi.fn>;
15+
let client: MoolahApiClient;
16+
17+
beforeEach(() => {
18+
fetchMock = vi.fn().mockResolvedValue(makeSuccessResponse({ total: 0, list: [] }));
19+
client = new MoolahApiClient({
20+
baseUrl: "https://api.lista.org",
21+
fetch: fetchMock as unknown as typeof fetch,
22+
});
23+
});
24+
25+
it("should serialize vault filters using bracket array params", async () => {
26+
await client.getVaultList({
27+
page: 1,
28+
pageSize: 10,
29+
sort: "depositsUsd",
30+
order: "desc",
31+
zone: 0,
32+
keyword: "123",
33+
chain: ["bsc", "ethereum"],
34+
assets: ["USDT", "BTCB"],
35+
curators: ["Pangolins", "MEV Capital"],
36+
});
37+
38+
expect(fetchMock).toHaveBeenCalledTimes(1);
39+
const url = new URL(String(fetchMock.mock.calls[0][0]));
40+
41+
expect(url.pathname).toBe("/api/moolah/vault/list");
42+
expect(url.searchParams.get("chain")).toBe("bsc,ethereum");
43+
expect(url.searchParams.getAll("assets[]")).toEqual(["USDT", "BTCB"]);
44+
expect(url.searchParams.getAll("curators[]")).toEqual([
45+
"Pangolins",
46+
"MEV Capital",
47+
]);
48+
expect(url.searchParams.get("assets")).toBeNull();
49+
expect(url.searchParams.get("curators")).toBeNull();
50+
});
51+
52+
it("should serialize market filters with smartLendingChecked", async () => {
53+
await client.getMarketList({
54+
page: 1,
55+
pageSize: 10,
56+
sort: "liquidity",
57+
order: "desc",
58+
zone: 3,
59+
keyword: "",
60+
chain: ["bsc", "ethereum"],
61+
loans: ["BTCB", "USDT"],
62+
collaterals: ["BTCB", "SolvBTC"],
63+
smartLendingChecked: true,
64+
});
65+
66+
expect(fetchMock).toHaveBeenCalledTimes(1);
67+
const url = new URL(String(fetchMock.mock.calls[0][0]));
68+
69+
expect(url.pathname).toBe("/api/moolah/borrow/markets");
70+
expect(url.searchParams.get("chain")).toBe("bsc,ethereum");
71+
expect(url.searchParams.getAll("loans[]")).toEqual(["BTCB", "USDT"]);
72+
expect(url.searchParams.getAll("collaterals[]")).toEqual([
73+
"BTCB",
74+
"SolvBTC",
75+
]);
76+
expect(url.searchParams.get("smartLendingChecked")).toBe("true");
77+
expect(url.searchParams.get("loans")).toBeNull();
78+
expect(url.searchParams.get("collaterals")).toBeNull();
79+
});
80+
81+
it("should serialize holdings params for vault and market types", async () => {
82+
await client.getHoldings({
83+
userAddress: "0x05e3a7a66945ca9af73f66660f22ffb36332fa54",
84+
type: "vault",
85+
});
86+
await client.getHoldings({
87+
userAddress: "0x05e3a7a66945ca9af73f66660f22ffb36332fa54",
88+
type: "market",
89+
});
90+
91+
expect(fetchMock).toHaveBeenCalledTimes(2);
92+
93+
const vaultUrl = new URL(String(fetchMock.mock.calls[0][0]));
94+
expect(vaultUrl.pathname).toBe("/api/moolah/one/holding");
95+
expect(vaultUrl.searchParams.get("userAddress")).toBe(
96+
"0x05e3a7a66945ca9af73f66660f22ffb36332fa54",
97+
);
98+
expect(vaultUrl.searchParams.get("type")).toBe("vault");
99+
100+
const marketUrl = new URL(String(fetchMock.mock.calls[1][0]));
101+
expect(marketUrl.pathname).toBe("/api/moolah/one/holding");
102+
expect(marketUrl.searchParams.get("userAddress")).toBe(
103+
"0x05e3a7a66945ca9af73f66660f22ffb36332fa54",
104+
);
105+
expect(marketUrl.searchParams.get("type")).toBe("market");
106+
});
107+
});

0 commit comments

Comments
 (0)