Skip to content

Commit 756c8e8

Browse files
committed
test(compound_v2): cover constructor defaultVtoken fallback chain
compound_v2.ts branches went 45.45% → 69.56%. The CompoundV2Adapter constructor picks defaultVtoken from contracts via the `??` chain: vusdt → vusdc → vbnb → comptroller Previously only the vusdt rung was hit (every fixture set it). This commit adds 4 tests reaching into the private `defaultVtoken` field to assert each rung: - vusdc selected when vusdt absent - vbnb selected when vusdt + vusdc absent - comptroller as last-resort defaultVtoken when no v* entries (deliberate so brand-new Venus forks can stand up the adapter before fixture data lands; resolveVtoken still fails without a cache but the constructor must not) - empty contracts {} → constructor throws "Missing vToken or comptroller" Field access is via `(adapter as { defaultVtoken: Address })` rather than routing through buildSupply, which would otherwise hit resolveVtoken's RPC fallback and need its own readContract mock for each test.
1 parent d58307f commit 756c8e8

1 file changed

Lines changed: 56 additions & 0 deletions

File tree

ts/packages/defi-protocols/src/lending/compound_v2.test.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,59 @@ describe("CompoundV2Adapter — v1.0.6 utilization unit conversion", () => {
391391
expect(rates.total_supply).toBe(1_000_000n);
392392
});
393393
});
394+
395+
describe("CompoundV2Adapter — constructor defaultVtoken fallback chain", () => {
396+
// The constructor picks defaultVtoken from contracts via a `??` chain:
397+
// vusdt → vusdc → vbnb → comptroller
398+
// We assert the picked address by reaching into the private field — the
399+
// only way to observe each rung without routing through resolveVtoken's
400+
// RPC fallback (which would need its own readContract mock).
401+
function pickedDefault(adapter: object): Address {
402+
return (adapter as { defaultVtoken: Address }).defaultVtoken;
403+
}
404+
405+
it("picks vusdc when vusdt is absent", async () => {
406+
const { CompoundV2Adapter } = await import("./compound_v2.js");
407+
const entry: ProtocolEntry = {
408+
...makeEntry(),
409+
contracts: { vusdc: VUSDC, comptroller: COMPTROLLER },
410+
};
411+
const adapter = new CompoundV2Adapter(entry, "https://example/bnb");
412+
expect(pickedDefault(adapter).toLowerCase()).toBe(VUSDC.toLowerCase());
413+
});
414+
415+
it("picks vbnb when vusdt + vusdc are absent", async () => {
416+
const { CompoundV2Adapter } = await import("./compound_v2.js");
417+
const entry: ProtocolEntry = {
418+
...makeEntry(),
419+
contracts: { vbnb: VBNB, comptroller: COMPTROLLER },
420+
};
421+
const adapter = new CompoundV2Adapter(entry, "https://example/bnb");
422+
expect(pickedDefault(adapter).toLowerCase()).toBe(VBNB.toLowerCase());
423+
});
424+
425+
it("falls back to comptroller as a last-resort defaultVtoken when no v* entries exist", async () => {
426+
const { CompoundV2Adapter } = await import("./compound_v2.js");
427+
const entry: ProtocolEntry = {
428+
...makeEntry(),
429+
// No v* keys at all. The `??` chain settles on comptroller — that's
430+
// wonky-but-deliberate so integrators wiring a brand-new Venus fork
431+
// can stand the adapter up before fixture data lands. resolveVtoken
432+
// will still fail without the cache, but the constructor must not.
433+
contracts: { comptroller: COMPTROLLER },
434+
};
435+
const adapter = new CompoundV2Adapter(entry, "https://example/bnb");
436+
expect(pickedDefault(adapter).toLowerCase()).toBe(COMPTROLLER.toLowerCase());
437+
});
438+
439+
it("throws when neither v* nor comptroller is configured", async () => {
440+
const { CompoundV2Adapter } = await import("./compound_v2.js");
441+
const entry: ProtocolEntry = {
442+
...makeEntry(),
443+
contracts: {}, // empty → !vtoken → throws
444+
};
445+
expect(() => new CompoundV2Adapter(entry, "https://example/bnb")).toThrow(
446+
/Missing vToken or comptroller/,
447+
);
448+
});
449+
});

0 commit comments

Comments
 (0)