@liquidium/client 0.3.4 → 0.4.1
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/README.md +32 -6
- package/dist/index.cjs +1171 -1257
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +107 -344
- package/dist/index.d.ts +107 -344
- package/dist/index.js +1168 -1251
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,11 +30,7 @@ var SupplyAction = {
|
|
|
30
30
|
var OutflowType = {
|
|
31
31
|
borrow: "borrow",
|
|
32
32
|
feeClaim: "feeClaim",
|
|
33
|
-
|
|
34
|
-
};
|
|
35
|
-
var InflowSubmitType = {
|
|
36
|
-
DEPOSIT: "DEPOSIT",
|
|
37
|
-
REPAY: "REPAY"
|
|
33
|
+
withdrawal: "withdrawal"
|
|
38
34
|
};
|
|
39
35
|
|
|
40
36
|
// src/core/config.ts
|
|
@@ -986,13 +982,10 @@ function getVariantKey(variant) {
|
|
|
986
982
|
|
|
987
983
|
// src/core/wallet-actions.ts
|
|
988
984
|
var TransferMode = {
|
|
989
|
-
ck: "ck",
|
|
990
985
|
native: "native"
|
|
991
986
|
};
|
|
992
987
|
var WalletExecutionKind = {
|
|
993
|
-
|
|
994
|
-
signMessage: "sign-message",
|
|
995
|
-
signPsbt: "sign-psbt"
|
|
988
|
+
signMessage: "sign-message"
|
|
996
989
|
};
|
|
997
990
|
var WalletActionKind = {
|
|
998
991
|
createAccount: "create-account",
|
|
@@ -1030,38 +1023,6 @@ function executeWith(options) {
|
|
|
1030
1023
|
account: options.account ?? action.account
|
|
1031
1024
|
});
|
|
1032
1025
|
}
|
|
1033
|
-
case WalletExecutionKind.signPsbt: {
|
|
1034
|
-
if (!options.walletAdapter.signPsbt) {
|
|
1035
|
-
throw new LiquidiumError(
|
|
1036
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
1037
|
-
"Wallet adapter does not support PSBT signing"
|
|
1038
|
-
);
|
|
1039
|
-
}
|
|
1040
|
-
const signedPsbtBase64 = await options.walletAdapter.signPsbt({
|
|
1041
|
-
chain: Chain.BTC,
|
|
1042
|
-
psbtBase64: action.psbtBase64,
|
|
1043
|
-
account: options.account ?? action.account,
|
|
1044
|
-
actionType: action.actionType,
|
|
1045
|
-
transferMode: action.transferMode
|
|
1046
|
-
});
|
|
1047
|
-
return action.submit({ signedPsbtBase64 });
|
|
1048
|
-
}
|
|
1049
|
-
case WalletExecutionKind.sendEthTransaction: {
|
|
1050
|
-
if (!options.walletAdapter.sendEthTransaction) {
|
|
1051
|
-
throw new LiquidiumError(
|
|
1052
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
1053
|
-
"Wallet adapter does not support ETH transaction sending"
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
const txHash = await options.walletAdapter.sendEthTransaction({
|
|
1057
|
-
chain: Chain.ETH,
|
|
1058
|
-
transaction: action.transaction,
|
|
1059
|
-
account: options.account ?? action.account,
|
|
1060
|
-
actionType: action.actionType,
|
|
1061
|
-
transferMode: action.transferMode
|
|
1062
|
-
});
|
|
1063
|
-
return action.submit({ txHash });
|
|
1064
|
-
}
|
|
1065
1026
|
default:
|
|
1066
1027
|
throw new LiquidiumError(
|
|
1067
1028
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
@@ -1368,8 +1329,8 @@ function mapCanisterWalletToWallet(canisterWallet) {
|
|
|
1368
1329
|
);
|
|
1369
1330
|
}
|
|
1370
1331
|
}
|
|
1371
|
-
var KNOWN_ASSET_TAGS = ["BTC", "
|
|
1372
|
-
var KNOWN_CHAIN_TAGS = ["BTC", "ETH"
|
|
1332
|
+
var KNOWN_ASSET_TAGS = ["BTC", "USDC", "USDT"];
|
|
1333
|
+
var KNOWN_CHAIN_TAGS = ["BTC", "ETH"];
|
|
1373
1334
|
function extractVariantTag(variant, knownTags) {
|
|
1374
1335
|
const [key] = Object.keys(variant);
|
|
1375
1336
|
if (!key) {
|
|
@@ -1682,49 +1643,24 @@ function decodeLoanCreatedEvent(payload) {
|
|
|
1682
1643
|
}
|
|
1683
1644
|
|
|
1684
1645
|
// src/core/sdk-api-paths.ts
|
|
1685
|
-
var
|
|
1686
|
-
|
|
1687
|
-
history: "v1",
|
|
1688
|
-
inflow: "v1",
|
|
1689
|
-
instantLoans: "v1"
|
|
1690
|
-
};
|
|
1646
|
+
var SDK_API_V1_PATH = "/v1";
|
|
1647
|
+
var SDK_API_V2_PATH = "/v2";
|
|
1691
1648
|
var SdkApiQueryParam = {
|
|
1692
1649
|
cursor: "cursor",
|
|
1693
1650
|
from: "from",
|
|
1651
|
+
filter: "filter",
|
|
1694
1652
|
limit: "limit",
|
|
1695
1653
|
market: "market",
|
|
1654
|
+
operations: "operations",
|
|
1696
1655
|
poolId: "poolId",
|
|
1697
1656
|
profileId: "profileId",
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
to: "to",
|
|
1701
|
-
types: "types"
|
|
1657
|
+
states: "states",
|
|
1658
|
+
to: "to"
|
|
1702
1659
|
};
|
|
1703
|
-
var ACTIVITIES =
|
|
1704
|
-
var
|
|
1705
|
-
var
|
|
1706
|
-
var
|
|
1707
|
-
var HISTORY_USERS = `/${SDK_API_VERSION.history}/history/users`;
|
|
1708
|
-
var INFLOW = `/${SDK_API_VERSION.inflow}/inflow`;
|
|
1709
|
-
var INSTANT_LOANS = `/${SDK_API_VERSION.instantLoans}/instant-loans`;
|
|
1710
|
-
function buildHistoryPoolPath(poolId, query) {
|
|
1711
|
-
const base = `${HISTORY_POOL}/${encodeURIComponent(poolId)}`;
|
|
1712
|
-
const qs = query.toString();
|
|
1713
|
-
return qs ? `${base}?${qs}` : base;
|
|
1714
|
-
}
|
|
1715
|
-
function buildHistoryPoolConfigPath(poolId, cursor) {
|
|
1716
|
-
const base = `${HISTORY_POOL_CONFIG}/${encodeURIComponent(poolId)}`;
|
|
1717
|
-
if (!cursor) {
|
|
1718
|
-
return base;
|
|
1719
|
-
}
|
|
1720
|
-
const query = new URLSearchParams({ [SdkApiQueryParam.cursor]: cursor });
|
|
1721
|
-
return `${base}?${query.toString()}`;
|
|
1722
|
-
}
|
|
1723
|
-
function buildHistoryRatesPath(poolId, query) {
|
|
1724
|
-
const base = `${HISTORY_RATES}/${encodeURIComponent(poolId)}`;
|
|
1725
|
-
const qs = query.toString();
|
|
1726
|
-
return qs ? `${base}?${qs}` : base;
|
|
1727
|
-
}
|
|
1660
|
+
var ACTIVITIES = `${SDK_API_V2_PATH}/activities`;
|
|
1661
|
+
var HISTORY_USERS = `${SDK_API_V2_PATH}/history/users`;
|
|
1662
|
+
var INFLOW = `${SDK_API_V2_PATH}/inflow`;
|
|
1663
|
+
var INSTANT_LOANS = `${SDK_API_V1_PATH}/instant-loans`;
|
|
1728
1664
|
function buildHistoryUserTransactionsPath(user, query) {
|
|
1729
1665
|
const base = `${HISTORY_USERS}/${encodeURIComponent(user)}/transactions`;
|
|
1730
1666
|
const qs = query.toString();
|
|
@@ -1739,8 +1675,8 @@ function buildActivitiesPath(request) {
|
|
|
1739
1675
|
const query = new URLSearchParams({
|
|
1740
1676
|
[SdkApiQueryParam.profileId]: request.profileId
|
|
1741
1677
|
});
|
|
1742
|
-
if (request.
|
|
1743
|
-
query.set(SdkApiQueryParam.
|
|
1678
|
+
if (request.filter) {
|
|
1679
|
+
query.set(SdkApiQueryParam.filter, request.filter);
|
|
1744
1680
|
}
|
|
1745
1681
|
return `${ACTIVITIES}?${query.toString()}`;
|
|
1746
1682
|
}
|
|
@@ -1798,12 +1734,6 @@ function parseBigInt(value, label) {
|
|
|
1798
1734
|
);
|
|
1799
1735
|
}
|
|
1800
1736
|
}
|
|
1801
|
-
function parseOptionalBigInt(value, label) {
|
|
1802
|
-
if (value === void 0) {
|
|
1803
|
-
return void 0;
|
|
1804
|
-
}
|
|
1805
|
-
return parseBigInt(value, label);
|
|
1806
|
-
}
|
|
1807
1737
|
|
|
1808
1738
|
// src/modules/instant-loans/ref-code.ts
|
|
1809
1739
|
var REF_LENGTH = 6;
|
|
@@ -1874,28 +1804,8 @@ var ActivityFilter = {
|
|
|
1874
1804
|
completed: "completed",
|
|
1875
1805
|
all: "all"
|
|
1876
1806
|
};
|
|
1877
|
-
var ActivityDirection = {
|
|
1878
|
-
inflow: "inflow",
|
|
1879
|
-
outflow: "outflow"
|
|
1880
|
-
};
|
|
1881
|
-
var ActivityKind = {
|
|
1882
|
-
deposit: "deposit",
|
|
1883
|
-
repayment: "repayment",
|
|
1884
|
-
borrow: "borrow",
|
|
1885
|
-
withdraw: "withdraw"
|
|
1886
|
-
};
|
|
1887
|
-
var ActivityStatus = {
|
|
1888
|
-
requested: "requested",
|
|
1889
|
-
pending: "pending",
|
|
1890
|
-
detected: "detected",
|
|
1891
|
-
processing: "processing",
|
|
1892
|
-
sent: "sent",
|
|
1893
|
-
confirmed: "confirmed",
|
|
1894
|
-
failed: "failed"
|
|
1895
|
-
};
|
|
1896
1807
|
|
|
1897
1808
|
// src/modules/activities/activities.ts
|
|
1898
|
-
var PRE_TERMINAL_ETH_ACTIVITY_ID_PREFIX = "pre_terminal_eth_";
|
|
1899
1809
|
var ActivitiesModule = class {
|
|
1900
1810
|
constructor(apiClient, canisterContext) {
|
|
1901
1811
|
this.apiClient = apiClient;
|
|
@@ -1904,11 +1814,11 @@ var ActivitiesModule = class {
|
|
|
1904
1814
|
apiClient;
|
|
1905
1815
|
canisterContext;
|
|
1906
1816
|
/**
|
|
1907
|
-
* Lists profile activities. Defaults to
|
|
1817
|
+
* Lists profile activities. Defaults to active activities.
|
|
1908
1818
|
*
|
|
1909
1819
|
* Uses the Liquidium SDK API.
|
|
1910
1820
|
*
|
|
1911
|
-
* @param request - Profile id or instant-loan short reference plus optional
|
|
1821
|
+
* @param request - Profile id or instant-loan short reference plus optional lifecycle filter.
|
|
1912
1822
|
* @returns Activities owned by the resolved profile.
|
|
1913
1823
|
*/
|
|
1914
1824
|
async list(request) {
|
|
@@ -1917,7 +1827,7 @@ var ActivitiesModule = class {
|
|
|
1917
1827
|
const response = await apiClient.get(
|
|
1918
1828
|
buildActivitiesPath({
|
|
1919
1829
|
profileId,
|
|
1920
|
-
|
|
1830
|
+
filter: request.filter ?? ActivityFilter.active
|
|
1921
1831
|
})
|
|
1922
1832
|
);
|
|
1923
1833
|
return response.activities.map(mapActivity);
|
|
@@ -1998,76 +1908,48 @@ function mapInstantLoanLookupError(error) {
|
|
|
1998
1908
|
return new LiquidiumError(LiquidiumErrorCode.INTERNAL, key);
|
|
1999
1909
|
}
|
|
2000
1910
|
function mapActivity(wire) {
|
|
2001
|
-
const
|
|
2002
|
-
const
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
status: mapInflowActivityStatus(
|
|
2010
|
-
mapActivityStatus(status, effectiveStage)
|
|
2011
|
-
),
|
|
2012
|
-
...topUp ? { topUp } : {},
|
|
2013
|
-
amount: parseBigInt(amount, "activity amount")
|
|
2014
|
-
};
|
|
2015
|
-
}
|
|
2016
|
-
return {
|
|
2017
|
-
...activity,
|
|
2018
|
-
direction: ActivityDirection.outflow,
|
|
2019
|
-
kind: mapOutflowActivityKind(activity.kind),
|
|
2020
|
-
status: mapOutflowActivityStatus(mapActivityStatus(status, effectiveStage)),
|
|
2021
|
-
amount: parseBigInt(amount, "activity amount")
|
|
1911
|
+
const amount = parseBigInt(wire.amount, "activity amount");
|
|
1912
|
+
const activityBase = {
|
|
1913
|
+
id: wire.id,
|
|
1914
|
+
poolId: wire.poolId,
|
|
1915
|
+
asset: wire.asset,
|
|
1916
|
+
chain: wire.chain,
|
|
1917
|
+
amount,
|
|
1918
|
+
timestampMs: wire.timestampMs
|
|
2022
1919
|
};
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
return kind;
|
|
1920
|
+
if (isInflowOperation(wire.status.operation)) {
|
|
1921
|
+
const activity = {
|
|
1922
|
+
...activityBase,
|
|
1923
|
+
status: wire.status
|
|
1924
|
+
};
|
|
1925
|
+
if (wire.txids) {
|
|
1926
|
+
activity.txids = wire.txids;
|
|
1927
|
+
}
|
|
1928
|
+
if (wire.topUp) {
|
|
1929
|
+
activity.topUp = mapActivityTopUp(wire.topUp);
|
|
1930
|
+
}
|
|
1931
|
+
return activity;
|
|
2036
1932
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
}
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
1933
|
+
if (isOutflowOperation(wire.status.operation)) {
|
|
1934
|
+
const activity = {
|
|
1935
|
+
...activityBase,
|
|
1936
|
+
status: wire.status
|
|
1937
|
+
};
|
|
1938
|
+
if (wire.txids) {
|
|
1939
|
+
activity.txids = wire.txids;
|
|
1940
|
+
}
|
|
1941
|
+
return activity;
|
|
2045
1942
|
}
|
|
2046
1943
|
throw new LiquidiumError(
|
|
2047
1944
|
LiquidiumErrorCode.INTERNAL,
|
|
2048
|
-
`Invalid
|
|
1945
|
+
`Invalid activity operation: ${wire.status.operation}`
|
|
2049
1946
|
);
|
|
2050
1947
|
}
|
|
2051
|
-
function
|
|
2052
|
-
|
|
2053
|
-
return status;
|
|
2054
|
-
}
|
|
2055
|
-
throw new LiquidiumError(
|
|
2056
|
-
LiquidiumErrorCode.INTERNAL,
|
|
2057
|
-
`Invalid outflow activity status: ${status}`
|
|
2058
|
-
);
|
|
1948
|
+
function isInflowOperation(operation) {
|
|
1949
|
+
return operation === "deposit" || operation === "repayment";
|
|
2059
1950
|
}
|
|
2060
|
-
function
|
|
2061
|
-
|
|
2062
|
-
return status;
|
|
2063
|
-
}
|
|
2064
|
-
if (stage === "deposited") {
|
|
2065
|
-
return "detected";
|
|
2066
|
-
}
|
|
2067
|
-
if (stage === "confirmed" || stage === "finalising" || stage === "pending") {
|
|
2068
|
-
return "processing";
|
|
2069
|
-
}
|
|
2070
|
-
return "pending";
|
|
1951
|
+
function isOutflowOperation(operation) {
|
|
1952
|
+
return operation === "borrow" || operation === "withdrawal";
|
|
2071
1953
|
}
|
|
2072
1954
|
function mapActivityTopUp(wire) {
|
|
2073
1955
|
return {
|
|
@@ -2083,24 +1965,6 @@ function mapActivityTopUp(wire) {
|
|
|
2083
1965
|
)
|
|
2084
1966
|
};
|
|
2085
1967
|
}
|
|
2086
|
-
function deriveActivityStage(wire) {
|
|
2087
|
-
if (wire.id.startsWith(PRE_TERMINAL_ETH_ACTIVITY_ID_PREFIX) && wire.direction === ActivityDirection.inflow && wire.chain === Chain.ETH) {
|
|
2088
|
-
return "deposited";
|
|
2089
|
-
}
|
|
2090
|
-
return void 0;
|
|
2091
|
-
}
|
|
2092
|
-
|
|
2093
|
-
// src/core/rates.ts
|
|
2094
|
-
var RATE_SCALE = 1000000000000000000000000000n;
|
|
2095
|
-
var RATE_DECIMALS = BigInt(RATE_SCALE.toString().length - 1);
|
|
2096
|
-
|
|
2097
|
-
// src/modules/history/types.ts
|
|
2098
|
-
var UserHistoryStatus = {
|
|
2099
|
-
requested: "requested",
|
|
2100
|
-
pending: "pending",
|
|
2101
|
-
confirmed: "confirmed",
|
|
2102
|
-
failed: "failed"
|
|
2103
|
-
};
|
|
2104
1968
|
|
|
2105
1969
|
// src/modules/history/history.ts
|
|
2106
1970
|
var HistoryModule = class {
|
|
@@ -2118,154 +1982,41 @@ var HistoryModule = class {
|
|
|
2118
1982
|
return this.apiClient;
|
|
2119
1983
|
}
|
|
2120
1984
|
/**
|
|
2121
|
-
* Returns
|
|
2122
|
-
*
|
|
2123
|
-
* @param poolId - The pool principal text.
|
|
2124
|
-
* @param window - Optional time window with from/to timestamps and limit.
|
|
2125
|
-
* @returns A page of pool rate history entries and the next cursor when more results are available.
|
|
2126
|
-
*/
|
|
2127
|
-
async getPoolHistory(poolId, window = {}) {
|
|
2128
|
-
const apiClient = this.requireApi();
|
|
2129
|
-
const query = createHistoryWindowQuery(window);
|
|
2130
|
-
const requestPath = buildHistoryPoolPath(poolId, query);
|
|
2131
|
-
const response = await apiClient.get(requestPath);
|
|
2132
|
-
return {
|
|
2133
|
-
items: response.items.map((item) => ({
|
|
2134
|
-
date: item.date,
|
|
2135
|
-
rateDecimals: RATE_DECIMALS,
|
|
2136
|
-
avgBorrowRate: parseBigInt(item.avgBorrowRate, "pool borrow rate"),
|
|
2137
|
-
avgLendRate: parseBigInt(item.avgLendRate, "pool lend rate"),
|
|
2138
|
-
avgUtilizationRate: parseBigInt(
|
|
2139
|
-
item.avgUtilizationRate,
|
|
2140
|
-
"pool utilization rate"
|
|
2141
|
-
)
|
|
2142
|
-
})),
|
|
2143
|
-
nextCursor: response.nextCursor
|
|
2144
|
-
};
|
|
2145
|
-
}
|
|
2146
|
-
/**
|
|
2147
|
-
* Returns paginated configuration change history for a pool.
|
|
2148
|
-
*
|
|
2149
|
-
* @param poolId - The pool principal text.
|
|
2150
|
-
* @param cursor - An optional pagination cursor from a previous response.
|
|
2151
|
-
* @returns A page of pool configuration changes and the next cursor when more results are available.
|
|
2152
|
-
*/
|
|
2153
|
-
async getPoolConfigHistory(poolId, cursor) {
|
|
2154
|
-
const apiClient = this.requireApi();
|
|
2155
|
-
const requestPath = buildHistoryPoolConfigPath(poolId, cursor);
|
|
2156
|
-
const response = await apiClient.get(requestPath);
|
|
2157
|
-
return {
|
|
2158
|
-
items: response.items.map((item) => ({
|
|
2159
|
-
type: item.type,
|
|
2160
|
-
poolId: item.poolId,
|
|
2161
|
-
asset: item.asset,
|
|
2162
|
-
chain: item.chain,
|
|
2163
|
-
timestamp: item.timestamp,
|
|
2164
|
-
totalSupply: parseBigInt(item.totalSupply, "pool history totalSupply"),
|
|
2165
|
-
totalDebt: parseBigInt(item.totalDebt, "pool history totalDebt"),
|
|
2166
|
-
supplyCap: parseOptionalBigInt(
|
|
2167
|
-
item.supplyCap,
|
|
2168
|
-
"pool history supplyCap"
|
|
2169
|
-
),
|
|
2170
|
-
borrowCap: parseOptionalBigInt(
|
|
2171
|
-
item.borrowCap,
|
|
2172
|
-
"pool history borrowCap"
|
|
2173
|
-
),
|
|
2174
|
-
maxLtv: parseBigInt(item.maxLtv, "pool history maxLtv"),
|
|
2175
|
-
liquidationThreshold: parseBigInt(
|
|
2176
|
-
item.liquidationThreshold,
|
|
2177
|
-
"pool history liquidationThreshold"
|
|
2178
|
-
),
|
|
2179
|
-
liquidationBonus: parseBigInt(
|
|
2180
|
-
item.liquidationBonus,
|
|
2181
|
-
"pool history liquidationBonus"
|
|
2182
|
-
),
|
|
2183
|
-
protocolLiquidationFee: parseBigInt(
|
|
2184
|
-
item.protocolLiquidationFee,
|
|
2185
|
-
"pool history protocolLiquidationFee"
|
|
2186
|
-
),
|
|
2187
|
-
reserveFactor: parseBigInt(
|
|
2188
|
-
item.reserveFactor,
|
|
2189
|
-
"pool history reserveFactor"
|
|
2190
|
-
),
|
|
2191
|
-
baseRate: parseBigInt(item.baseRate, "pool history baseRate"),
|
|
2192
|
-
optimalUtilizationRate: parseBigInt(
|
|
2193
|
-
item.optimalUtilizationRate,
|
|
2194
|
-
"pool history optimalUtilizationRate"
|
|
2195
|
-
),
|
|
2196
|
-
rateSlopeBefore: parseBigInt(
|
|
2197
|
-
item.rateSlopeBefore,
|
|
2198
|
-
"pool history rateSlopeBefore"
|
|
2199
|
-
),
|
|
2200
|
-
rateSlopeAfter: parseBigInt(
|
|
2201
|
-
item.rateSlopeAfter,
|
|
2202
|
-
"pool history rateSlopeAfter"
|
|
2203
|
-
),
|
|
2204
|
-
lendingIndex: parseBigInt(
|
|
2205
|
-
item.lendingIndex,
|
|
2206
|
-
"pool history lendingIndex"
|
|
2207
|
-
),
|
|
2208
|
-
borrowIndex: parseBigInt(item.borrowIndex, "pool history borrowIndex"),
|
|
2209
|
-
sameAssetBorrowing: item.sameAssetBorrowing,
|
|
2210
|
-
frozen: item.frozen
|
|
2211
|
-
})),
|
|
2212
|
-
nextCursor: response.nextCursor
|
|
2213
|
-
};
|
|
2214
|
-
}
|
|
2215
|
-
/**
|
|
2216
|
-
* Returns borrow rate history for a pool.
|
|
1985
|
+
* Returns transaction history for a user.
|
|
2217
1986
|
*
|
|
2218
|
-
* @param
|
|
2219
|
-
* @param
|
|
2220
|
-
* @returns Paginated
|
|
1987
|
+
* @param user - The Liquidium profile principal text.
|
|
1988
|
+
* @param filters - Optional pool, operation, state, time range, and pagination filters.
|
|
1989
|
+
* @returns Paginated user history entries.
|
|
2221
1990
|
*/
|
|
2222
|
-
async
|
|
2223
|
-
const apiClient = this.requireApi();
|
|
2224
|
-
const query = createHistoryWindowQuery(window);
|
|
2225
|
-
const requestPath = buildHistoryRatesPath(poolId, query);
|
|
2226
|
-
const response = await apiClient.get(requestPath);
|
|
2227
|
-
return {
|
|
2228
|
-
items: response.items.map((item) => ({
|
|
2229
|
-
date: item.date,
|
|
2230
|
-
rateDecimals: RATE_DECIMALS,
|
|
2231
|
-
avgRate: parseBigInt(item.avgRate, "borrow rate")
|
|
2232
|
-
})),
|
|
2233
|
-
nextCursor: response.nextCursor
|
|
2234
|
-
};
|
|
2235
|
-
}
|
|
2236
|
-
async getUserTransactionHistory(user, marketOrFilters, filters = {}) {
|
|
1991
|
+
async getUserTransactionHistory(user, filters = {}) {
|
|
2237
1992
|
const apiClient = this.requireApi();
|
|
2238
|
-
const normalizedFilters = normalizeTransactionHistoryFilters(
|
|
2239
|
-
marketOrFilters,
|
|
2240
|
-
filters
|
|
2241
|
-
);
|
|
2242
1993
|
const query = new URLSearchParams();
|
|
2243
|
-
if (
|
|
2244
|
-
query.set(SdkApiQueryParam.cursor,
|
|
1994
|
+
if (filters.cursor) {
|
|
1995
|
+
query.set(SdkApiQueryParam.cursor, filters.cursor);
|
|
2245
1996
|
}
|
|
2246
|
-
if (
|
|
2247
|
-
query.set(SdkApiQueryParam.market,
|
|
1997
|
+
if (filters.market) {
|
|
1998
|
+
query.set(SdkApiQueryParam.market, filters.market);
|
|
2248
1999
|
}
|
|
2249
|
-
if (
|
|
2250
|
-
query.set(SdkApiQueryParam.poolId,
|
|
2000
|
+
if (filters.poolId) {
|
|
2001
|
+
query.set(SdkApiQueryParam.poolId, filters.poolId);
|
|
2251
2002
|
}
|
|
2252
|
-
if (
|
|
2253
|
-
query.set(SdkApiQueryParam.
|
|
2003
|
+
if (filters.operations?.length) {
|
|
2004
|
+
query.set(SdkApiQueryParam.operations, filters.operations.join(","));
|
|
2254
2005
|
}
|
|
2255
|
-
if (
|
|
2006
|
+
if (filters.states?.length) {
|
|
2256
2007
|
query.set(
|
|
2257
|
-
SdkApiQueryParam.
|
|
2258
|
-
|
|
2008
|
+
SdkApiQueryParam.states,
|
|
2009
|
+
createHistoryStateFilterParam(filters.states)
|
|
2259
2010
|
);
|
|
2260
2011
|
}
|
|
2261
|
-
if (
|
|
2262
|
-
query.set(SdkApiQueryParam.from,
|
|
2012
|
+
if (filters.from) {
|
|
2013
|
+
query.set(SdkApiQueryParam.from, filters.from);
|
|
2263
2014
|
}
|
|
2264
|
-
if (
|
|
2265
|
-
query.set(SdkApiQueryParam.to,
|
|
2015
|
+
if (filters.to) {
|
|
2016
|
+
query.set(SdkApiQueryParam.to, filters.to);
|
|
2266
2017
|
}
|
|
2267
|
-
if (
|
|
2268
|
-
query.set(SdkApiQueryParam.limit, String(
|
|
2018
|
+
if (filters.limit !== void 0) {
|
|
2019
|
+
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2269
2020
|
}
|
|
2270
2021
|
const requestPath = buildHistoryUserTransactionsPath(user, query);
|
|
2271
2022
|
const response = await apiClient.get(requestPath);
|
|
@@ -2274,30 +2025,33 @@ var HistoryModule = class {
|
|
|
2274
2025
|
nextCursor: response.nextCursor
|
|
2275
2026
|
};
|
|
2276
2027
|
}
|
|
2277
|
-
|
|
2028
|
+
/**
|
|
2029
|
+
* Returns liquidation history for a user.
|
|
2030
|
+
*
|
|
2031
|
+
* @param user - The Liquidium profile principal text.
|
|
2032
|
+
* @param filters - Optional pool, time range, and pagination filters.
|
|
2033
|
+
* @returns Paginated liquidation history entries.
|
|
2034
|
+
*/
|
|
2035
|
+
async getLiquidationHistory(user, filters = {}) {
|
|
2278
2036
|
const apiClient = this.requireApi();
|
|
2279
|
-
const normalizedFilters = normalizeLiquidationHistoryFilters(
|
|
2280
|
-
marketOrFilters,
|
|
2281
|
-
filters
|
|
2282
|
-
);
|
|
2283
2037
|
const query = new URLSearchParams();
|
|
2284
|
-
if (
|
|
2285
|
-
query.set(SdkApiQueryParam.cursor,
|
|
2038
|
+
if (filters.cursor) {
|
|
2039
|
+
query.set(SdkApiQueryParam.cursor, filters.cursor);
|
|
2286
2040
|
}
|
|
2287
|
-
if (
|
|
2288
|
-
query.set(SdkApiQueryParam.market,
|
|
2041
|
+
if (filters.market) {
|
|
2042
|
+
query.set(SdkApiQueryParam.market, filters.market);
|
|
2289
2043
|
}
|
|
2290
|
-
if (
|
|
2291
|
-
query.set(SdkApiQueryParam.poolId,
|
|
2044
|
+
if (filters.poolId) {
|
|
2045
|
+
query.set(SdkApiQueryParam.poolId, filters.poolId);
|
|
2292
2046
|
}
|
|
2293
|
-
if (
|
|
2294
|
-
query.set(SdkApiQueryParam.from,
|
|
2047
|
+
if (filters.from) {
|
|
2048
|
+
query.set(SdkApiQueryParam.from, filters.from);
|
|
2295
2049
|
}
|
|
2296
|
-
if (
|
|
2297
|
-
query.set(SdkApiQueryParam.to,
|
|
2050
|
+
if (filters.to) {
|
|
2051
|
+
query.set(SdkApiQueryParam.to, filters.to);
|
|
2298
2052
|
}
|
|
2299
|
-
if (
|
|
2300
|
-
query.set(SdkApiQueryParam.limit, String(
|
|
2053
|
+
if (filters.limit !== void 0) {
|
|
2054
|
+
query.set(SdkApiQueryParam.limit, String(filters.limit));
|
|
2301
2055
|
}
|
|
2302
2056
|
const requestPath = buildHistoryUserLiquidationsPath(user, query);
|
|
2303
2057
|
const response = await apiClient.get(requestPath);
|
|
@@ -2310,77 +2064,59 @@ var HistoryModule = class {
|
|
|
2310
2064
|
function mapUserTransactionHistoryEntry(item) {
|
|
2311
2065
|
return {
|
|
2312
2066
|
id: item.id,
|
|
2313
|
-
type: mapUserTransactionHistoryType(item.type),
|
|
2314
2067
|
amount: parseBigInt(item.amount, "history user amount"),
|
|
2315
2068
|
poolId: item.poolId,
|
|
2316
2069
|
timestamp: item.timestamp,
|
|
2317
|
-
status:
|
|
2070
|
+
status: item.status,
|
|
2318
2071
|
txids: item.txids
|
|
2319
2072
|
};
|
|
2320
2073
|
}
|
|
2321
2074
|
function mapUserLiquidationHistoryEntry(item) {
|
|
2322
|
-
if (item.
|
|
2075
|
+
if (item.status.operation !== "liquidation" || item.status.state !== "completed") {
|
|
2323
2076
|
throw new LiquidiumError(
|
|
2324
2077
|
LiquidiumErrorCode.INTERNAL,
|
|
2325
|
-
`Invalid liquidation history
|
|
2078
|
+
`Invalid liquidation history status: ${item.status.state}`
|
|
2326
2079
|
);
|
|
2327
2080
|
}
|
|
2328
2081
|
return {
|
|
2329
2082
|
id: item.id,
|
|
2330
|
-
type: "liquidation",
|
|
2331
2083
|
amount: parseBigInt(item.amount, "history user amount"),
|
|
2332
2084
|
poolId: item.poolId,
|
|
2333
2085
|
timestamp: item.timestamp,
|
|
2334
|
-
status:
|
|
2086
|
+
status: item.status,
|
|
2335
2087
|
txids: item.txids
|
|
2336
2088
|
};
|
|
2337
2089
|
}
|
|
2338
|
-
function
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
}
|
|
2342
|
-
throw new LiquidiumError(
|
|
2343
|
-
LiquidiumErrorCode.INTERNAL,
|
|
2344
|
-
"Transaction history response included a liquidation entry"
|
|
2345
|
-
);
|
|
2346
|
-
}
|
|
2347
|
-
function mapLiquidationHistoryStatus(status) {
|
|
2348
|
-
const mappedStatus = mapHistoryStatusFromApi(status);
|
|
2349
|
-
if (mappedStatus === UserHistoryStatus.confirmed) {
|
|
2350
|
-
return mappedStatus;
|
|
2351
|
-
}
|
|
2352
|
-
throw new LiquidiumError(
|
|
2353
|
-
LiquidiumErrorCode.INTERNAL,
|
|
2354
|
-
`Invalid liquidation history status: ${status}`
|
|
2355
|
-
);
|
|
2356
|
-
}
|
|
2357
|
-
function createHistoryWindowQuery(window) {
|
|
2358
|
-
const query = new URLSearchParams();
|
|
2359
|
-
if (window.cursor) query.set(SdkApiQueryParam.cursor, window.cursor);
|
|
2360
|
-
if (window.from) query.set(SdkApiQueryParam.from, window.from);
|
|
2361
|
-
if (window.to) query.set(SdkApiQueryParam.to, window.to);
|
|
2362
|
-
if (window.limit !== void 0) {
|
|
2363
|
-
query.set(SdkApiQueryParam.limit, String(window.limit));
|
|
2090
|
+
function createHistoryStateFilterParam(states) {
|
|
2091
|
+
for (const state of states) {
|
|
2092
|
+
validateHistoryStateFilter(state);
|
|
2364
2093
|
}
|
|
2365
|
-
return
|
|
2094
|
+
return [...new Set(states)].join(",");
|
|
2366
2095
|
}
|
|
2367
|
-
function
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2096
|
+
function validateHistoryStateFilter(state) {
|
|
2097
|
+
switch (state) {
|
|
2098
|
+
case "action_required":
|
|
2099
|
+
case "confirming":
|
|
2100
|
+
case "processing":
|
|
2101
|
+
case "completed":
|
|
2102
|
+
case "failed":
|
|
2103
|
+
return;
|
|
2104
|
+
default:
|
|
2105
|
+
throw new LiquidiumError(
|
|
2106
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
2107
|
+
`History state filter is not supported: ${state}`
|
|
2108
|
+
);
|
|
2376
2109
|
}
|
|
2377
|
-
return { ...marketOrFilters ?? {}, ...filters };
|
|
2378
2110
|
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2111
|
+
|
|
2112
|
+
// src/core/status.ts
|
|
2113
|
+
function createLiquidiumStatus(params) {
|
|
2114
|
+
return {
|
|
2115
|
+
operation: params.operation,
|
|
2116
|
+
state: params.state,
|
|
2117
|
+
confirmations: params.confirmations ?? null,
|
|
2118
|
+
requiredConfirmations: params.requiredConfirmations ?? null
|
|
2119
|
+
};
|
|
2384
2120
|
}
|
|
2385
2121
|
|
|
2386
2122
|
// src/core/utils/api-response-parsers.ts
|
|
@@ -3486,13 +3222,12 @@ function assertSupportsIcrcAccountInflowTarget(asset) {
|
|
|
3486
3222
|
}
|
|
3487
3223
|
|
|
3488
3224
|
// src/core/borrow-minimums.ts
|
|
3225
|
+
var MINIMUM_BTC_BORROW_AMOUNT_SATS = 5100n;
|
|
3226
|
+
var MINIMUM_STABLECOIN_BORROW_AMOUNT_BASE_UNITS = 1000000n;
|
|
3489
3227
|
var MIN_BORROW_AMOUNTS_BY_ASSET = {
|
|
3490
|
-
BTC:
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
// 1 USDC
|
|
3494
|
-
USDT: 1000000n
|
|
3495
|
-
// 1 USDT
|
|
3228
|
+
[Asset.BTC]: MINIMUM_BTC_BORROW_AMOUNT_SATS,
|
|
3229
|
+
[Asset.USDC]: MINIMUM_STABLECOIN_BORROW_AMOUNT_BASE_UNITS,
|
|
3230
|
+
[Asset.USDT]: MINIMUM_STABLECOIN_BORROW_AMOUNT_BASE_UNITS
|
|
3496
3231
|
};
|
|
3497
3232
|
function getMinimumBorrowAmount(asset) {
|
|
3498
3233
|
if (!isMinimumBorrowAsset(asset)) {
|
|
@@ -3977,20 +3712,11 @@ function getChainForInstantLoanAsset(asset) {
|
|
|
3977
3712
|
return asset;
|
|
3978
3713
|
}
|
|
3979
3714
|
|
|
3980
|
-
// src/modules/instant-loans/types.ts
|
|
3981
|
-
var InstantLoanStatus = {
|
|
3982
|
-
awaitingDeposit: "awaiting_deposit",
|
|
3983
|
-
depositDetected: "deposit_detected",
|
|
3984
|
-
active: "active",
|
|
3985
|
-
settling: "settling",
|
|
3986
|
-
closed: "closed",
|
|
3987
|
-
expired: "expired"
|
|
3988
|
-
};
|
|
3989
|
-
|
|
3990
3715
|
// src/modules/instant-loans/instant-loans.ts
|
|
3991
3716
|
var REPAYMENT_BUFFER_SECONDS = 86400n;
|
|
3992
|
-
var
|
|
3717
|
+
var RATE_SCALE = 10n ** 27n;
|
|
3993
3718
|
var SECONDS_PER_YEAR = 31536000n;
|
|
3719
|
+
var MILLISECONDS_PER_SECOND3 = 1e3;
|
|
3994
3720
|
var ETH_STABLECOIN_INFLOW_FEE_FALLBACK = 1500000n;
|
|
3995
3721
|
var INSTANT_LOAN_MIN_SLIPPAGE_BUFFER_BPS = 200n;
|
|
3996
3722
|
var INSTANT_LOAN_FIND_QUERY_MAX_LENGTH = 256;
|
|
@@ -4002,14 +3728,16 @@ var INSTANT_LOAN_ASSETS = [
|
|
|
4002
3728
|
Asset.USDT
|
|
4003
3729
|
];
|
|
4004
3730
|
var InstantLoansModule = class {
|
|
4005
|
-
constructor(canisterContext, apiClient, lending, positions) {
|
|
3731
|
+
constructor(canisterContext, apiClient, activities, lending, positions) {
|
|
4006
3732
|
this.canisterContext = canisterContext;
|
|
4007
3733
|
this.apiClient = apiClient;
|
|
3734
|
+
this.activities = activities;
|
|
4008
3735
|
this.lending = lending;
|
|
4009
3736
|
this.positions = positions;
|
|
4010
3737
|
}
|
|
4011
3738
|
canisterContext;
|
|
4012
3739
|
apiClient;
|
|
3740
|
+
activities;
|
|
4013
3741
|
lending;
|
|
4014
3742
|
positions;
|
|
4015
3743
|
/**
|
|
@@ -4209,7 +3937,8 @@ var InstantLoansModule = class {
|
|
|
4209
3937
|
const response = await apiClient.get(
|
|
4210
3938
|
buildInstantLoanFindPath({ query })
|
|
4211
3939
|
);
|
|
4212
|
-
|
|
3940
|
+
const candidates = "candidates" in response ? response.candidates : response.loans;
|
|
3941
|
+
return candidates.map(mapCandidateWire);
|
|
4213
3942
|
}
|
|
4214
3943
|
async getLoanRecord(loanId) {
|
|
4215
3944
|
try {
|
|
@@ -4248,6 +3977,7 @@ var InstantLoansModule = class {
|
|
|
4248
3977
|
borrowAmount: record.borrow_amount,
|
|
4249
3978
|
borrowDestination: accountFromCanister(record.borrow_destination),
|
|
4250
3979
|
refundDestination: accountFromCanister(record.refund_destination),
|
|
3980
|
+
started: record.started,
|
|
4251
3981
|
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
4252
3982
|
expiryTimestamp: record.expires_at[0] ?? deriveDepositExpiryTimestamp({
|
|
4253
3983
|
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
@@ -4276,7 +4006,8 @@ var InstantLoansModule = class {
|
|
|
4276
4006
|
repayTarget,
|
|
4277
4007
|
collateralPosition,
|
|
4278
4008
|
borrowPosition,
|
|
4279
|
-
borrowPoolRate
|
|
4009
|
+
borrowPoolRate,
|
|
4010
|
+
activeActivities
|
|
4280
4011
|
] = await Promise.all([
|
|
4281
4012
|
resolveSupplyTarget(this.canisterContext, {
|
|
4282
4013
|
profileId,
|
|
@@ -4292,7 +4023,8 @@ var InstantLoansModule = class {
|
|
|
4292
4023
|
}),
|
|
4293
4024
|
this.positions.getPosition(profileId, collateralPoolId),
|
|
4294
4025
|
this.positions.getPosition(profileId, borrowPoolId),
|
|
4295
|
-
this.positions.market.getPoolRate(borrowPoolId)
|
|
4026
|
+
this.positions.market.getPoolRate(borrowPoolId),
|
|
4027
|
+
this.activities.list({ profileId, filter: ActivityFilter.active })
|
|
4296
4028
|
]);
|
|
4297
4029
|
const totalDebtAmount = calculateTotalDebtAmount(borrowPosition);
|
|
4298
4030
|
const interestBufferAmount = calculateInterestBufferAmount(
|
|
@@ -4309,8 +4041,12 @@ var InstantLoansModule = class {
|
|
|
4309
4041
|
const borrowedDecimals = borrowPosition?.borrowedDecimals ?? getAssetNativeDecimals(borrowAsset);
|
|
4310
4042
|
const debtInterestAmount = borrowPosition?.debtInterest ?? 0n;
|
|
4311
4043
|
const status = deriveInstantLoanStatus({
|
|
4044
|
+
started: input.started,
|
|
4045
|
+
depositDetectedTimestamp: input.depositDetectedTimestamp,
|
|
4046
|
+
expiryTimestamp: input.expiryTimestamp,
|
|
4312
4047
|
collateralAmount: currentCollateralAmount,
|
|
4313
|
-
totalDebtAmount
|
|
4048
|
+
totalDebtAmount,
|
|
4049
|
+
activeActivities
|
|
4314
4050
|
});
|
|
4315
4051
|
const initialDeposit = await this.createInitialDepositQuote({
|
|
4316
4052
|
collateralAmount,
|
|
@@ -4462,7 +4198,7 @@ function calculateInterestBufferAmount(borrowPosition, annualBorrowRate) {
|
|
|
4462
4198
|
if (totalDebtAmount <= 0n || annualBorrowRate <= 0n) {
|
|
4463
4199
|
return 0n;
|
|
4464
4200
|
}
|
|
4465
|
-
const interestBuffer = totalDebtAmount * annualBorrowRate * REPAYMENT_BUFFER_SECONDS /
|
|
4201
|
+
const interestBuffer = totalDebtAmount * annualBorrowRate * REPAYMENT_BUFFER_SECONDS / RATE_SCALE / SECONDS_PER_YEAR;
|
|
4466
4202
|
return interestBuffer > 1n ? interestBuffer : 1n;
|
|
4467
4203
|
}
|
|
4468
4204
|
function calculateTotalDebtAmount(borrowPosition) {
|
|
@@ -4472,13 +4208,75 @@ function calculateTotalDebtAmount(borrowPosition) {
|
|
|
4472
4208
|
return borrowPosition.borrowed + borrowPosition.debtInterest;
|
|
4473
4209
|
}
|
|
4474
4210
|
function deriveInstantLoanStatus(input) {
|
|
4211
|
+
const activeActivityStatus = deriveActiveInstantLoanActivityStatus(input);
|
|
4212
|
+
if (activeActivityStatus) {
|
|
4213
|
+
return activeActivityStatus;
|
|
4214
|
+
}
|
|
4475
4215
|
if (input.totalDebtAmount > 0n) {
|
|
4476
|
-
return
|
|
4216
|
+
return createLiquidiumStatus({
|
|
4217
|
+
operation: "repayment",
|
|
4218
|
+
state: "active"
|
|
4219
|
+
});
|
|
4220
|
+
}
|
|
4221
|
+
if (input.started) {
|
|
4222
|
+
return createLiquidiumStatus({
|
|
4223
|
+
operation: "repayment",
|
|
4224
|
+
state: "completed"
|
|
4225
|
+
});
|
|
4226
|
+
}
|
|
4227
|
+
if (isInstantLoanDepositExpired(input)) {
|
|
4228
|
+
return createLiquidiumStatus({
|
|
4229
|
+
operation: "deposit",
|
|
4230
|
+
state: "expired"
|
|
4231
|
+
});
|
|
4477
4232
|
}
|
|
4478
4233
|
if (input.collateralAmount > 0n) {
|
|
4479
|
-
return
|
|
4234
|
+
return createLiquidiumStatus({
|
|
4235
|
+
operation: "deposit",
|
|
4236
|
+
state: "processing"
|
|
4237
|
+
});
|
|
4238
|
+
}
|
|
4239
|
+
if (input.depositDetectedTimestamp !== null) {
|
|
4240
|
+
return createLiquidiumStatus({
|
|
4241
|
+
operation: "deposit",
|
|
4242
|
+
state: "confirming"
|
|
4243
|
+
});
|
|
4244
|
+
}
|
|
4245
|
+
return createLiquidiumStatus({
|
|
4246
|
+
operation: "deposit",
|
|
4247
|
+
state: "action_required"
|
|
4248
|
+
});
|
|
4249
|
+
}
|
|
4250
|
+
function deriveActiveInstantLoanActivityStatus(input) {
|
|
4251
|
+
if (!input.started) {
|
|
4252
|
+
return findActiveActivityStatus(input.activeActivities, "deposit");
|
|
4253
|
+
}
|
|
4254
|
+
const borrowStatus = findActiveActivityStatus(
|
|
4255
|
+
input.activeActivities,
|
|
4256
|
+
"borrow"
|
|
4257
|
+
);
|
|
4258
|
+
if (borrowStatus) {
|
|
4259
|
+
return borrowStatus;
|
|
4480
4260
|
}
|
|
4481
|
-
return
|
|
4261
|
+
return findActiveActivityStatus(input.activeActivities, "repayment");
|
|
4262
|
+
}
|
|
4263
|
+
function findActiveActivityStatus(activities, operation) {
|
|
4264
|
+
const activity = activities.find(
|
|
4265
|
+
(candidate) => candidate.status.operation === operation
|
|
4266
|
+
);
|
|
4267
|
+
return activity?.status ?? null;
|
|
4268
|
+
}
|
|
4269
|
+
function isInstantLoanDepositExpired(input) {
|
|
4270
|
+
if (input.started || input.depositDetectedTimestamp === null) {
|
|
4271
|
+
return false;
|
|
4272
|
+
}
|
|
4273
|
+
if (input.expiryTimestamp === null) {
|
|
4274
|
+
return false;
|
|
4275
|
+
}
|
|
4276
|
+
return input.expiryTimestamp <= getCurrentUnixTimestampSeconds();
|
|
4277
|
+
}
|
|
4278
|
+
function getCurrentUnixTimestampSeconds() {
|
|
4279
|
+
return BigInt(Math.floor(Date.now() / MILLISECONDS_PER_SECOND3));
|
|
4482
4280
|
}
|
|
4483
4281
|
function deriveDepositExpiryTimestamp(input) {
|
|
4484
4282
|
if (input.depositDetectedTimestamp === null) {
|
|
@@ -4927,6 +4725,60 @@ function accountTypeToString(accountType) {
|
|
|
4927
4725
|
}
|
|
4928
4726
|
}
|
|
4929
4727
|
|
|
4728
|
+
// src/core/withdraw-minimums.ts
|
|
4729
|
+
var MINIMUM_BTC_WITHDRAW_AMOUNT_SATS = 5000n;
|
|
4730
|
+
var MINIMUM_STABLECOIN_WITHDRAW_AMOUNT_BASE_UNITS = 1000000n;
|
|
4731
|
+
var MIN_WITHDRAW_AMOUNTS_BY_ASSET = {
|
|
4732
|
+
[Asset.BTC]: MINIMUM_BTC_WITHDRAW_AMOUNT_SATS,
|
|
4733
|
+
[Asset.USDC]: MINIMUM_STABLECOIN_WITHDRAW_AMOUNT_BASE_UNITS,
|
|
4734
|
+
[Asset.USDT]: MINIMUM_STABLECOIN_WITHDRAW_AMOUNT_BASE_UNITS
|
|
4735
|
+
};
|
|
4736
|
+
function getMinimumWithdrawAmount(asset) {
|
|
4737
|
+
if (!isMinimumWithdrawAsset(asset)) {
|
|
4738
|
+
return 0n;
|
|
4739
|
+
}
|
|
4740
|
+
return MIN_WITHDRAW_AMOUNTS_BY_ASSET[asset];
|
|
4741
|
+
}
|
|
4742
|
+
function getWithdrawAmountMinimumValidationError(params) {
|
|
4743
|
+
const minimumAmount = getMinimumWithdrawAmount(params.asset);
|
|
4744
|
+
if (minimumAmount <= 0n || params.amount >= minimumAmount) {
|
|
4745
|
+
return null;
|
|
4746
|
+
}
|
|
4747
|
+
return {
|
|
4748
|
+
asset: params.asset,
|
|
4749
|
+
minimumAmount,
|
|
4750
|
+
message: formatMinimumWithdrawAmountMessage(params.asset, minimumAmount)
|
|
4751
|
+
};
|
|
4752
|
+
}
|
|
4753
|
+
function formatMinimumWithdrawAmountMessage(asset, minimumAmount) {
|
|
4754
|
+
return `Withdraw amount must be at least ${minimumAmount} base units for ${asset}`;
|
|
4755
|
+
}
|
|
4756
|
+
function isMinimumWithdrawAsset(asset) {
|
|
4757
|
+
return Object.hasOwn(MIN_WITHDRAW_AMOUNTS_BY_ASSET, asset);
|
|
4758
|
+
}
|
|
4759
|
+
|
|
4760
|
+
// src/modules/lending/_internal/inflow-fee-rounding.ts
|
|
4761
|
+
var ETH_STABLECOIN_INFLOW_FEE_ROUND_UP_TO_NEAREST_10_CENTS = 100000n;
|
|
4762
|
+
var BTC_INFLOW_FEE_ROUND_UP_TO_NEAREST_SATS = 500n;
|
|
4763
|
+
function roundInflowFeeEstimate(request, totalFee) {
|
|
4764
|
+
if (totalFee <= 0n) {
|
|
4765
|
+
return 0n;
|
|
4766
|
+
}
|
|
4767
|
+
if (isEthStablecoin(request.asset, request.chain)) {
|
|
4768
|
+
return roundUpToNearest(
|
|
4769
|
+
totalFee,
|
|
4770
|
+
ETH_STABLECOIN_INFLOW_FEE_ROUND_UP_TO_NEAREST_10_CENTS
|
|
4771
|
+
);
|
|
4772
|
+
}
|
|
4773
|
+
if (request.asset === Asset.BTC && request.chain === Chain.BTC) {
|
|
4774
|
+
return roundUpToNearest(totalFee, BTC_INFLOW_FEE_ROUND_UP_TO_NEAREST_SATS);
|
|
4775
|
+
}
|
|
4776
|
+
return totalFee;
|
|
4777
|
+
}
|
|
4778
|
+
function roundUpToNearest(amount, roundingUnit) {
|
|
4779
|
+
return ceilDivBigint(amount, roundingUnit) * roundingUnit;
|
|
4780
|
+
}
|
|
4781
|
+
|
|
4930
4782
|
// src/core/utils/retry.ts
|
|
4931
4783
|
var MIN_ATTEMPTS = 1;
|
|
4932
4784
|
var MIN_INITIAL_RETRY_DELAY_MS = 0;
|
|
@@ -4978,835 +4830,985 @@ function assertValidRetryOptions(options) {
|
|
|
4978
4830
|
}
|
|
4979
4831
|
}
|
|
4980
4832
|
|
|
4981
|
-
// src/modules/lending/_internal/
|
|
4982
|
-
var
|
|
4983
|
-
var
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4833
|
+
// src/modules/lending/_internal/supply-flow.ts
|
|
4834
|
+
var SUBMIT_INFLOW_MAX_ATTEMPTS = 4;
|
|
4835
|
+
var SUBMIT_INFLOW_INITIAL_RETRY_DELAY_MS = 1500;
|
|
4836
|
+
var SUBMIT_INFLOW_RETRY_BACKOFF_MULTIPLIER = 2;
|
|
4837
|
+
var ETH_APPROVAL_POLL_INTERVAL_MS = 2e3;
|
|
4838
|
+
var ETH_APPROVAL_MAX_POLLS = 30;
|
|
4839
|
+
var SupplyFlowExecutor = class {
|
|
4840
|
+
constructor(params) {
|
|
4841
|
+
this.params = params;
|
|
4987
4842
|
}
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4843
|
+
params;
|
|
4844
|
+
async create(request) {
|
|
4845
|
+
const target = await resolveSupplyTarget(
|
|
4846
|
+
this.params.canisterContext,
|
|
4847
|
+
request
|
|
4992
4848
|
);
|
|
4993
|
-
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
function roundUpToNearest(amount, roundingUnit) {
|
|
5000
|
-
return ceilDivBigint(amount, roundingUnit) * roundingUnit;
|
|
5001
|
-
}
|
|
5002
|
-
function mapCanisterOutflowDetails(outflow) {
|
|
5003
|
-
const rawOutflowType = getVariantKey(outflow.outflow_type);
|
|
5004
|
-
return {
|
|
5005
|
-
id: outflow.id,
|
|
5006
|
-
outflowType: normalizeOutflowType(rawOutflowType),
|
|
5007
|
-
outflowRef: outflow.outflow_ref[0],
|
|
5008
|
-
txid: outflow.txid[0],
|
|
5009
|
-
amount: outflow.amount,
|
|
5010
|
-
receiver: mapCanisterAccountType(outflow.receiver)
|
|
5011
|
-
};
|
|
5012
|
-
}
|
|
5013
|
-
function mapCanisterAccountType(receiver) {
|
|
5014
|
-
if ("Native" in receiver) {
|
|
5015
|
-
return {
|
|
5016
|
-
type: "Native",
|
|
5017
|
-
account: receiver.Native.toText()
|
|
5018
|
-
};
|
|
5019
|
-
}
|
|
5020
|
-
if ("AccountIdentifier" in receiver) {
|
|
5021
|
-
return {
|
|
5022
|
-
type: "AccountIdentifier",
|
|
5023
|
-
account: receiver.AccountIdentifier
|
|
4849
|
+
const instruction = {
|
|
4850
|
+
poolId: request.poolId,
|
|
4851
|
+
asset: target.asset,
|
|
4852
|
+
chain: target.chain,
|
|
4853
|
+
action: request.action,
|
|
4854
|
+
target
|
|
5024
4855
|
};
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
4856
|
+
const mechanism = resolveSupplyMechanism({
|
|
4857
|
+
asset: instruction.asset,
|
|
4858
|
+
chain: instruction.chain,
|
|
4859
|
+
requestedMechanism: request.mechanism
|
|
4860
|
+
});
|
|
4861
|
+
const defaultSubmitInflowRequest = getDefaultSubmitInflowRequest({
|
|
4862
|
+
action: request.action,
|
|
4863
|
+
chain: mechanism === SupplyPlanType.contractInteraction ? Chain.ETH : instruction.chain
|
|
4864
|
+
});
|
|
4865
|
+
let txid;
|
|
4866
|
+
switch (mechanism) {
|
|
4867
|
+
case SupplyPlanType.transfer:
|
|
4868
|
+
if (request.walletAdapter) {
|
|
4869
|
+
txid = await this.sendAndSubmitNativeSupplyInflow({
|
|
4870
|
+
request,
|
|
4871
|
+
instruction,
|
|
4872
|
+
defaultSubmitInflowRequest
|
|
4873
|
+
});
|
|
4874
|
+
}
|
|
4875
|
+
break;
|
|
4876
|
+
case SupplyPlanType.contractInteraction:
|
|
4877
|
+
txid = await this.executeContractSupply({
|
|
4878
|
+
request,
|
|
4879
|
+
instruction,
|
|
4880
|
+
defaultSubmitInflowRequest
|
|
4881
|
+
});
|
|
4882
|
+
break;
|
|
4883
|
+
}
|
|
4884
|
+
return {
|
|
4885
|
+
type: mechanism,
|
|
4886
|
+
target: instruction.target,
|
|
4887
|
+
txid,
|
|
4888
|
+
status: createLiquidiumStatus({
|
|
4889
|
+
operation: mapSupplyActionToStatusOperation(request.action),
|
|
4890
|
+
state: txid ? "confirming" : "action_required"
|
|
4891
|
+
}),
|
|
4892
|
+
submit: async (submitRequest) => {
|
|
4893
|
+
return await this.submitSupplyFlowInflow({
|
|
4894
|
+
instruction,
|
|
4895
|
+
mechanism,
|
|
4896
|
+
defaultSubmitInflowRequest,
|
|
4897
|
+
submitRequest
|
|
4898
|
+
});
|
|
4899
|
+
}
|
|
5036
4900
|
};
|
|
5037
4901
|
}
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
return void 0;
|
|
4902
|
+
async getEvmSupplyContext(request) {
|
|
4903
|
+
const selectedPool = await this.params.getPoolById(request.poolId);
|
|
4904
|
+
return await this.getEvmSupplyContextForPool({
|
|
4905
|
+
request,
|
|
4906
|
+
asset: selectedPool.asset,
|
|
4907
|
+
chain: selectedPool.chain
|
|
4908
|
+
});
|
|
5046
4909
|
}
|
|
5047
|
-
|
|
5048
|
-
}
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
default:
|
|
4910
|
+
async getEvmSupplyContextForPool(params) {
|
|
4911
|
+
const { request, asset, chain } = params;
|
|
4912
|
+
const evmReadClient = this.requireEvmReadClient(
|
|
4913
|
+
"EVM supply context requires an EVM RPC URL or public client"
|
|
4914
|
+
);
|
|
4915
|
+
const walletAddress = normalizeAndValidateEvmAddress(
|
|
4916
|
+
request.walletAddress,
|
|
4917
|
+
"Invalid EVM wallet address"
|
|
4918
|
+
);
|
|
4919
|
+
if (request.amount <= 0n) {
|
|
5058
4920
|
throw new LiquidiumError(
|
|
5059
|
-
LiquidiumErrorCode.
|
|
5060
|
-
|
|
4921
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4922
|
+
"EVM supply context requires a positive amount"
|
|
4923
|
+
);
|
|
4924
|
+
}
|
|
4925
|
+
if (!isEthStablecoin(asset, chain)) {
|
|
4926
|
+
throw new LiquidiumError(
|
|
4927
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4928
|
+
`EVM supply context only supports ETH stablecoin pools, received ${asset} on ${chain}`
|
|
5061
4929
|
);
|
|
4930
|
+
}
|
|
4931
|
+
const tokenAddress = getEthStablecoinContractAddress(asset);
|
|
4932
|
+
const spenderAddress = CK_ETH_DEPOSIT_CONTRACT_ADDRESS;
|
|
4933
|
+
const [allowance, balance] = await Promise.all([
|
|
4934
|
+
readErc20Allowance({
|
|
4935
|
+
evmReadClient,
|
|
4936
|
+
tokenAddress,
|
|
4937
|
+
ownerAddress: walletAddress,
|
|
4938
|
+
spenderAddress
|
|
4939
|
+
}),
|
|
4940
|
+
readErc20Balance({
|
|
4941
|
+
evmReadClient,
|
|
4942
|
+
tokenAddress,
|
|
4943
|
+
ownerAddress: walletAddress
|
|
4944
|
+
})
|
|
4945
|
+
]);
|
|
4946
|
+
const approvalStrategy = getApprovalStrategy({
|
|
4947
|
+
allowance,
|
|
4948
|
+
amount: request.amount
|
|
4949
|
+
});
|
|
4950
|
+
return {
|
|
4951
|
+
profileId: request.profileId,
|
|
4952
|
+
poolId: request.poolId,
|
|
4953
|
+
walletAddress,
|
|
4954
|
+
action: request.action,
|
|
4955
|
+
asset,
|
|
4956
|
+
chain: Chain.ETH,
|
|
4957
|
+
amount: request.amount.toString(),
|
|
4958
|
+
tokenAddress,
|
|
4959
|
+
spenderAddress,
|
|
4960
|
+
depositContractAddress: CK_ETH_DEPOSIT_CONTRACT_ADDRESS,
|
|
4961
|
+
balance: balance.toString(),
|
|
4962
|
+
allowance: allowance.toString(),
|
|
4963
|
+
requiresApproval: approvalStrategy !== EvmSupplyApprovalStrategy.none,
|
|
4964
|
+
approvalStrategy
|
|
4965
|
+
};
|
|
5062
4966
|
}
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
4967
|
+
async sendAndSubmitNativeSupplyInflow(params) {
|
|
4968
|
+
const { request, instruction, defaultSubmitInflowRequest } = params;
|
|
4969
|
+
if (instruction.target.type !== "nativeAddress") {
|
|
4970
|
+
throw new LiquidiumError(
|
|
4971
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4972
|
+
"Wallet-executed supply requires a native-address target"
|
|
4973
|
+
);
|
|
4974
|
+
}
|
|
4975
|
+
if (!request.walletAdapter) {
|
|
4976
|
+
throw new LiquidiumError(
|
|
4977
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4978
|
+
"Wallet-executed supply requires a wallet adapter"
|
|
4979
|
+
);
|
|
4980
|
+
}
|
|
4981
|
+
const account = request.account?.trim();
|
|
4982
|
+
if (!account) {
|
|
4983
|
+
throw new LiquidiumError(
|
|
4984
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4985
|
+
"Wallet-executed transfer supply requires an account"
|
|
4986
|
+
);
|
|
4987
|
+
}
|
|
4988
|
+
if (!request.amount || request.amount <= 0n) {
|
|
4989
|
+
throw new LiquidiumError(
|
|
4990
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4991
|
+
"Wallet-executed supply requires a positive amount"
|
|
4992
|
+
);
|
|
4993
|
+
}
|
|
4994
|
+
const txid = await this.sendNativeSupplyTransaction({
|
|
4995
|
+
walletAdapter: request.walletAdapter,
|
|
4996
|
+
chain: instruction.chain,
|
|
4997
|
+
toAddress: instruction.target.address,
|
|
4998
|
+
amount: request.amount,
|
|
4999
|
+
senderAccount: account,
|
|
5000
|
+
asset: instruction.asset,
|
|
5001
|
+
action: request.action
|
|
5002
|
+
});
|
|
5003
|
+
if (shouldSubmitInflow({ instruction, mechanism: SupplyPlanType.transfer })) {
|
|
5004
|
+
try {
|
|
5005
|
+
await this.submitInflowWithRetry(txid, defaultSubmitInflowRequest);
|
|
5006
|
+
} catch {
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
return txid;
|
|
5070
5010
|
}
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5011
|
+
async submitSupplyFlowInflow(params) {
|
|
5012
|
+
if (!shouldSubmitInflow(params)) {
|
|
5013
|
+
return {
|
|
5014
|
+
txid: params.submitRequest.txid
|
|
5015
|
+
};
|
|
5016
|
+
}
|
|
5017
|
+
const defaultSubmitInflowRequest = params.defaultSubmitInflowRequest;
|
|
5018
|
+
if (!defaultSubmitInflowRequest) {
|
|
5019
|
+
throw new LiquidiumError(
|
|
5020
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5021
|
+
"Supply flow submit requires an inflow operation"
|
|
5022
|
+
);
|
|
5023
|
+
}
|
|
5024
|
+
return await this.params.submitInflow({
|
|
5025
|
+
...defaultSubmitInflowRequest,
|
|
5026
|
+
...params.submitRequest
|
|
5027
|
+
});
|
|
5084
5028
|
}
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5029
|
+
async executeContractSupply(params) {
|
|
5030
|
+
const { request, instruction, defaultSubmitInflowRequest } = params;
|
|
5031
|
+
if (instruction.target.type !== "icrcAccount" || instruction.chain !== Chain.ETH) {
|
|
5032
|
+
throw new LiquidiumError(
|
|
5033
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5034
|
+
"Contract-interaction supply is only supported for ETH ICRC-account targets"
|
|
5035
|
+
);
|
|
5036
|
+
}
|
|
5037
|
+
const walletAddressInput = request.account?.trim();
|
|
5038
|
+
if (!walletAddressInput) {
|
|
5039
|
+
throw new LiquidiumError(
|
|
5040
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5041
|
+
"Contract-interaction supply requires an account"
|
|
5042
|
+
);
|
|
5043
|
+
}
|
|
5044
|
+
const walletAddress = normalizeAndValidateEvmAddress(
|
|
5045
|
+
walletAddressInput,
|
|
5046
|
+
"Invalid EVM wallet address"
|
|
5100
5047
|
);
|
|
5101
|
-
if (!
|
|
5048
|
+
if (!request.amount || request.amount <= 0n) {
|
|
5102
5049
|
throw new LiquidiumError(
|
|
5103
5050
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5104
|
-
"
|
|
5051
|
+
"Contract-interaction supply requires a positive amount"
|
|
5105
5052
|
);
|
|
5106
5053
|
}
|
|
5107
|
-
|
|
5054
|
+
const walletAdapter = request.walletAdapter;
|
|
5055
|
+
if (!walletAdapter?.sendEthTransaction) {
|
|
5108
5056
|
throw new LiquidiumError(
|
|
5109
5057
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5110
|
-
"
|
|
5058
|
+
"Contract-interaction supply requires an ETH wallet adapter"
|
|
5111
5059
|
);
|
|
5112
5060
|
}
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
const
|
|
5118
|
-
|
|
5119
|
-
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
5120
|
-
const nonce = await lendingActor.get_nonce(signerAccount);
|
|
5121
|
-
const withdrawRequestData = {
|
|
5061
|
+
this.params.requireApi();
|
|
5062
|
+
this.requireEvmReadClient(
|
|
5063
|
+
"Contract-interaction supply requires an EVM RPC URL or public client"
|
|
5064
|
+
);
|
|
5065
|
+
const evmSupplyContext = await this.getEvmSupplyContextForPool({
|
|
5066
|
+
request: {
|
|
5122
5067
|
profileId: request.profileId,
|
|
5123
5068
|
poolId: request.poolId,
|
|
5069
|
+
walletAddress,
|
|
5124
5070
|
amount: request.amount,
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
{
|
|
5137
|
-
pool_id: request.poolId,
|
|
5138
|
-
amount: request.amount.toString(),
|
|
5139
|
-
account: { type: "External", data: receiverAddress },
|
|
5140
|
-
expiry_timestamp: expiryTimestamp
|
|
5141
|
-
},
|
|
5142
|
-
nonce
|
|
5143
|
-
),
|
|
5144
|
-
data: withdrawRequestData,
|
|
5145
|
-
submit: async (signatureInfo) => {
|
|
5146
|
-
return await this.submitWithdraw(withdrawRequestData, signatureInfo);
|
|
5147
|
-
}
|
|
5148
|
-
};
|
|
5149
|
-
} catch (error) {
|
|
5150
|
-
if (error instanceof LiquidiumError) {
|
|
5151
|
-
throw error;
|
|
5152
|
-
}
|
|
5153
|
-
throw mapCanisterCallErrorToLiquidiumError("get_nonce", error);
|
|
5071
|
+
action: request.action
|
|
5072
|
+
},
|
|
5073
|
+
asset: instruction.asset,
|
|
5074
|
+
chain: instruction.chain
|
|
5075
|
+
});
|
|
5076
|
+
const supplyAmount = BigInt(evmSupplyContext.amount);
|
|
5077
|
+
if (BigInt(evmSupplyContext.balance) < supplyAmount) {
|
|
5078
|
+
throw new LiquidiumError(
|
|
5079
|
+
LiquidiumErrorCode.INSUFFICIENT_FUNDS,
|
|
5080
|
+
`Insufficient ${evmSupplyContext.asset} balance for ${request.action}`
|
|
5081
|
+
);
|
|
5154
5082
|
}
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
amount: request.amount
|
|
5166
|
-
},
|
|
5167
|
-
signature_info: {
|
|
5168
|
-
Wallet: {
|
|
5169
|
-
signature: normalizeWalletSignature(
|
|
5170
|
-
signatureInfo.signature,
|
|
5171
|
-
signatureInfo.chain
|
|
5172
|
-
),
|
|
5173
|
-
chain: mapWalletChainToLendingChain(signatureInfo.chain),
|
|
5174
|
-
account: request.signerWalletAddress
|
|
5175
|
-
}
|
|
5176
|
-
}
|
|
5177
|
-
}
|
|
5083
|
+
if (evmSupplyContext.approvalStrategy === EvmSupplyApprovalStrategy.resetThenApproveMax) {
|
|
5084
|
+
await this.sendEthContractTransaction(
|
|
5085
|
+
walletAdapter,
|
|
5086
|
+
walletAddress,
|
|
5087
|
+
createApproveTransaction({
|
|
5088
|
+
tokenAddress: evmSupplyContext.tokenAddress,
|
|
5089
|
+
spenderAddress: evmSupplyContext.spenderAddress,
|
|
5090
|
+
amount: 0n
|
|
5091
|
+
}),
|
|
5092
|
+
`supply-${request.action}-approve-reset`
|
|
5178
5093
|
);
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
|
|
5185
|
-
|
|
5094
|
+
await this.waitForExpectedAllowance({
|
|
5095
|
+
walletAddress,
|
|
5096
|
+
tokenAddress: evmSupplyContext.tokenAddress,
|
|
5097
|
+
spenderAddress: evmSupplyContext.spenderAddress,
|
|
5098
|
+
amount: supplyAmount,
|
|
5099
|
+
expectation: "zero"
|
|
5100
|
+
});
|
|
5101
|
+
}
|
|
5102
|
+
if (evmSupplyContext.approvalStrategy !== EvmSupplyApprovalStrategy.none) {
|
|
5103
|
+
await this.sendEthContractTransaction(
|
|
5104
|
+
walletAdapter,
|
|
5105
|
+
walletAddress,
|
|
5106
|
+
createApproveTransaction({
|
|
5107
|
+
tokenAddress: evmSupplyContext.tokenAddress,
|
|
5108
|
+
spenderAddress: evmSupplyContext.spenderAddress,
|
|
5109
|
+
amount: MAX_UINT256
|
|
5110
|
+
}),
|
|
5111
|
+
`supply-${request.action}-approve-max`
|
|
5186
5112
|
);
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5113
|
+
await this.waitForExpectedAllowance({
|
|
5114
|
+
walletAddress,
|
|
5115
|
+
tokenAddress: evmSupplyContext.tokenAddress,
|
|
5116
|
+
spenderAddress: evmSupplyContext.spenderAddress,
|
|
5117
|
+
amount: supplyAmount,
|
|
5118
|
+
expectation: "sufficient"
|
|
5119
|
+
});
|
|
5192
5120
|
}
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
chain: params.signerChain,
|
|
5207
|
-
account: action.account
|
|
5208
|
-
})(action);
|
|
5209
|
-
}
|
|
5210
|
-
/**
|
|
5211
|
-
* Prepares a borrow action that can be signed and submitted later.
|
|
5212
|
-
*
|
|
5213
|
-
* Use this when you need explicit control over signing and submission.
|
|
5214
|
-
*
|
|
5215
|
-
* @param request - Profile, pool, amount (borrow asset base units), outflow address, and signer wallet.
|
|
5216
|
-
* @returns A signable {@link BorrowAction} with `submit` wired to the canister.
|
|
5217
|
-
*/
|
|
5218
|
-
async prepareBorrow(request) {
|
|
5219
|
-
const destinationAccount = request.receiverAddress.trim();
|
|
5220
|
-
const signerAccount = normalizeEvmAddress(
|
|
5221
|
-
request.signerWalletAddress.trim()
|
|
5121
|
+
const depositTxid = await this.sendEthContractTransaction(
|
|
5122
|
+
walletAdapter,
|
|
5123
|
+
walletAddress,
|
|
5124
|
+
createDepositErc20Transaction({
|
|
5125
|
+
depositContractAddress: evmSupplyContext.depositContractAddress,
|
|
5126
|
+
tokenAddress: evmSupplyContext.tokenAddress,
|
|
5127
|
+
amount: supplyAmount,
|
|
5128
|
+
poolId: request.poolId,
|
|
5129
|
+
profileId: request.profileId,
|
|
5130
|
+
destinationAccount: instruction.target.account,
|
|
5131
|
+
action: request.action
|
|
5132
|
+
}),
|
|
5133
|
+
`supply-${request.action}-deposit-erc20`
|
|
5222
5134
|
);
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
"Borrow requires a custom outflow account"
|
|
5227
|
-
);
|
|
5135
|
+
try {
|
|
5136
|
+
await this.submitInflowWithRetry(depositTxid, defaultSubmitInflowRequest);
|
|
5137
|
+
} catch {
|
|
5228
5138
|
}
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5139
|
+
return depositTxid;
|
|
5140
|
+
}
|
|
5141
|
+
async sendNativeSupplyTransaction(params) {
|
|
5142
|
+
switch (params.chain) {
|
|
5143
|
+
case Chain.BTC: {
|
|
5144
|
+
if (!params.walletAdapter.sendBtcTransaction) {
|
|
5145
|
+
throw new LiquidiumError(
|
|
5146
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5147
|
+
"BTC wallet adapter does not support transaction sending"
|
|
5148
|
+
);
|
|
5149
|
+
}
|
|
5150
|
+
return await params.walletAdapter.sendBtcTransaction({
|
|
5151
|
+
chain: Chain.BTC,
|
|
5152
|
+
toAddress: params.toAddress,
|
|
5153
|
+
amountSats: params.amount,
|
|
5154
|
+
account: params.senderAccount,
|
|
5155
|
+
actionType: `supply-${params.action}`,
|
|
5156
|
+
transferMode: TransferMode.native
|
|
5157
|
+
});
|
|
5158
|
+
}
|
|
5159
|
+
case Chain.ETH: {
|
|
5160
|
+
if (!params.walletAdapter.sendEthTransaction) {
|
|
5161
|
+
throw new LiquidiumError(
|
|
5162
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5163
|
+
"ETH wallet adapter does not support transaction sending"
|
|
5164
|
+
);
|
|
5165
|
+
}
|
|
5166
|
+
if (isEthStablecoin(params.asset, params.chain)) {
|
|
5167
|
+
return await params.walletAdapter.sendEthTransaction({
|
|
5168
|
+
chain: Chain.ETH,
|
|
5169
|
+
account: params.senderAccount,
|
|
5170
|
+
actionType: `supply-${params.action}`,
|
|
5171
|
+
transferMode: TransferMode.native,
|
|
5172
|
+
transaction: createTransferErc20Transaction({
|
|
5173
|
+
tokenAddress: getEthStablecoinContractAddress(params.asset),
|
|
5174
|
+
recipientAddress: params.toAddress,
|
|
5175
|
+
amount: params.amount
|
|
5176
|
+
})
|
|
5177
|
+
});
|
|
5178
|
+
}
|
|
5179
|
+
return await params.walletAdapter.sendEthTransaction({
|
|
5180
|
+
chain: Chain.ETH,
|
|
5181
|
+
account: params.senderAccount,
|
|
5182
|
+
actionType: `supply-${params.action}`,
|
|
5183
|
+
transferMode: TransferMode.native,
|
|
5184
|
+
transaction: {
|
|
5185
|
+
to: params.toAddress,
|
|
5186
|
+
value: params.amount.toString()
|
|
5187
|
+
}
|
|
5188
|
+
});
|
|
5189
|
+
}
|
|
5190
|
+
default:
|
|
5191
|
+
throw new LiquidiumError(
|
|
5192
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5193
|
+
`Native-address wallet execution is not supported for ${params.chain}`
|
|
5194
|
+
);
|
|
5234
5195
|
}
|
|
5235
|
-
|
|
5196
|
+
}
|
|
5197
|
+
async submitInflowWithRetry(txid, extraRequest) {
|
|
5198
|
+
if (!extraRequest) {
|
|
5236
5199
|
throw new LiquidiumError(
|
|
5237
5200
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5238
|
-
"
|
|
5201
|
+
"Inflow submission requires an operation"
|
|
5239
5202
|
);
|
|
5240
5203
|
}
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5204
|
+
await retryWithBackoff({
|
|
5205
|
+
execute: async () => {
|
|
5206
|
+
await this.params.submitInflow({ txid, ...extraRequest });
|
|
5207
|
+
},
|
|
5208
|
+
maxAttempts: SUBMIT_INFLOW_MAX_ATTEMPTS,
|
|
5209
|
+
initialRetryDelayMs: SUBMIT_INFLOW_INITIAL_RETRY_DELAY_MS,
|
|
5210
|
+
backoffMultiplier: SUBMIT_INFLOW_RETRY_BACKOFF_MULTIPLIER,
|
|
5211
|
+
shouldRetryError: isRetriableInflowSubmitError
|
|
5246
5212
|
});
|
|
5247
|
-
|
|
5213
|
+
}
|
|
5214
|
+
async sendEthContractTransaction(walletAdapter, walletAddress, request, actionType) {
|
|
5215
|
+
if (!walletAdapter.sendEthTransaction) {
|
|
5248
5216
|
throw new LiquidiumError(
|
|
5249
5217
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5250
|
-
|
|
5218
|
+
"ETH wallet adapter does not support transaction sending"
|
|
5251
5219
|
);
|
|
5252
5220
|
}
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5221
|
+
return await walletAdapter.sendEthTransaction({
|
|
5222
|
+
chain: Chain.ETH,
|
|
5223
|
+
account: walletAddress,
|
|
5224
|
+
actionType,
|
|
5225
|
+
transferMode: TransferMode.native,
|
|
5226
|
+
transaction: request
|
|
5257
5227
|
});
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
account: signerAccount,
|
|
5276
|
-
message: createBorrowAssetMessage(
|
|
5277
|
-
{
|
|
5278
|
-
pool_id: request.poolId,
|
|
5279
|
-
amount: request.amount.toString(),
|
|
5280
|
-
account: { type: "External", data: receiverAddress },
|
|
5281
|
-
expiry_timestamp: expiryTimestamp
|
|
5282
|
-
},
|
|
5283
|
-
nonce
|
|
5284
|
-
),
|
|
5285
|
-
data: borrowRequestData,
|
|
5286
|
-
submit: async (signatureInfo) => {
|
|
5287
|
-
return await this.submitBorrow(borrowRequestData, signatureInfo);
|
|
5228
|
+
}
|
|
5229
|
+
async waitForExpectedAllowance(params) {
|
|
5230
|
+
const evmReadClient = this.requireEvmReadClient(
|
|
5231
|
+
"Contract-interaction supply requires an EVM RPC URL or public client"
|
|
5232
|
+
);
|
|
5233
|
+
let lastPollingError;
|
|
5234
|
+
for (let pollIndex = 0; pollIndex < ETH_APPROVAL_MAX_POLLS; pollIndex += 1) {
|
|
5235
|
+
try {
|
|
5236
|
+
const allowance = await readErc20Allowance({
|
|
5237
|
+
evmReadClient,
|
|
5238
|
+
tokenAddress: params.tokenAddress,
|
|
5239
|
+
ownerAddress: params.walletAddress,
|
|
5240
|
+
spenderAddress: params.spenderAddress
|
|
5241
|
+
});
|
|
5242
|
+
const matchesExpectation = params.expectation === "zero" ? allowance === 0n : allowance >= params.amount;
|
|
5243
|
+
if (matchesExpectation) {
|
|
5244
|
+
return;
|
|
5288
5245
|
}
|
|
5289
|
-
}
|
|
5290
|
-
|
|
5291
|
-
if (error instanceof LiquidiumError) {
|
|
5292
|
-
throw error;
|
|
5246
|
+
} catch (error) {
|
|
5247
|
+
lastPollingError = error;
|
|
5293
5248
|
}
|
|
5294
|
-
|
|
5249
|
+
await delay(ETH_APPROVAL_POLL_INTERVAL_MS);
|
|
5295
5250
|
}
|
|
5251
|
+
const lastPollingErrorMessage = getUnknownErrorMessage(lastPollingError);
|
|
5252
|
+
throw new LiquidiumError(
|
|
5253
|
+
LiquidiumErrorCode.SERVICE_UNAVAILABLE,
|
|
5254
|
+
lastPollingErrorMessage ? `Timed out waiting for ${params.expectation} ETH allowance update. Last polling error: ${lastPollingErrorMessage}` : `Timed out waiting for ${params.expectation} ETH allowance update`
|
|
5255
|
+
);
|
|
5296
5256
|
}
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
this.canisterContext
|
|
5301
|
-
).borrow_assets(Principal.fromText(request.profileId), {
|
|
5302
|
-
data: {
|
|
5303
|
-
expiry_timestamp: request.expiryTimestamp,
|
|
5304
|
-
account: { External: request.receiverAddress },
|
|
5305
|
-
pool_id: Principal.fromText(request.poolId),
|
|
5306
|
-
amount: request.amount
|
|
5307
|
-
},
|
|
5308
|
-
signature_info: {
|
|
5309
|
-
Wallet: {
|
|
5310
|
-
signature: normalizeWalletSignature(
|
|
5311
|
-
signatureInfo.signature,
|
|
5312
|
-
signatureInfo.chain
|
|
5313
|
-
),
|
|
5314
|
-
chain: mapWalletChainToLendingChain(signatureInfo.chain),
|
|
5315
|
-
account: request.signerWalletAddress
|
|
5316
|
-
}
|
|
5317
|
-
}
|
|
5318
|
-
});
|
|
5319
|
-
if ("Err" in result) {
|
|
5320
|
-
throw mapLendingProtocolErrorToLiquidiumError(result.Err);
|
|
5321
|
-
}
|
|
5322
|
-
return mapExpectedOutflowDetails(
|
|
5323
|
-
mapCanisterOutflowDetails(result.Ok),
|
|
5324
|
-
OutflowType.borrow,
|
|
5325
|
-
"borrow_assets"
|
|
5326
|
-
);
|
|
5327
|
-
} catch (error) {
|
|
5328
|
-
if (error instanceof LiquidiumError) {
|
|
5329
|
-
throw error;
|
|
5330
|
-
}
|
|
5331
|
-
throw mapCanisterCallErrorToLiquidiumError("borrow_assets", error);
|
|
5257
|
+
requireEvmReadClient(message) {
|
|
5258
|
+
if (!this.params.evmReadClient) {
|
|
5259
|
+
throw new LiquidiumError(LiquidiumErrorCode.VALIDATION_ERROR, message);
|
|
5332
5260
|
}
|
|
5261
|
+
return this.params.evmReadClient;
|
|
5333
5262
|
}
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5263
|
+
};
|
|
5264
|
+
async function readErc20Allowance(params) {
|
|
5265
|
+
const allowance = await params.evmReadClient.readContract({
|
|
5266
|
+
address: params.tokenAddress,
|
|
5267
|
+
abi: ERC20_ABI,
|
|
5268
|
+
functionName: "allowance",
|
|
5269
|
+
args: [
|
|
5270
|
+
params.ownerAddress,
|
|
5271
|
+
params.spenderAddress
|
|
5272
|
+
]
|
|
5273
|
+
});
|
|
5274
|
+
return BigInt(allowance);
|
|
5275
|
+
}
|
|
5276
|
+
async function readErc20Balance(params) {
|
|
5277
|
+
const balance = await params.evmReadClient.readContract({
|
|
5278
|
+
address: params.tokenAddress,
|
|
5279
|
+
abi: ERC20_ABI,
|
|
5280
|
+
functionName: "balanceOf",
|
|
5281
|
+
args: [params.ownerAddress]
|
|
5282
|
+
});
|
|
5283
|
+
return BigInt(balance);
|
|
5284
|
+
}
|
|
5285
|
+
function getApprovalStrategy(params) {
|
|
5286
|
+
if (params.allowance >= params.amount) {
|
|
5287
|
+
return EvmSupplyApprovalStrategy.none;
|
|
5353
5288
|
}
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
*
|
|
5357
|
-
* Transfer mode can return manual broadcast instructions when wallet fields are
|
|
5358
|
-
* omitted. Contract-interaction mode always requires `walletAdapter`, `account`,
|
|
5359
|
-
* and `amount` because it must prepare and submit approval/deposit calls.
|
|
5360
|
-
*
|
|
5361
|
-
* The SDK does not poll for inflow status. When a `txid` is returned, it is the
|
|
5362
|
-
* caller's responsibility to track confirmation state using their own polling.
|
|
5363
|
-
*
|
|
5364
|
-
* @returns A {@link SupplyFlow} receipt with `type`, `target`, `submit`, and
|
|
5365
|
-
* an optional `txid` present when the SDK broadcast for you.
|
|
5366
|
-
*/
|
|
5367
|
-
async supply(request) {
|
|
5368
|
-
const target = await resolveSupplyTarget(this.canisterContext, request);
|
|
5369
|
-
const instruction = {
|
|
5370
|
-
poolId: request.poolId,
|
|
5371
|
-
asset: target.asset,
|
|
5372
|
-
chain: target.chain,
|
|
5373
|
-
action: request.action,
|
|
5374
|
-
target
|
|
5375
|
-
};
|
|
5376
|
-
const mechanism = resolveSupplyMechanism({
|
|
5377
|
-
asset: instruction.asset,
|
|
5378
|
-
chain: instruction.chain,
|
|
5379
|
-
requestedMechanism: request.mechanism
|
|
5380
|
-
});
|
|
5381
|
-
const defaultSubmitInflowRequest = getDefaultSubmitInflowRequest({
|
|
5382
|
-
action: request.action,
|
|
5383
|
-
chain: mechanism === SupplyPlanType.contractInteraction ? Chain.ETH : instruction.chain
|
|
5384
|
-
});
|
|
5385
|
-
let txid;
|
|
5386
|
-
switch (mechanism) {
|
|
5387
|
-
case SupplyPlanType.transfer:
|
|
5388
|
-
if (request.walletAdapter) {
|
|
5389
|
-
txid = await this.sendAndSubmitNativeSupplyInflow({
|
|
5390
|
-
request,
|
|
5391
|
-
instruction,
|
|
5392
|
-
defaultSubmitInflowRequest
|
|
5393
|
-
});
|
|
5394
|
-
}
|
|
5395
|
-
break;
|
|
5396
|
-
case SupplyPlanType.contractInteraction:
|
|
5397
|
-
txid = await this.executeContractSupply({
|
|
5398
|
-
request,
|
|
5399
|
-
instruction,
|
|
5400
|
-
defaultSubmitInflowRequest
|
|
5401
|
-
});
|
|
5402
|
-
break;
|
|
5403
|
-
}
|
|
5404
|
-
return {
|
|
5405
|
-
type: mechanism,
|
|
5406
|
-
target: instruction.target,
|
|
5407
|
-
txid,
|
|
5408
|
-
submit: async (submitRequest) => {
|
|
5409
|
-
return await this.submitSupplyFlowInflow({
|
|
5410
|
-
instruction,
|
|
5411
|
-
mechanism,
|
|
5412
|
-
defaultSubmitInflowRequest,
|
|
5413
|
-
submitRequest
|
|
5414
|
-
});
|
|
5415
|
-
}
|
|
5416
|
-
};
|
|
5289
|
+
if (params.allowance === 0n) {
|
|
5290
|
+
return EvmSupplyApprovalStrategy.approveMax;
|
|
5417
5291
|
}
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
*/
|
|
5427
|
-
async getEvmSupplyContext(request) {
|
|
5428
|
-
const selectedPool = await this.getPoolById(request.poolId);
|
|
5429
|
-
return await this.getEvmSupplyContextForPool({
|
|
5430
|
-
request,
|
|
5431
|
-
asset: selectedPool.asset,
|
|
5432
|
-
chain: selectedPool.chain
|
|
5433
|
-
});
|
|
5292
|
+
return EvmSupplyApprovalStrategy.resetThenApproveMax;
|
|
5293
|
+
}
|
|
5294
|
+
async function delay(timeoutMs) {
|
|
5295
|
+
await new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
5296
|
+
}
|
|
5297
|
+
function isRetriableInflowSubmitError(error) {
|
|
5298
|
+
if (!(error instanceof LiquidiumError)) {
|
|
5299
|
+
return false;
|
|
5434
5300
|
}
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
]
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5301
|
+
return error.code === LiquidiumErrorCode.SERVICE_UNAVAILABLE;
|
|
5302
|
+
}
|
|
5303
|
+
function getUnknownErrorMessage(error) {
|
|
5304
|
+
if (error instanceof Error) {
|
|
5305
|
+
return error.message;
|
|
5306
|
+
}
|
|
5307
|
+
if (typeof error === "string") {
|
|
5308
|
+
return error;
|
|
5309
|
+
}
|
|
5310
|
+
return null;
|
|
5311
|
+
}
|
|
5312
|
+
function getDefaultSubmitInflowRequest(params) {
|
|
5313
|
+
if (params.chain !== Chain.BTC && params.chain !== Chain.ETH) {
|
|
5314
|
+
return void 0;
|
|
5315
|
+
}
|
|
5316
|
+
return {
|
|
5317
|
+
chain: params.chain,
|
|
5318
|
+
operation: mapSupplyActionToStatusOperation(params.action)
|
|
5319
|
+
};
|
|
5320
|
+
}
|
|
5321
|
+
function mapSupplyActionToStatusOperation(action) {
|
|
5322
|
+
return action === SupplyAction.repayment ? "repayment" : "deposit";
|
|
5323
|
+
}
|
|
5324
|
+
function shouldSubmitInflow(params) {
|
|
5325
|
+
if (params.mechanism !== SupplyPlanType.transfer) {
|
|
5326
|
+
return true;
|
|
5327
|
+
}
|
|
5328
|
+
return !isEthStablecoin(params.instruction.asset, params.instruction.chain);
|
|
5329
|
+
}
|
|
5330
|
+
function mapCanisterOutflowDetails(outflow) {
|
|
5331
|
+
const rawOutflowType = getVariantKey(outflow.outflow_type);
|
|
5332
|
+
return {
|
|
5333
|
+
id: outflow.id,
|
|
5334
|
+
outflowType: normalizeOutflowType(rawOutflowType),
|
|
5335
|
+
outflowRef: outflow.outflow_ref[0],
|
|
5336
|
+
txid: outflow.txid[0],
|
|
5337
|
+
amount: outflow.amount,
|
|
5338
|
+
receiver: mapCanisterAccountType(outflow.receiver)
|
|
5339
|
+
};
|
|
5340
|
+
}
|
|
5341
|
+
function mapCanisterAccountType(receiver) {
|
|
5342
|
+
if ("Native" in receiver) {
|
|
5475
5343
|
return {
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
poolId: request.poolId,
|
|
5479
|
-
walletAddress,
|
|
5480
|
-
action: request.action,
|
|
5481
|
-
asset,
|
|
5482
|
-
chain: Chain.ETH,
|
|
5483
|
-
amount: request.amount.toString(),
|
|
5484
|
-
tokenAddress,
|
|
5485
|
-
spenderAddress,
|
|
5486
|
-
depositContractAddress: CK_ETH_DEPOSIT_CONTRACT_ADDRESS,
|
|
5487
|
-
balance: balance.toString(),
|
|
5488
|
-
allowance: allowance.toString(),
|
|
5489
|
-
requiresApproval: approvalStrategy !== EvmSupplyApprovalStrategy.none,
|
|
5490
|
-
approvalStrategy
|
|
5344
|
+
type: "Native",
|
|
5345
|
+
account: receiver.Native.toText()
|
|
5491
5346
|
};
|
|
5492
5347
|
}
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5348
|
+
if ("AccountIdentifier" in receiver) {
|
|
5349
|
+
return {
|
|
5350
|
+
type: "AccountIdentifier",
|
|
5351
|
+
account: receiver.AccountIdentifier
|
|
5352
|
+
};
|
|
5353
|
+
}
|
|
5354
|
+
if ("Icrc" in receiver) {
|
|
5355
|
+
const subaccount = normalizeOptionalSubaccount2(receiver.Icrc.subaccount[0]);
|
|
5356
|
+
return {
|
|
5357
|
+
type: "Icrc",
|
|
5358
|
+
owner: receiver.Icrc.owner.toText(),
|
|
5359
|
+
subaccount,
|
|
5360
|
+
account: encodeIcrcAccount({
|
|
5361
|
+
owner: receiver.Icrc.owner,
|
|
5362
|
+
subaccount
|
|
5363
|
+
})
|
|
5364
|
+
};
|
|
5365
|
+
}
|
|
5366
|
+
return {
|
|
5367
|
+
type: "External",
|
|
5368
|
+
account: receiver.External
|
|
5369
|
+
};
|
|
5370
|
+
}
|
|
5371
|
+
function normalizeOptionalSubaccount2(subaccount) {
|
|
5372
|
+
if (!subaccount) {
|
|
5373
|
+
return void 0;
|
|
5374
|
+
}
|
|
5375
|
+
return subaccount instanceof Uint8Array ? subaccount : Uint8Array.from(subaccount);
|
|
5376
|
+
}
|
|
5377
|
+
function normalizeOutflowType(rawOutflowType) {
|
|
5378
|
+
switch (rawOutflowType) {
|
|
5379
|
+
case "Withdraw":
|
|
5380
|
+
return OutflowType.withdrawal;
|
|
5381
|
+
case "Borrow":
|
|
5382
|
+
return OutflowType.borrow;
|
|
5383
|
+
case "FeeClaim":
|
|
5384
|
+
return OutflowType.feeClaim;
|
|
5385
|
+
default:
|
|
5504
5386
|
throw new LiquidiumError(
|
|
5505
|
-
LiquidiumErrorCode.
|
|
5506
|
-
|
|
5387
|
+
LiquidiumErrorCode.INTERNAL,
|
|
5388
|
+
`Unsupported outflow type: ${rawOutflowType}`
|
|
5507
5389
|
);
|
|
5508
|
-
}
|
|
5509
|
-
const tokenAddress = getEthStablecoinContractAddress(request.asset);
|
|
5510
|
-
const subaccount = encodeInflowSubaccount({
|
|
5511
|
-
action: request.action,
|
|
5512
|
-
principal: Principal.fromText(request.profileId)
|
|
5513
|
-
});
|
|
5514
|
-
const result = await createDepositAccountsActor(
|
|
5515
|
-
this.canisterContext
|
|
5516
|
-
).get_deposit_address(
|
|
5517
|
-
{
|
|
5518
|
-
owner: Principal.fromText(request.poolId),
|
|
5519
|
-
subaccount: [subaccount]
|
|
5520
|
-
},
|
|
5521
|
-
[tokenAddress]
|
|
5522
|
-
);
|
|
5523
|
-
if ("Err" in result) {
|
|
5524
|
-
throw mapDepositAccountErrorToLiquidiumError(result.Err);
|
|
5525
|
-
}
|
|
5526
|
-
return result.Ok;
|
|
5527
5390
|
}
|
|
5391
|
+
}
|
|
5392
|
+
function mapWalletChainToLendingChain(chain) {
|
|
5393
|
+
switch (chain) {
|
|
5394
|
+
case Chain.BTC:
|
|
5395
|
+
return { BTC: null };
|
|
5396
|
+
case Chain.ETH:
|
|
5397
|
+
return { ETH: null };
|
|
5398
|
+
}
|
|
5399
|
+
}
|
|
5400
|
+
|
|
5401
|
+
// src/modules/lending/lending.ts
|
|
5402
|
+
var LendingModule = class {
|
|
5403
|
+
constructor(canisterContext, apiClient, evmReadClient) {
|
|
5404
|
+
this.canisterContext = canisterContext;
|
|
5405
|
+
this.apiClient = apiClient;
|
|
5406
|
+
this.evmReadClient = evmReadClient;
|
|
5407
|
+
}
|
|
5408
|
+
canisterContext;
|
|
5409
|
+
apiClient;
|
|
5410
|
+
evmReadClient;
|
|
5528
5411
|
/**
|
|
5529
|
-
*
|
|
5412
|
+
* Prepares a withdraw action that can be signed and submitted later.
|
|
5530
5413
|
*
|
|
5531
|
-
*
|
|
5532
|
-
* canister. BTC estimates include the ckBTC minter deposit fee and ledger fee.
|
|
5414
|
+
* Use this when you need explicit control over signing and submission.
|
|
5533
5415
|
*
|
|
5534
|
-
* @param request -
|
|
5535
|
-
* @returns
|
|
5416
|
+
* @param request - Profile, pool, amount (pool asset base units), outflow address, and signer wallet.
|
|
5417
|
+
* @returns A signable {@link WithdrawAction} with `submit` wired to the canister.
|
|
5536
5418
|
*/
|
|
5537
|
-
async
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
).estimate_deposit_fee([getEthStablecoinContractAddress(request.asset)]);
|
|
5542
|
-
if ("Err" in result) {
|
|
5543
|
-
throw mapDepositAccountErrorToLiquidiumError(result.Err);
|
|
5544
|
-
}
|
|
5545
|
-
return {
|
|
5546
|
-
totalFee: roundInflowFeeEstimate(request, result.Ok)
|
|
5547
|
-
};
|
|
5548
|
-
}
|
|
5549
|
-
if (request.asset === Asset.BTC && request.chain === Chain.BTC) {
|
|
5550
|
-
const estimate = await this.estimateBtcInflowFee();
|
|
5551
|
-
return {
|
|
5552
|
-
totalFee: roundInflowFeeEstimate(request, estimate.totalFee)
|
|
5553
|
-
};
|
|
5554
|
-
}
|
|
5555
|
-
throw new LiquidiumError(
|
|
5556
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5557
|
-
`Inflow fee estimates are not supported for ${request.asset} on ${request.chain}`
|
|
5419
|
+
async prepareWithdraw(request) {
|
|
5420
|
+
const destinationAccount = request.receiverAddress.trim();
|
|
5421
|
+
const signerAccount = normalizeEvmAddress(
|
|
5422
|
+
request.signerWalletAddress.trim()
|
|
5558
5423
|
);
|
|
5559
|
-
|
|
5560
|
-
async estimateBtcInflowFee() {
|
|
5561
|
-
const [minterFee, ledgerFee] = await Promise.all([
|
|
5562
|
-
createCkBtcMinterActor(this.canisterContext).get_deposit_fee(),
|
|
5563
|
-
createCkBtcLedgerActor(this.canisterContext).icrc1_fee()
|
|
5564
|
-
]);
|
|
5565
|
-
return { totalFee: minterFee + ledgerFee };
|
|
5566
|
-
}
|
|
5567
|
-
async sendAndSubmitNativeSupplyInflow(params) {
|
|
5568
|
-
const { request, instruction, defaultSubmitInflowRequest } = params;
|
|
5569
|
-
if (instruction.target.type !== "nativeAddress") {
|
|
5424
|
+
if (!destinationAccount) {
|
|
5570
5425
|
throw new LiquidiumError(
|
|
5571
5426
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5572
|
-
"
|
|
5427
|
+
"Withdraw requires a custom outflow account"
|
|
5573
5428
|
);
|
|
5574
5429
|
}
|
|
5575
|
-
if (!
|
|
5430
|
+
if (!signerAccount) {
|
|
5576
5431
|
throw new LiquidiumError(
|
|
5577
5432
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5578
|
-
"
|
|
5433
|
+
"Withdraw requires a signer account"
|
|
5579
5434
|
);
|
|
5580
5435
|
}
|
|
5581
|
-
|
|
5582
|
-
if (!account) {
|
|
5436
|
+
if (request.amount <= 0n) {
|
|
5583
5437
|
throw new LiquidiumError(
|
|
5584
5438
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5585
|
-
"
|
|
5439
|
+
"Withdraw amount must be greater than 0"
|
|
5586
5440
|
);
|
|
5587
5441
|
}
|
|
5588
|
-
|
|
5442
|
+
const selectedPool = await this.getPoolById(request.poolId);
|
|
5443
|
+
const selectedAsset = selectedPool.asset;
|
|
5444
|
+
const minimumWithdrawAmountError = getWithdrawAmountMinimumValidationError({
|
|
5445
|
+
amount: request.amount,
|
|
5446
|
+
asset: selectedAsset
|
|
5447
|
+
});
|
|
5448
|
+
if (minimumWithdrawAmountError) {
|
|
5589
5449
|
throw new LiquidiumError(
|
|
5590
5450
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5591
|
-
|
|
5451
|
+
minimumWithdrawAmountError.message
|
|
5592
5452
|
);
|
|
5593
5453
|
}
|
|
5594
|
-
const
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
amount: request.amount,
|
|
5599
|
-
senderAccount: account,
|
|
5600
|
-
asset: instruction.asset,
|
|
5601
|
-
action: request.action
|
|
5454
|
+
const receiverAddress = normalizeExternalAddress({
|
|
5455
|
+
address: destinationAccount,
|
|
5456
|
+
asset: selectedAsset,
|
|
5457
|
+
chain: selectedPool.chain
|
|
5602
5458
|
});
|
|
5603
|
-
|
|
5604
|
-
|
|
5459
|
+
const lendingActor = createLendingActor(this.canisterContext);
|
|
5460
|
+
try {
|
|
5461
|
+
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
5462
|
+
const nonce = await lendingActor.get_nonce(signerAccount);
|
|
5463
|
+
const withdrawRequestData = {
|
|
5464
|
+
profileId: request.profileId,
|
|
5465
|
+
poolId: request.poolId,
|
|
5466
|
+
amount: request.amount,
|
|
5467
|
+
receiverAddress,
|
|
5468
|
+
signerWalletAddress: signerAccount,
|
|
5469
|
+
expiryTimestamp
|
|
5470
|
+
};
|
|
5471
|
+
return {
|
|
5472
|
+
kind: WalletActionKind.createWithdraw,
|
|
5473
|
+
executionKind: WalletExecutionKind.signMessage,
|
|
5474
|
+
actionType: WalletActionKind.createWithdraw,
|
|
5475
|
+
transferMode: TransferMode.native,
|
|
5476
|
+
account: signerAccount,
|
|
5477
|
+
message: createWithdrawAssetMessage(
|
|
5478
|
+
{
|
|
5479
|
+
pool_id: request.poolId,
|
|
5480
|
+
amount: request.amount.toString(),
|
|
5481
|
+
account: { type: "External", data: receiverAddress },
|
|
5482
|
+
expiry_timestamp: expiryTimestamp
|
|
5483
|
+
},
|
|
5484
|
+
nonce
|
|
5485
|
+
),
|
|
5486
|
+
data: withdrawRequestData,
|
|
5487
|
+
submit: async (signatureInfo) => {
|
|
5488
|
+
return await this.submitWithdraw(withdrawRequestData, signatureInfo);
|
|
5489
|
+
}
|
|
5490
|
+
};
|
|
5491
|
+
} catch (error) {
|
|
5492
|
+
if (error instanceof LiquidiumError) {
|
|
5493
|
+
throw error;
|
|
5494
|
+
}
|
|
5495
|
+
throw mapCanisterCallErrorToLiquidiumError("get_nonce", error);
|
|
5496
|
+
}
|
|
5497
|
+
}
|
|
5498
|
+
async submitWithdraw(request, signatureInfo) {
|
|
5499
|
+
try {
|
|
5500
|
+
const result = await createLendingActor(this.canisterContext).withdraw(
|
|
5501
|
+
Principal.fromText(request.profileId),
|
|
5502
|
+
{
|
|
5503
|
+
data: {
|
|
5504
|
+
expiry_timestamp: request.expiryTimestamp,
|
|
5505
|
+
account: { External: request.receiverAddress },
|
|
5506
|
+
pool_id: Principal.fromText(request.poolId),
|
|
5507
|
+
amount: request.amount
|
|
5508
|
+
},
|
|
5509
|
+
signature_info: {
|
|
5510
|
+
Wallet: {
|
|
5511
|
+
signature: normalizeWalletSignature(
|
|
5512
|
+
signatureInfo.signature,
|
|
5513
|
+
signatureInfo.chain
|
|
5514
|
+
),
|
|
5515
|
+
chain: mapWalletChainToLendingChain(signatureInfo.chain),
|
|
5516
|
+
account: request.signerWalletAddress
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
);
|
|
5521
|
+
if ("Err" in result) {
|
|
5522
|
+
throw mapLendingProtocolErrorToLiquidiumError(result.Err);
|
|
5523
|
+
}
|
|
5524
|
+
return mapExpectedOutflowDetails(
|
|
5525
|
+
mapCanisterOutflowDetails(result.Ok),
|
|
5526
|
+
OutflowType.withdrawal,
|
|
5527
|
+
"withdraw"
|
|
5528
|
+
);
|
|
5529
|
+
} catch (error) {
|
|
5530
|
+
if (error instanceof LiquidiumError) {
|
|
5531
|
+
throw error;
|
|
5532
|
+
}
|
|
5533
|
+
throw mapCanisterCallErrorToLiquidiumError("withdraw", error);
|
|
5605
5534
|
}
|
|
5606
|
-
return txid;
|
|
5607
5535
|
}
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5536
|
+
/**
|
|
5537
|
+
* Creates a withdraw outflow using the provided wallet adapter.
|
|
5538
|
+
*
|
|
5539
|
+
* This is the convenience form of `prepareWithdraw(...)` plus execution.
|
|
5540
|
+
*
|
|
5541
|
+
* @param params - Withdraw request fields plus `signerChain` and `signerWalletAdapter`.
|
|
5542
|
+
* @returns The canister {@link OutflowDetails} for the completed withdraw.
|
|
5543
|
+
*/
|
|
5544
|
+
async withdraw(params) {
|
|
5545
|
+
const action = await this.prepareWithdraw(params);
|
|
5546
|
+
return await executeWith({
|
|
5547
|
+
walletAdapter: params.signerWalletAdapter,
|
|
5548
|
+
chain: params.signerChain,
|
|
5549
|
+
account: action.account
|
|
5550
|
+
})(action);
|
|
5616
5551
|
}
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5552
|
+
/**
|
|
5553
|
+
* Prepares a borrow action that can be signed and submitted later.
|
|
5554
|
+
*
|
|
5555
|
+
* Use this when you need explicit control over signing and submission.
|
|
5556
|
+
*
|
|
5557
|
+
* @param request - Profile, pool, amount (borrow asset base units), outflow address, and signer wallet.
|
|
5558
|
+
* @returns A signable {@link BorrowAction} with `submit` wired to the canister.
|
|
5559
|
+
*/
|
|
5560
|
+
async prepareBorrow(request) {
|
|
5561
|
+
const destinationAccount = request.receiverAddress.trim();
|
|
5562
|
+
const signerAccount = normalizeEvmAddress(
|
|
5563
|
+
request.signerWalletAddress.trim()
|
|
5564
|
+
);
|
|
5565
|
+
if (!destinationAccount) {
|
|
5620
5566
|
throw new LiquidiumError(
|
|
5621
5567
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5622
|
-
"
|
|
5568
|
+
"Borrow requires a custom outflow account"
|
|
5623
5569
|
);
|
|
5624
5570
|
}
|
|
5625
|
-
|
|
5626
|
-
if (!walletAddressInput) {
|
|
5571
|
+
if (!signerAccount) {
|
|
5627
5572
|
throw new LiquidiumError(
|
|
5628
5573
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5629
|
-
"
|
|
5574
|
+
"Borrow requires a signer account"
|
|
5630
5575
|
);
|
|
5631
5576
|
}
|
|
5632
|
-
|
|
5633
|
-
walletAddressInput,
|
|
5634
|
-
"Invalid EVM wallet address"
|
|
5635
|
-
);
|
|
5636
|
-
if (!request.amount || request.amount <= 0n) {
|
|
5577
|
+
if (request.amount <= 0n) {
|
|
5637
5578
|
throw new LiquidiumError(
|
|
5638
5579
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5639
|
-
"
|
|
5580
|
+
"Borrow amount must be greater than 0"
|
|
5640
5581
|
);
|
|
5641
5582
|
}
|
|
5642
|
-
const
|
|
5643
|
-
|
|
5583
|
+
const selectedPool = await this.getPoolById(request.poolId);
|
|
5584
|
+
const selectedAsset = selectedPool.asset;
|
|
5585
|
+
const minimumBorrowAmountError = getBorrowAmountMinimumValidationError({
|
|
5586
|
+
amount: request.amount,
|
|
5587
|
+
asset: selectedAsset
|
|
5588
|
+
});
|
|
5589
|
+
if (minimumBorrowAmountError) {
|
|
5644
5590
|
throw new LiquidiumError(
|
|
5645
5591
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5646
|
-
|
|
5592
|
+
minimumBorrowAmountError.message
|
|
5647
5593
|
);
|
|
5648
5594
|
}
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5595
|
+
const receiverAddress = normalizeExternalAddress({
|
|
5596
|
+
address: destinationAccount,
|
|
5597
|
+
asset: selectedAsset,
|
|
5598
|
+
chain: selectedPool.chain
|
|
5599
|
+
});
|
|
5600
|
+
const lendingActor = createLendingActor(this.canisterContext);
|
|
5601
|
+
try {
|
|
5602
|
+
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
5603
|
+
const nonce = await lendingActor.get_nonce(signerAccount);
|
|
5604
|
+
const borrowRequestData = {
|
|
5655
5605
|
profileId: request.profileId,
|
|
5656
5606
|
poolId: request.poolId,
|
|
5657
|
-
walletAddress,
|
|
5658
5607
|
amount: request.amount,
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5608
|
+
receiverAddress,
|
|
5609
|
+
signerWalletAddress: signerAccount,
|
|
5610
|
+
expiryTimestamp
|
|
5611
|
+
};
|
|
5612
|
+
return {
|
|
5613
|
+
kind: WalletActionKind.createBorrow,
|
|
5614
|
+
executionKind: WalletExecutionKind.signMessage,
|
|
5615
|
+
actionType: WalletActionKind.createBorrow,
|
|
5616
|
+
transferMode: TransferMode.native,
|
|
5617
|
+
account: signerAccount,
|
|
5618
|
+
message: createBorrowAssetMessage(
|
|
5619
|
+
{
|
|
5620
|
+
pool_id: request.poolId,
|
|
5621
|
+
amount: request.amount.toString(),
|
|
5622
|
+
account: { type: "External", data: receiverAddress },
|
|
5623
|
+
expiry_timestamp: expiryTimestamp
|
|
5624
|
+
},
|
|
5625
|
+
nonce
|
|
5626
|
+
),
|
|
5627
|
+
data: borrowRequestData,
|
|
5628
|
+
submit: async (signatureInfo) => {
|
|
5629
|
+
return await this.submitBorrow(borrowRequestData, signatureInfo);
|
|
5630
|
+
}
|
|
5631
|
+
};
|
|
5632
|
+
} catch (error) {
|
|
5633
|
+
if (error instanceof LiquidiumError) {
|
|
5634
|
+
throw error;
|
|
5635
|
+
}
|
|
5636
|
+
throw mapCanisterCallErrorToLiquidiumError("get_nonce", error);
|
|
5670
5637
|
}
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5638
|
+
}
|
|
5639
|
+
async submitBorrow(request, signatureInfo) {
|
|
5640
|
+
try {
|
|
5641
|
+
const result = await createLendingActor(
|
|
5642
|
+
this.canisterContext
|
|
5643
|
+
).borrow_assets(Principal.fromText(request.profileId), {
|
|
5644
|
+
data: {
|
|
5645
|
+
expiry_timestamp: request.expiryTimestamp,
|
|
5646
|
+
account: { External: request.receiverAddress },
|
|
5647
|
+
pool_id: Principal.fromText(request.poolId),
|
|
5648
|
+
amount: request.amount
|
|
5649
|
+
},
|
|
5650
|
+
signature_info: {
|
|
5651
|
+
Wallet: {
|
|
5652
|
+
signature: normalizeWalletSignature(
|
|
5653
|
+
signatureInfo.signature,
|
|
5654
|
+
signatureInfo.chain
|
|
5655
|
+
),
|
|
5656
|
+
chain: mapWalletChainToLendingChain(signatureInfo.chain),
|
|
5657
|
+
account: request.signerWalletAddress
|
|
5658
|
+
}
|
|
5659
|
+
}
|
|
5688
5660
|
});
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
spenderAddress: evmSupplyContext.spenderAddress,
|
|
5697
|
-
amount: MAX_UINT256
|
|
5698
|
-
}),
|
|
5699
|
-
`supply-${request.action}-approve-max`
|
|
5661
|
+
if ("Err" in result) {
|
|
5662
|
+
throw mapLendingProtocolErrorToLiquidiumError(result.Err);
|
|
5663
|
+
}
|
|
5664
|
+
return mapExpectedOutflowDetails(
|
|
5665
|
+
mapCanisterOutflowDetails(result.Ok),
|
|
5666
|
+
OutflowType.borrow,
|
|
5667
|
+
"borrow_assets"
|
|
5700
5668
|
);
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
expectation: "sufficient"
|
|
5707
|
-
});
|
|
5669
|
+
} catch (error) {
|
|
5670
|
+
if (error instanceof LiquidiumError) {
|
|
5671
|
+
throw error;
|
|
5672
|
+
}
|
|
5673
|
+
throw mapCanisterCallErrorToLiquidiumError("borrow_assets", error);
|
|
5708
5674
|
}
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5675
|
+
}
|
|
5676
|
+
/**
|
|
5677
|
+
* Creates a borrow outflow using the provided wallet adapter.
|
|
5678
|
+
*
|
|
5679
|
+
* This is the convenience form of `prepareBorrow(...)` plus execution.
|
|
5680
|
+
*
|
|
5681
|
+
* @param params - Borrow request fields plus `signerChain` and `signerWalletAdapter`.
|
|
5682
|
+
* @returns The lending canister receipt as {@link OutflowDetails}.
|
|
5683
|
+
*
|
|
5684
|
+
* @remarks
|
|
5685
|
+
* `id` is always present. `txid` may be missing on the first response; the SDK does not
|
|
5686
|
+
* poll for it. Use history or app-level polling if you need the chain transaction id.
|
|
5687
|
+
*/
|
|
5688
|
+
async borrow(params) {
|
|
5689
|
+
const action = await this.prepareBorrow(params);
|
|
5690
|
+
return await executeWith({
|
|
5691
|
+
walletAdapter: params.signerWalletAdapter,
|
|
5692
|
+
chain: params.signerChain,
|
|
5693
|
+
account: action.account
|
|
5694
|
+
})(action);
|
|
5695
|
+
}
|
|
5696
|
+
/**
|
|
5697
|
+
* Resolves a supply target for a deposit or repayment and optionally broadcasts it.
|
|
5698
|
+
*
|
|
5699
|
+
* Transfer mode can return manual broadcast instructions when wallet fields are
|
|
5700
|
+
* omitted. Contract-interaction mode always requires `walletAdapter`, `account`,
|
|
5701
|
+
* and `amount` because it must prepare and submit approval/deposit calls.
|
|
5702
|
+
*
|
|
5703
|
+
* The SDK does not poll for inflow status. When a `txid` is returned, it is the
|
|
5704
|
+
* caller's responsibility to track confirmation state using their own polling.
|
|
5705
|
+
*
|
|
5706
|
+
* @returns A {@link SupplyFlow} receipt with `type`, `target`, `submit`, and
|
|
5707
|
+
* an optional `txid` present when the SDK broadcast for you.
|
|
5708
|
+
*/
|
|
5709
|
+
async supply(request) {
|
|
5710
|
+
return await this.createSupplyFlowExecutor().create(request);
|
|
5711
|
+
}
|
|
5712
|
+
/**
|
|
5713
|
+
* Fetches ERC-20 supply planning data with the configured EVM read client.
|
|
5714
|
+
*
|
|
5715
|
+
* Requires `evmRpcUrl` or `evmPublicClient` on the client. Used internally by
|
|
5716
|
+
* contract-interaction `supply`.
|
|
5717
|
+
*
|
|
5718
|
+
* @param request - Profile, pool, wallet, amount (token base units), and action.
|
|
5719
|
+
* @returns Locally computed {@link EvmSupplyContext} for approvals and deposit.
|
|
5720
|
+
*/
|
|
5721
|
+
async getEvmSupplyContext(request) {
|
|
5722
|
+
return await this.createSupplyFlowExecutor().getEvmSupplyContext(request);
|
|
5723
|
+
}
|
|
5724
|
+
/**
|
|
5725
|
+
* Returns the read-only deposit address for an ETH stablecoin inflow target.
|
|
5726
|
+
*
|
|
5727
|
+
* This is a query call that does not create or mutate state. Use it when you
|
|
5728
|
+
* need the deposit address without hitting the authorization-gated update path.
|
|
5729
|
+
*
|
|
5730
|
+
* @param request - Profile, pool, asset, and supply action.
|
|
5731
|
+
* @returns The EVM deposit address for the derived account.
|
|
5732
|
+
*/
|
|
5733
|
+
async getDepositAddress(request) {
|
|
5734
|
+
if (!isEthStablecoin(request.asset, Chain.ETH)) {
|
|
5735
|
+
throw new LiquidiumError(
|
|
5736
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5737
|
+
"getDepositAddress is only supported for ETH stablecoins"
|
|
5738
|
+
);
|
|
5739
|
+
}
|
|
5740
|
+
const tokenAddress = getEthStablecoinContractAddress(request.asset);
|
|
5741
|
+
const subaccount = encodeInflowSubaccount({
|
|
5742
|
+
action: request.action,
|
|
5743
|
+
principal: Principal.fromText(request.profileId)
|
|
5744
|
+
});
|
|
5745
|
+
const result = await createDepositAccountsActor(
|
|
5746
|
+
this.canisterContext
|
|
5747
|
+
).get_deposit_address(
|
|
5748
|
+
{
|
|
5749
|
+
owner: Principal.fromText(request.poolId),
|
|
5750
|
+
subaccount: [subaccount]
|
|
5751
|
+
},
|
|
5752
|
+
[tokenAddress]
|
|
5722
5753
|
);
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
} catch {
|
|
5754
|
+
if ("Err" in result) {
|
|
5755
|
+
throw mapDepositAccountErrorToLiquidiumError(result.Err);
|
|
5726
5756
|
}
|
|
5727
|
-
return
|
|
5757
|
+
return result.Ok;
|
|
5728
5758
|
}
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
});
|
|
5746
|
-
}
|
|
5747
|
-
case Chain.ETH: {
|
|
5748
|
-
if (!params.walletAdapter.sendEthTransaction) {
|
|
5749
|
-
throw new LiquidiumError(
|
|
5750
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5751
|
-
"ETH wallet adapter does not support transaction sending"
|
|
5752
|
-
);
|
|
5753
|
-
}
|
|
5754
|
-
if (isEthStablecoin(params.asset, params.chain)) {
|
|
5755
|
-
return await params.walletAdapter.sendEthTransaction({
|
|
5756
|
-
chain: Chain.ETH,
|
|
5757
|
-
account: params.senderAccount,
|
|
5758
|
-
actionType: `supply-${params.action}`,
|
|
5759
|
-
transferMode: TransferMode.native,
|
|
5760
|
-
transaction: createTransferErc20Transaction({
|
|
5761
|
-
tokenAddress: getEthStablecoinContractAddress(params.asset),
|
|
5762
|
-
recipientAddress: params.toAddress,
|
|
5763
|
-
amount: params.amount
|
|
5764
|
-
})
|
|
5765
|
-
});
|
|
5766
|
-
}
|
|
5767
|
-
return await params.walletAdapter.sendEthTransaction({
|
|
5768
|
-
chain: Chain.ETH,
|
|
5769
|
-
account: params.senderAccount,
|
|
5770
|
-
actionType: `supply-${params.action}`,
|
|
5771
|
-
transferMode: TransferMode.native,
|
|
5772
|
-
transaction: {
|
|
5773
|
-
to: params.toAddress,
|
|
5774
|
-
value: params.amount.toString()
|
|
5775
|
-
}
|
|
5776
|
-
});
|
|
5759
|
+
/**
|
|
5760
|
+
* Estimates the network/deposit fee for an inflow target.
|
|
5761
|
+
*
|
|
5762
|
+
* ETH stablecoin deposit-address estimates are served by the deposit-address
|
|
5763
|
+
* canister. BTC estimates include the ckBTC minter deposit fee and ledger fee.
|
|
5764
|
+
*
|
|
5765
|
+
* @param request - Asset and chain pair to estimate for.
|
|
5766
|
+
* @returns Total fee estimate rounded up in the asset's base units.
|
|
5767
|
+
*/
|
|
5768
|
+
async estimateInflowFee(request) {
|
|
5769
|
+
if (isEthStablecoin(request.asset, request.chain)) {
|
|
5770
|
+
const result = await createDepositAccountsActor(
|
|
5771
|
+
this.canisterContext
|
|
5772
|
+
).estimate_deposit_fee([getEthStablecoinContractAddress(request.asset)]);
|
|
5773
|
+
if ("Err" in result) {
|
|
5774
|
+
throw mapDepositAccountErrorToLiquidiumError(result.Err);
|
|
5777
5775
|
}
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
`Native-address wallet execution is not supported for ${params.chain}`
|
|
5782
|
-
);
|
|
5776
|
+
return {
|
|
5777
|
+
totalFee: roundInflowFeeEstimate(request, result.Ok)
|
|
5778
|
+
};
|
|
5783
5779
|
}
|
|
5780
|
+
if (request.asset === Asset.BTC && request.chain === Chain.BTC) {
|
|
5781
|
+
const estimate = await this.estimateBtcInflowFee();
|
|
5782
|
+
return {
|
|
5783
|
+
totalFee: roundInflowFeeEstimate(request, estimate.totalFee)
|
|
5784
|
+
};
|
|
5785
|
+
}
|
|
5786
|
+
throw new LiquidiumError(
|
|
5787
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5788
|
+
`Inflow fee estimates are not supported for ${request.asset} on ${request.chain}`
|
|
5789
|
+
);
|
|
5784
5790
|
}
|
|
5785
|
-
async
|
|
5786
|
-
await
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
initialRetryDelayMs: SUBMIT_INFLOW_INITIAL_RETRY_DELAY_MS,
|
|
5792
|
-
backoffMultiplier: SUBMIT_INFLOW_RETRY_BACKOFF_MULTIPLIER,
|
|
5793
|
-
shouldRetryError: isRetriableInflowSubmitError
|
|
5794
|
-
});
|
|
5791
|
+
async estimateBtcInflowFee() {
|
|
5792
|
+
const [minterFee, ledgerFee] = await Promise.all([
|
|
5793
|
+
createCkBtcMinterActor(this.canisterContext).get_deposit_fee(),
|
|
5794
|
+
createCkBtcLedgerActor(this.canisterContext).icrc1_fee()
|
|
5795
|
+
]);
|
|
5796
|
+
return { totalFee: minterFee + ledgerFee };
|
|
5795
5797
|
}
|
|
5796
5798
|
/**
|
|
5797
5799
|
* Submits an inflow transaction id for faster indexing.
|
|
5798
5800
|
*
|
|
5799
5801
|
* Uses the Liquidium SDK API.
|
|
5800
5802
|
*
|
|
5801
|
-
* @param request - Broadcast `txid` plus
|
|
5803
|
+
* @param request - Broadcast `txid` plus inflow `operation` and optional `chain`.
|
|
5802
5804
|
* @returns Acknowledgement including the submitted `txid`.
|
|
5803
5805
|
*/
|
|
5804
5806
|
async submitInflow(request) {
|
|
5805
5807
|
const apiClient = this.requireApi();
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5808
|
+
const response = await apiClient.post(SdkApiPath.inflow, request);
|
|
5809
|
+
return {
|
|
5810
|
+
txid: response.txid
|
|
5811
|
+
};
|
|
5810
5812
|
}
|
|
5811
5813
|
/**
|
|
5812
5814
|
* Returns whether borrowing is currently disabled by the protocol.
|
|
@@ -5837,11 +5839,16 @@ var LendingModule = class {
|
|
|
5837
5839
|
}
|
|
5838
5840
|
return this.apiClient;
|
|
5839
5841
|
}
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5842
|
+
createSupplyFlowExecutor() {
|
|
5843
|
+
return new SupplyFlowExecutor({
|
|
5844
|
+
canisterContext: this.canisterContext,
|
|
5845
|
+
evmReadClient: this.evmReadClient,
|
|
5846
|
+
getPoolById: async (poolId) => await this.getPoolById(poolId),
|
|
5847
|
+
requireApi: () => {
|
|
5848
|
+
this.requireApi();
|
|
5849
|
+
},
|
|
5850
|
+
submitInflow: async (request) => await this.submitInflow(request)
|
|
5851
|
+
});
|
|
5845
5852
|
}
|
|
5846
5853
|
async getPoolById(poolId) {
|
|
5847
5854
|
const pools = await createFlexibleLendingActor(
|
|
@@ -5859,88 +5866,7 @@ var LendingModule = class {
|
|
|
5859
5866
|
}
|
|
5860
5867
|
return decodedPool;
|
|
5861
5868
|
}
|
|
5862
|
-
async normalizeOutflowReceiverAddress(params) {
|
|
5863
|
-
const selectedPool = await this.getPoolById(params.poolId);
|
|
5864
|
-
return normalizeExternalAddress({
|
|
5865
|
-
address: params.receiverAddress,
|
|
5866
|
-
asset: selectedPool.asset,
|
|
5867
|
-
chain: selectedPool.chain
|
|
5868
|
-
});
|
|
5869
|
-
}
|
|
5870
|
-
async sendEthContractTransaction(walletAdapter, walletAddress, request, actionType) {
|
|
5871
|
-
if (!walletAdapter.sendEthTransaction) {
|
|
5872
|
-
throw new LiquidiumError(
|
|
5873
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5874
|
-
"ETH wallet adapter does not support transaction sending"
|
|
5875
|
-
);
|
|
5876
|
-
}
|
|
5877
|
-
return await walletAdapter.sendEthTransaction({
|
|
5878
|
-
chain: Chain.ETH,
|
|
5879
|
-
account: walletAddress,
|
|
5880
|
-
actionType,
|
|
5881
|
-
transferMode: TransferMode.native,
|
|
5882
|
-
transaction: request
|
|
5883
|
-
});
|
|
5884
|
-
}
|
|
5885
|
-
async waitForExpectedAllowance(params) {
|
|
5886
|
-
const evmReadClient = this.requireEvmReadClient(
|
|
5887
|
-
"Contract-interaction supply requires an EVM RPC URL or public client"
|
|
5888
|
-
);
|
|
5889
|
-
let lastPollingError;
|
|
5890
|
-
for (let pollIndex = 0; pollIndex < ETH_APPROVAL_MAX_POLLS; pollIndex += 1) {
|
|
5891
|
-
try {
|
|
5892
|
-
const allowance = await readErc20Allowance({
|
|
5893
|
-
evmReadClient,
|
|
5894
|
-
tokenAddress: params.tokenAddress,
|
|
5895
|
-
ownerAddress: params.walletAddress,
|
|
5896
|
-
spenderAddress: params.spenderAddress
|
|
5897
|
-
});
|
|
5898
|
-
const matchesExpectation = params.expectation === "zero" ? allowance === 0n : allowance >= params.amount;
|
|
5899
|
-
if (matchesExpectation) {
|
|
5900
|
-
return;
|
|
5901
|
-
}
|
|
5902
|
-
} catch (error) {
|
|
5903
|
-
lastPollingError = error;
|
|
5904
|
-
}
|
|
5905
|
-
await delay(ETH_APPROVAL_POLL_INTERVAL_MS);
|
|
5906
|
-
}
|
|
5907
|
-
const lastPollingErrorMessage = getUnknownErrorMessage(lastPollingError);
|
|
5908
|
-
throw new LiquidiumError(
|
|
5909
|
-
LiquidiumErrorCode.SERVICE_UNAVAILABLE,
|
|
5910
|
-
lastPollingErrorMessage ? `Timed out waiting for ${params.expectation} ETH allowance update. Last polling error: ${lastPollingErrorMessage}` : `Timed out waiting for ${params.expectation} ETH allowance update`
|
|
5911
|
-
);
|
|
5912
|
-
}
|
|
5913
5869
|
};
|
|
5914
|
-
async function readErc20Allowance(params) {
|
|
5915
|
-
const allowance = await params.evmReadClient.readContract({
|
|
5916
|
-
address: params.tokenAddress,
|
|
5917
|
-
abi: ERC20_ABI,
|
|
5918
|
-
functionName: "allowance",
|
|
5919
|
-
args: [
|
|
5920
|
-
params.ownerAddress,
|
|
5921
|
-
params.spenderAddress
|
|
5922
|
-
]
|
|
5923
|
-
});
|
|
5924
|
-
return BigInt(allowance);
|
|
5925
|
-
}
|
|
5926
|
-
async function readErc20Balance(params) {
|
|
5927
|
-
const balance = await params.evmReadClient.readContract({
|
|
5928
|
-
address: params.tokenAddress,
|
|
5929
|
-
abi: ERC20_ABI,
|
|
5930
|
-
functionName: "balanceOf",
|
|
5931
|
-
args: [params.ownerAddress]
|
|
5932
|
-
});
|
|
5933
|
-
return BigInt(balance);
|
|
5934
|
-
}
|
|
5935
|
-
function getApprovalStrategy(params) {
|
|
5936
|
-
if (params.allowance >= params.amount) {
|
|
5937
|
-
return EvmSupplyApprovalStrategy.none;
|
|
5938
|
-
}
|
|
5939
|
-
if (params.allowance === 0n) {
|
|
5940
|
-
return EvmSupplyApprovalStrategy.approveMax;
|
|
5941
|
-
}
|
|
5942
|
-
return EvmSupplyApprovalStrategy.resetThenApproveMax;
|
|
5943
|
-
}
|
|
5944
5870
|
function mapExpectedOutflowDetails(details, expectedOutflowType, operation) {
|
|
5945
5871
|
if (details.outflowType !== expectedOutflowType) {
|
|
5946
5872
|
throw new LiquidiumError(
|
|
@@ -5948,42 +5874,22 @@ function mapExpectedOutflowDetails(details, expectedOutflowType, operation) {
|
|
|
5948
5874
|
`${operation} returned unexpected outflow type ${details.outflowType}`
|
|
5949
5875
|
);
|
|
5950
5876
|
}
|
|
5951
|
-
return details;
|
|
5952
|
-
}
|
|
5953
|
-
async function delay(timeoutMs) {
|
|
5954
|
-
await new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
5955
|
-
}
|
|
5956
|
-
function isRetriableInflowSubmitError(error) {
|
|
5957
|
-
if (!(error instanceof LiquidiumError)) {
|
|
5958
|
-
return false;
|
|
5959
|
-
}
|
|
5960
|
-
return error.code === LiquidiumErrorCode.SERVICE_UNAVAILABLE;
|
|
5961
|
-
}
|
|
5962
|
-
function getUnknownErrorMessage(error) {
|
|
5963
|
-
if (error instanceof Error) {
|
|
5964
|
-
return error.message;
|
|
5965
|
-
}
|
|
5966
|
-
if (typeof error === "string") {
|
|
5967
|
-
return error;
|
|
5968
|
-
}
|
|
5969
|
-
return null;
|
|
5970
|
-
}
|
|
5971
|
-
function getDefaultSubmitInflowRequest(params) {
|
|
5972
|
-
if (params.chain !== Chain.BTC && params.chain !== Chain.ETH) {
|
|
5973
|
-
return void 0;
|
|
5974
|
-
}
|
|
5975
5877
|
return {
|
|
5976
|
-
|
|
5977
|
-
|
|
5878
|
+
...details,
|
|
5879
|
+
status: createLiquidiumStatus({
|
|
5880
|
+
operation: mapOutflowTypeToStatusOperation(expectedOutflowType),
|
|
5881
|
+
state: details.txid ? "confirming" : "processing"
|
|
5882
|
+
})
|
|
5978
5883
|
};
|
|
5979
5884
|
}
|
|
5980
|
-
function
|
|
5981
|
-
|
|
5982
|
-
return true;
|
|
5983
|
-
}
|
|
5984
|
-
return !isEthStablecoin(params.instruction.asset, params.instruction.chain);
|
|
5885
|
+
function mapOutflowTypeToStatusOperation(outflowType) {
|
|
5886
|
+
return outflowType;
|
|
5985
5887
|
}
|
|
5986
5888
|
|
|
5889
|
+
// src/core/rates.ts
|
|
5890
|
+
var RATE_SCALE2 = 1000000000000000000000000000n;
|
|
5891
|
+
var RATE_DECIMALS = BigInt(RATE_SCALE2.toString().length - 1);
|
|
5892
|
+
|
|
5987
5893
|
// src/modules/market/mappers.ts
|
|
5988
5894
|
var DECIMAL_BASE = 10;
|
|
5989
5895
|
var PAIR_SEPARATOR = "_";
|
|
@@ -6055,23 +5961,22 @@ function formatPrice(price, decimals) {
|
|
|
6055
5961
|
// src/modules/market/market.ts
|
|
6056
5962
|
var ZERO_POOL_RATE = [0n, 0n, 0n];
|
|
6057
5963
|
var MarketModule = class {
|
|
6058
|
-
constructor(canisterContext
|
|
5964
|
+
constructor(canisterContext) {
|
|
6059
5965
|
this.canisterContext = canisterContext;
|
|
6060
|
-
this.apiClient = apiClient;
|
|
6061
5966
|
}
|
|
6062
5967
|
canisterContext;
|
|
6063
|
-
apiClient;
|
|
6064
5968
|
/**
|
|
6065
|
-
* Lists
|
|
5969
|
+
* Lists SDK-supported pools with their current rates.
|
|
6066
5970
|
*
|
|
6067
|
-
*
|
|
5971
|
+
* Unsupported asset or chain variants returned by the canister are omitted.
|
|
5972
|
+
*
|
|
5973
|
+
* @returns Supported lending pools enriched with their current rate data.
|
|
6068
5974
|
*/
|
|
6069
5975
|
async listPools() {
|
|
6070
|
-
void this.apiClient;
|
|
6071
5976
|
try {
|
|
6072
5977
|
const flexibleActor = createFlexibleLendingActor(this.canisterContext);
|
|
6073
5978
|
const rawPools = await flexibleActor.list_pools();
|
|
6074
|
-
const decodedPools = rawPools
|
|
5979
|
+
const decodedPools = decodeSupportedFlexiblePools(rawPools);
|
|
6075
5980
|
return await Promise.all(
|
|
6076
5981
|
decodedPools.map(async (pool) => {
|
|
6077
5982
|
const poolRate = await flexibleActor.get_pool_rate(pool.principal);
|
|
@@ -6178,6 +6083,17 @@ var MarketModule = class {
|
|
|
6178
6083
|
}
|
|
6179
6084
|
}
|
|
6180
6085
|
};
|
|
6086
|
+
function decodeSupportedFlexiblePools(rawPools) {
|
|
6087
|
+
const decodedPools = [];
|
|
6088
|
+
for (const rawPool of rawPools) {
|
|
6089
|
+
const decodedPool = decodeFlexiblePool(rawPool);
|
|
6090
|
+
if (!decodedPool) {
|
|
6091
|
+
continue;
|
|
6092
|
+
}
|
|
6093
|
+
decodedPools.push(decodedPool);
|
|
6094
|
+
}
|
|
6095
|
+
return decodedPools;
|
|
6096
|
+
}
|
|
6181
6097
|
|
|
6182
6098
|
// src/modules/positions/mappers.ts
|
|
6183
6099
|
var USD_VALUE_SCALE_DECIMALS = 27n;
|
|
@@ -6498,7 +6414,7 @@ var LiquidiumClient = class {
|
|
|
6498
6414
|
this.apiClient,
|
|
6499
6415
|
this.evmReadClient
|
|
6500
6416
|
);
|
|
6501
|
-
this.market = new MarketModule(this.canisterContext
|
|
6417
|
+
this.market = new MarketModule(this.canisterContext);
|
|
6502
6418
|
this.positions = new PositionsModule(this.canisterContext, this.market);
|
|
6503
6419
|
this.activities = new ActivitiesModule(
|
|
6504
6420
|
this.apiClient,
|
|
@@ -6508,6 +6424,7 @@ var LiquidiumClient = class {
|
|
|
6508
6424
|
this.instantLoans = new InstantLoansModule(
|
|
6509
6425
|
this.canisterContext,
|
|
6510
6426
|
this.apiClient,
|
|
6427
|
+
this.activities,
|
|
6511
6428
|
this.lending,
|
|
6512
6429
|
this.positions
|
|
6513
6430
|
);
|
|
@@ -6529,6 +6446,6 @@ function resolveEvmReadClient(config) {
|
|
|
6529
6446
|
});
|
|
6530
6447
|
}
|
|
6531
6448
|
|
|
6532
|
-
export { AccountsModule, ActivitiesModule,
|
|
6449
|
+
export { AccountsModule, ActivitiesModule, ActivityFilter, Asset, CK_ETH_DEPOSIT_CONTRACT_ADDRESS, Chain, Environment, EvmSupplyApprovalStrategy, HistoryModule, InstantLoansModule, LendingModule, LiquidiumClient, LiquidiumError, LiquidiumErrorCode, MIN_BORROW_AMOUNTS_BY_ASSET, MIN_WITHDRAW_AMOUNTS_BY_ASSET, MarketModule, OutflowType, PositionsModule, QuoteModule, QuoteValidationErrorCode, QuoteWarningCode, RATE_DECIMALS, RATE_SCALE2 as RATE_SCALE, SupplyAction, SupplyPlanType, TransferMode, USDC_CONTRACT_ADDRESS, USDT_CONTRACT_ADDRESS, WalletActionKind, WalletExecutionKind, createTransferErc20Transaction, executeWith, getMinimumBorrowAmount, getMinimumWithdrawAmount, intFromPublicId, publicIdFromInt };
|
|
6533
6450
|
//# sourceMappingURL=index.js.map
|
|
6534
6451
|
//# sourceMappingURL=index.js.map
|