@hypurrquant/defi-cli 1.0.1 → 1.0.2

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.
@@ -5724,6 +5724,7 @@ var init_dist2 = __esm({
5724
5724
  }
5725
5725
  };
5726
5726
  CTOKEN_ABI = parseAbi17([
5727
+ "function underlying() external view returns (address)",
5727
5728
  "function supplyRatePerBlock() external view returns (uint256)",
5728
5729
  "function borrowRatePerBlock() external view returns (uint256)",
5729
5730
  "function totalSupply() external view returns (uint256)",
@@ -5737,7 +5738,10 @@ var init_dist2 = __esm({
5737
5738
  CompoundV2Adapter = class {
5738
5739
  protocolName;
5739
5740
  defaultVtoken;
5741
+ vTokenCandidates;
5740
5742
  rpcUrl;
5743
+ // Lazy cache: underlying asset address (lowercased) → vToken address
5744
+ vTokenByAsset = null;
5741
5745
  constructor(entry, rpcUrl) {
5742
5746
  this.protocolName = entry.name;
5743
5747
  this.rpcUrl = rpcUrl;
@@ -5745,6 +5749,26 @@ var init_dist2 = __esm({
5745
5749
  const vtoken = contracts["vusdt"] ?? contracts["vusdc"] ?? contracts["vbnb"] ?? contracts["comptroller"];
5746
5750
  if (!vtoken) throw DefiError.contractError("Missing vToken or comptroller address");
5747
5751
  this.defaultVtoken = vtoken;
5752
+ this.vTokenCandidates = Object.entries(contracts).filter(([k]) => /^v[a-z][a-z0-9]*$/i.test(k)).map(([, v]) => v);
5753
+ if (this.vTokenCandidates.length === 0) this.vTokenCandidates = [vtoken];
5754
+ }
5755
+ async resolveVtoken(asset) {
5756
+ if (!this.rpcUrl) return null;
5757
+ if (!this.vTokenByAsset) {
5758
+ const client = createPublicClient13({ transport: http13(this.rpcUrl) });
5759
+ const map = /* @__PURE__ */ new Map();
5760
+ const lookups = await Promise.allSettled(
5761
+ this.vTokenCandidates.map(async (v) => {
5762
+ const u = await client.readContract({ address: v, abi: CTOKEN_ABI, functionName: "underlying" });
5763
+ return [u.toLowerCase(), v];
5764
+ })
5765
+ );
5766
+ for (const r of lookups) {
5767
+ if (r.status === "fulfilled") map.set(r.value[0], r.value[1]);
5768
+ }
5769
+ this.vTokenByAsset = map;
5770
+ }
5771
+ return this.vTokenByAsset.get(asset.toLowerCase()) ?? null;
5748
5772
  }
5749
5773
  name() {
5750
5774
  return this.protocolName;
@@ -5808,15 +5832,27 @@ var init_dist2 = __esm({
5808
5832
  async getRates(asset) {
5809
5833
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
5810
5834
  const client = createPublicClient13({ transport: http13(this.rpcUrl) });
5835
+ const vtoken = await this.resolveVtoken(asset);
5836
+ if (!vtoken) {
5837
+ return {
5838
+ protocol: this.protocolName,
5839
+ asset,
5840
+ supply_apy: 0,
5841
+ borrow_variable_apy: 0,
5842
+ utilization: 0,
5843
+ total_supply: 0n,
5844
+ total_borrow: 0n
5845
+ };
5846
+ }
5811
5847
  const [supplyRate, borrowRate, totalSupply, totalBorrows] = await Promise.all([
5812
- client.readContract({ address: this.defaultVtoken, abi: CTOKEN_ABI, functionName: "supplyRatePerBlock" }).catch((e) => {
5848
+ client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "supplyRatePerBlock" }).catch((e) => {
5813
5849
  throw DefiError.rpcError(`[${this.protocolName}] supplyRatePerBlock failed: ${e}`);
5814
5850
  }),
5815
- client.readContract({ address: this.defaultVtoken, abi: CTOKEN_ABI, functionName: "borrowRatePerBlock" }).catch((e) => {
5851
+ client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "borrowRatePerBlock" }).catch((e) => {
5816
5852
  throw DefiError.rpcError(`[${this.protocolName}] borrowRatePerBlock failed: ${e}`);
5817
5853
  }),
5818
- client.readContract({ address: this.defaultVtoken, abi: CTOKEN_ABI, functionName: "totalSupply" }).catch(() => 0n),
5819
- client.readContract({ address: this.defaultVtoken, abi: CTOKEN_ABI, functionName: "totalBorrows" }).catch(() => 0n)
5854
+ client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "totalSupply" }).catch(() => 0n),
5855
+ client.readContract({ address: vtoken, abi: CTOKEN_ABI, functionName: "totalBorrows" }).catch(() => 0n)
5820
5856
  ]);
5821
5857
  const supplyPerBlock = Number(supplyRate) / 1e18;
5822
5858
  const borrowPerBlock = Number(borrowRate) / 1e18;
@@ -5842,6 +5878,7 @@ var init_dist2 = __esm({
5842
5878
  }
5843
5879
  };
5844
5880
  COMET_ABI = parseAbi18([
5881
+ "function baseToken() external view returns (address)",
5845
5882
  "function getUtilization() external view returns (uint256)",
5846
5883
  "function getSupplyRate(uint256 utilization) external view returns (uint64)",
5847
5884
  "function getBorrowRate(uint256 utilization) external view returns (uint64)",
@@ -5927,6 +5964,24 @@ var init_dist2 = __esm({
5927
5964
  async getRates(asset) {
5928
5965
  if (!this.rpcUrl) throw DefiError.rpcError("No RPC URL configured");
5929
5966
  const client = createPublicClient14({ transport: http14(this.rpcUrl) });
5967
+ const baseToken = await client.readContract({
5968
+ address: this.comet,
5969
+ abi: COMET_ABI,
5970
+ functionName: "baseToken"
5971
+ }).catch((e) => {
5972
+ throw DefiError.rpcError(`[${this.protocolName}] baseToken failed: ${e}`);
5973
+ });
5974
+ if (baseToken.toLowerCase() !== asset.toLowerCase()) {
5975
+ return {
5976
+ protocol: this.protocolName,
5977
+ asset,
5978
+ supply_apy: 0,
5979
+ borrow_variable_apy: 0,
5980
+ utilization: 0,
5981
+ total_supply: 0n,
5982
+ total_borrow: 0n
5983
+ };
5984
+ }
5930
5985
  const utilization = await client.readContract({
5931
5986
  address: this.comet,
5932
5987
  abi: COMET_ABI,