@t2000/engine 0.50.0 → 0.50.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.
package/dist/index.d.ts CHANGED
@@ -1963,7 +1963,7 @@ declare const balanceCheckTool: Tool<{
1963
1963
  pendingRewards: number;
1964
1964
  gasReserve: number;
1965
1965
  defi: number;
1966
- defiByProtocol: Partial<Record<"cetus" | "suilend" | "scallop" | "bluefin" | "aftermath" | "haedal", number>>;
1966
+ defiByProtocol: Partial<Record<"aftermath" | "bluefin" | "cetus" | "haedal" | "scallop" | "suilend" | "suins-staking" | "suistake" | "walrus", number>>;
1967
1967
  defiSource: "blockvision" | "partial" | "degraded";
1968
1968
  total: number;
1969
1969
  stables: number;
package/dist/index.js CHANGED
@@ -714,13 +714,21 @@ function parseNumberOrNull(input) {
714
714
  var DEFI_PORTFOLIO_TIMEOUT_MS = 4e3;
715
715
  var DEFI_CACHE_TTL_MS = 6e4;
716
716
  var DEFI_PROTOCOLS = [
717
+ "aftermath",
718
+ "bluefin",
717
719
  "cetus",
718
- "suilend",
720
+ "haedal",
719
721
  "scallop",
720
- "bluefin",
721
- "aftermath",
722
- "haedal"
722
+ "suilend",
723
+ "suins-staking",
724
+ "suistake",
725
+ "walrus"
723
726
  ];
727
+ var SUI_TYPE_FULL = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
728
+ var USDC_TYPE_FULL = "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC";
729
+ var BLUE_TYPE_FULL = "0xe1b45a0e641b9955a20aa0ad1c1f4ad86aad8afb07296d4085e349a50e90bdca::blue::BLUE";
730
+ var WAL_TYPE_FULL = "0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL";
731
+ var NS_TYPE_FULL = "0x5145494a5f5100e645e4b0aa950fa6b68f614e8c59e17bc5ded3495123a79178::ns::NS";
724
732
  var defiCache = /* @__PURE__ */ new Map();
725
733
  var defiInflight = /* @__PURE__ */ new Map();
726
734
  async function fetchAddressDefiPortfolio(address, apiKey, priceHints = {}) {
@@ -775,7 +783,7 @@ async function fetchAddressDefiPortfolio(address, apiKey, priceHints = {}) {
775
783
  continue;
776
784
  }
777
785
  try {
778
- const usd = NORMALIZERS[proto](s.value, prices);
786
+ const usd = normalizeProtocol(proto, s.value, prices);
779
787
  if (Number.isFinite(usd) && usd !== 0) {
780
788
  perProtocol[proto] = usd;
781
789
  totalUsd += usd;
@@ -827,6 +835,166 @@ async function fetchOneDefiProtocol(address, protocol, apiKey) {
827
835
  if (json.code !== 200 || !json.result) return null;
828
836
  return json.result;
829
837
  }
838
+ var PAIR_A_COIN_KEYS = ["coinTypeA", "coinTypeX", "tokenXType"];
839
+ var PAIR_B_COIN_KEYS = ["coinTypeB", "coinTypeY", "tokenYType"];
840
+ var PAIR_A_AMOUNT_KEYS = [
841
+ "balanceA",
842
+ "amountA",
843
+ "coinAmountA",
844
+ "coinAAmount",
845
+ "coinTypeAAmount",
846
+ "tokenXBalance",
847
+ "tokenXAmount",
848
+ "amountX",
849
+ "valueA"
850
+ ];
851
+ var PAIR_B_AMOUNT_KEYS = [
852
+ "balanceB",
853
+ "amountB",
854
+ "coinAmountB",
855
+ "coinBAmount",
856
+ "coinTypeBAmount",
857
+ "tokenYBalance",
858
+ "tokenYAmount",
859
+ "amountY",
860
+ "valueB"
861
+ ];
862
+ var PAIR_A_DECIMALS_KEYS = ["coinTypeADecimals", "tokenXDecimals", "decimalsA"];
863
+ var PAIR_B_DECIMALS_KEYS = ["coinTypeBDecimals", "tokenYDecimals", "decimalsB"];
864
+ var SINGLE_COIN_KEYS = ["coinType", "depositToken", "token"];
865
+ var SINGLE_AMOUNT_KEYS = ["amount", "balance", "value", "equity"];
866
+ var SINGLE_DECIMALS_KEYS = ["decimals", "decimal", "coinDecimals"];
867
+ var DEBT_KEYS = /* @__PURE__ */ new Set([
868
+ "borrow",
869
+ "borrows",
870
+ "debt",
871
+ "debts",
872
+ "borrowings",
873
+ "borrowedpools"
874
+ ]);
875
+ var SKIP_KEYS = /* @__PURE__ */ new Set([
876
+ "rewards",
877
+ "reward",
878
+ "fees",
879
+ "fee",
880
+ "pendingrewards",
881
+ "incentiveinfos",
882
+ "feereward",
883
+ "incentivereward"
884
+ ]);
885
+ function isCoinTypeString(v) {
886
+ if (typeof v !== "string" || !v.includes("::")) return false;
887
+ return v.startsWith("0x") || /^[0-9a-fA-F]/.test(v);
888
+ }
889
+ function ensure0xPrefix(coinType) {
890
+ return coinType.startsWith("0x") ? coinType : "0x" + coinType;
891
+ }
892
+ function isAmountValue(v) {
893
+ return typeof v === "string" && v.trim().length > 0 || typeof v === "number" && Number.isFinite(v);
894
+ }
895
+ function isFiniteNumber(v) {
896
+ return typeof v === "number" && Number.isFinite(v);
897
+ }
898
+ function pickField(obj, keys, predicate) {
899
+ for (const k of keys) {
900
+ const v = obj[k];
901
+ if (predicate(v)) return v;
902
+ }
903
+ return void 0;
904
+ }
905
+ function nestedDecimals(node) {
906
+ if (!node || typeof node !== "object") return void 0;
907
+ const obj = node;
908
+ if (typeof obj.decimals === "number") return obj.decimals;
909
+ return void 0;
910
+ }
911
+ function toHumanQuantity(raw, decimalsHint) {
912
+ if (typeof raw === "number") {
913
+ if (!Number.isFinite(raw)) return 0;
914
+ if (!Number.isInteger(raw)) return raw;
915
+ if (decimalsHint != null) return raw / 10 ** decimalsHint;
916
+ return raw;
917
+ }
918
+ const trimmed = raw.trim();
919
+ if (trimmed.length === 0) return 0;
920
+ if (trimmed.includes(".") || trimmed.includes("e") || trimmed.includes("E")) {
921
+ const n2 = Number(trimmed);
922
+ return Number.isFinite(n2) ? n2 : 0;
923
+ }
924
+ const n = Number(trimmed);
925
+ if (!Number.isFinite(n)) return 0;
926
+ const dec = decimalsHint ?? 9;
927
+ return n / 10 ** dec;
928
+ }
929
+ function priceFor(coinType, prices) {
930
+ const prefixed = ensure0xPrefix(coinType);
931
+ const norm = normalizeCoinType(prefixed);
932
+ return prices[norm] ?? prices[prefixed] ?? prices[coinType] ?? STABLE_USD_PRICES[norm] ?? 0;
933
+ }
934
+ function toUsd(coinType, raw, decimalsHint, prices) {
935
+ if (raw == null || typeof raw !== "string" && typeof raw !== "number") return 0;
936
+ if (typeof raw === "string" && raw.trim().length === 0) return 0;
937
+ const prefixed = ensure0xPrefix(coinType);
938
+ const decimals = typeof decimalsHint === "number" ? decimalsHint : getDecimalsForCoinType(prefixed);
939
+ const human = toHumanQuantity(raw, decimals);
940
+ if (!Number.isFinite(human)) return 0;
941
+ return human * priceFor(prefixed, prices);
942
+ }
943
+ function extractPair(obj) {
944
+ const coinTypeA = pickField(obj, PAIR_A_COIN_KEYS, isCoinTypeString);
945
+ const coinTypeB = pickField(obj, PAIR_B_COIN_KEYS, isCoinTypeString);
946
+ if (!coinTypeA || !coinTypeB) return null;
947
+ const amountA = pickField(obj, PAIR_A_AMOUNT_KEYS, isAmountValue);
948
+ const amountB = pickField(obj, PAIR_B_AMOUNT_KEYS, isAmountValue);
949
+ if (amountA == null || amountB == null) return null;
950
+ const decimalsA = pickField(obj, PAIR_A_DECIMALS_KEYS, isFiniteNumber) ?? nestedDecimals(obj.coinA);
951
+ const decimalsB = pickField(obj, PAIR_B_DECIMALS_KEYS, isFiniteNumber) ?? nestedDecimals(obj.coinB);
952
+ return { coinTypeA, amountA, decimalsA, coinTypeB, amountB, decimalsB };
953
+ }
954
+ function extractSingle(obj) {
955
+ const coinType = pickField(obj, SINGLE_COIN_KEYS, isCoinTypeString);
956
+ if (!coinType) return null;
957
+ const amount = pickField(obj, SINGLE_AMOUNT_KEYS, isAmountValue);
958
+ if (amount == null) return null;
959
+ const decimals = pickField(obj, SINGLE_DECIMALS_KEYS, isFiniteNumber);
960
+ const isBorrow = obj.type === "Borrow";
961
+ return { coinType, amount, decimals, isBorrow };
962
+ }
963
+ function walkProtocolResponse(result, prices) {
964
+ let total = 0;
965
+ walk(result, false);
966
+ return total;
967
+ function walk(node, debtSide) {
968
+ if (!node || typeof node !== "object") return;
969
+ if (Array.isArray(node)) {
970
+ for (const item of node) walk(item, debtSide);
971
+ return;
972
+ }
973
+ const obj = node;
974
+ if (typeof obj.totalSupplyValue === "number") total += obj.totalSupplyValue;
975
+ if (typeof obj.totalCollateralValue === "number") total += obj.totalCollateralValue;
976
+ if (typeof obj.totalLockedScaValue === "number") total += obj.totalLockedScaValue;
977
+ if (typeof obj.totalDebtValue === "number") total -= obj.totalDebtValue;
978
+ const pair = extractPair(obj);
979
+ if (pair) {
980
+ const a = toUsd(pair.coinTypeA, pair.amountA, pair.decimalsA, prices);
981
+ const b = toUsd(pair.coinTypeB, pair.amountB, pair.decimalsB, prices);
982
+ total += debtSide ? -(a + b) : a + b;
983
+ } else {
984
+ const single = extractSingle(obj);
985
+ if (single) {
986
+ const usd = toUsd(single.coinType, single.amount, single.decimals, prices);
987
+ total += debtSide || single.isBorrow ? -usd : usd;
988
+ }
989
+ }
990
+ for (const [k, v] of Object.entries(obj)) {
991
+ const lk = k.toLowerCase();
992
+ if (SKIP_KEYS.has(lk)) continue;
993
+ const childDebt = debtSide || DEBT_KEYS.has(lk);
994
+ walk(v, childDebt);
995
+ }
996
+ }
997
+ }
830
998
  function collectCoinTypes(obj, out) {
831
999
  if (!obj || typeof obj !== "object") return;
832
1000
  if (Array.isArray(obj)) {
@@ -834,139 +1002,86 @@ function collectCoinTypes(obj, out) {
834
1002
  return;
835
1003
  }
836
1004
  for (const [k, v] of Object.entries(obj)) {
837
- if (typeof v === "string" && v.startsWith("0x") && v.includes("::")) {
1005
+ if (typeof v === "string" && isCoinTypeString(v)) {
838
1006
  const lk = k.toLowerCase();
839
- if (lk.includes("cointype") || lk === "cointypea" || lk === "cointypeb" || lk === "tokenxtype" || lk === "tokenytype" || lk === "coinaddress" || lk === "phantomtype" || lk === "typename") {
840
- out.add(v);
1007
+ if (lk.includes("cointype") || lk === "tokenxtype" || lk === "tokenytype" || lk === "deposittoken" || lk === "rewardstoken" || lk === "token" || lk === "coinaddress" || lk === "phantomtype" || lk === "typename") {
1008
+ out.add(ensure0xPrefix(v));
841
1009
  }
842
1010
  } else if (typeof v === "object" && v !== null) {
843
1011
  collectCoinTypes(v, out);
844
1012
  }
845
1013
  }
846
1014
  }
847
- function priceFor(coinType, prices) {
848
- const norm = normalizeCoinType(coinType);
849
- return prices[norm] ?? prices[coinType] ?? STABLE_USD_PRICES[norm] ?? 0;
850
- }
851
- function rawToUsd(coinType, raw, decimalsHint, prices) {
852
- if (raw == null) return 0;
853
- const decimals = typeof decimalsHint === "number" ? decimalsHint : getDecimalsForCoinType(coinType);
854
- const amount = Number(raw) / 10 ** decimals;
855
- if (!Number.isFinite(amount)) return 0;
856
- return amount * priceFor(coinType, prices);
857
- }
858
- var NORMALIZERS = {
859
- cetus: normalizeCetus,
860
- suilend: normalizeSuilend,
861
- scallop: normalizeScallop,
862
- bluefin: normalizeBluefin,
863
- aftermath: normalizeAftermath,
864
- haedal: normalizeHaedal
865
- };
866
- function normalizeCetus(result, prices) {
867
- const data = result.cetus ?? {};
868
- let total = 0;
869
- const sumPair = (item, aField, bField) => {
870
- if (item.coinTypeA && item[aField] != null) {
871
- const dec = item.coinTypeADecimals ?? item.coinA?.decimals;
872
- total += rawToUsd(item.coinTypeA, item[aField], dec, prices);
873
- }
874
- if (item.coinTypeB && item[bField] != null) {
875
- const dec = item.coinTypeBDecimals ?? item.coinB?.decimals;
876
- total += rawToUsd(item.coinTypeB, item[bField], dec, prices);
877
- }
878
- };
879
- for (const lp of data.lps ?? []) sumPair(lp, "balanceA", "balanceB");
880
- for (const farm of data.farms ?? []) sumPair(farm, "balanceA", "balanceB");
881
- for (const vault of data.vaults ?? []) sumPair(vault, "coinAAmount", "coinBAmount");
882
- return total;
883
- }
884
- function normalizeSuilend(result, prices) {
885
- const data = result.suilend ?? {};
886
- let total = 0;
887
- for (const d of data.deposits ?? []) {
888
- if (d.coinType && d.amount != null) total += rawToUsd(d.coinType, d.amount, d.decimals, prices);
889
- }
890
- for (const b of data.borrows ?? []) {
891
- if (b.coinType && b.amount != null) total -= rawToUsd(b.coinType, b.amount, b.decimals, prices);
892
- }
893
- for (const s of data.strategies ?? []) {
894
- if (s.coinType && s.amount != null) total += rawToUsd(s.coinType, s.amount, s.decimals, prices);
895
- }
896
- return total;
897
- }
898
- function normalizeScallop(result, _prices) {
899
- const s = result.scallop;
900
- if (!s) return 0;
901
- const supply = Number(s.totalSupplyValue ?? 0);
902
- const collateral = Number(s.totalCollateralValue ?? 0);
903
- const locked = Number(s.totalLockedScaValue ?? 0);
904
- const debt = Number(s.totalDebtValue ?? 0);
905
- const net = (Number.isFinite(supply) ? supply : 0) + (Number.isFinite(collateral) ? collateral : 0) + (Number.isFinite(locked) ? locked : 0) - (Number.isFinite(debt) ? debt : 0);
906
- return net;
907
- }
908
1015
  function normalizeBluefin(result, prices) {
909
1016
  const data = result.bluefin ?? {};
910
1017
  let total = 0;
911
1018
  for (const lp of data.lps ?? []) {
912
1019
  if (lp.coinTypeA && lp.coinAmountA != null) {
913
- total += rawToUsd(lp.coinTypeA, lp.coinAmountA, void 0, prices);
1020
+ total += toUsd(lp.coinTypeA, lp.coinAmountA, void 0, prices);
914
1021
  }
915
1022
  if (lp.coinTypeB && lp.coinAmountB != null) {
916
- total += rawToUsd(lp.coinTypeB, lp.coinAmountB, void 0, prices);
1023
+ total += toUsd(lp.coinTypeB, lp.coinAmountB, void 0, prices);
917
1024
  }
918
1025
  }
919
1026
  if (data.usdcVault?.amount != null) {
920
- total += rawToUsd(
921
- "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC",
922
- data.usdcVault.amount,
923
- 6,
924
- prices
925
- );
1027
+ total += toUsd(USDC_TYPE_FULL, data.usdcVault.amount, 6, prices);
926
1028
  }
927
1029
  if (data.blueVault?.amount != null) {
928
- total += rawToUsd(
929
- "0xe1b45a0e641b9955a20aa0ad1c1f4ad86aad8afb07296d4085e349a50e90bdca::blue::BLUE",
930
- data.blueVault.amount,
931
- 9,
932
- prices
933
- );
934
- }
935
- return total;
936
- }
937
- function normalizeAftermath(result, prices) {
938
- const data = result.aftermath ?? {};
939
- let total = 0;
940
- const positions = [...data.lpPositions ?? [], ...data.farmPositions ?? []];
941
- for (const pos of positions) {
942
- for (const c of pos.coins ?? []) {
943
- if (c.coinType && c.amount != null) {
944
- total += rawToUsd(c.coinType, c.amount, void 0, prices);
945
- }
946
- }
1030
+ total += toUsd(BLUE_TYPE_FULL, data.blueVault.amount, 9, prices);
947
1031
  }
948
1032
  return total;
949
1033
  }
950
1034
  function normalizeHaedal(result, prices) {
951
- const SUI_TYPE_FULL = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
952
1035
  const data = result.haedal ?? {};
953
1036
  let total = 0;
954
1037
  for (const lp of data.lps ?? []) {
955
- const item = lp;
956
- if (item.coinTypeA && item.balanceA != null) {
957
- total += rawToUsd(item.coinTypeA, item.balanceA, void 0, prices);
1038
+ if (lp.coinTypeA && lp.balanceA != null) {
1039
+ total += toUsd(lp.coinTypeA, lp.balanceA, void 0, prices);
958
1040
  }
959
- if (item.coinTypeB && item.balanceB != null) {
960
- total += rawToUsd(item.coinTypeB, item.balanceB, void 0, prices);
1041
+ if (lp.coinTypeB && lp.balanceB != null) {
1042
+ total += toUsd(lp.coinTypeB, lp.balanceB, void 0, prices);
961
1043
  }
962
1044
  }
963
1045
  for (const stake of data.stakings ?? []) {
964
1046
  if (stake.sui_amount != null) {
965
- total += rawToUsd(SUI_TYPE_FULL, stake.sui_amount, 9, prices);
1047
+ total += toUsd(SUI_TYPE_FULL, stake.sui_amount, 9, prices);
966
1048
  }
967
1049
  }
968
1050
  return total;
969
1051
  }
1052
+ function sumBareStakings(data, impliedCoinType, decimals, prices) {
1053
+ if (!data) return 0;
1054
+ let total = 0;
1055
+ for (const s of data.stakings ?? []) {
1056
+ const amt = s.sui_amount ?? s.amount;
1057
+ if (amt != null) total += toUsd(impliedCoinType, amt, decimals, prices);
1058
+ }
1059
+ return total;
1060
+ }
1061
+ function normalizeSuistake(result, prices) {
1062
+ const data = result.suistake;
1063
+ return sumBareStakings(data, SUI_TYPE_FULL, 9, prices);
1064
+ }
1065
+ function normalizeWalrus(result, prices) {
1066
+ const data = result.walrus;
1067
+ return sumBareStakings(data, WAL_TYPE_FULL, 9, prices);
1068
+ }
1069
+ function normalizeSuinsStaking(result, prices) {
1070
+ const data = result["suins-staking"] ?? result.suinsStaking ?? result.suins_staking;
1071
+ return sumBareStakings(data, NS_TYPE_FULL, 6, prices);
1072
+ }
1073
+ var BESPOKE_NORMALIZERS = {
1074
+ bluefin: normalizeBluefin,
1075
+ haedal: normalizeHaedal,
1076
+ suistake: normalizeSuistake,
1077
+ walrus: normalizeWalrus,
1078
+ "suins-staking": normalizeSuinsStaking
1079
+ };
1080
+ function normalizeProtocol(protocol, result, prices) {
1081
+ const bespoke = BESPOKE_NORMALIZERS[protocol];
1082
+ if (bespoke) return bespoke(result, prices);
1083
+ return walkProtocolResponse(result, prices);
1084
+ }
970
1085
  function clearPortfolioCache() {
971
1086
  portfolioCache.clear();
972
1087
  portfolioInflight.clear();