@liquidium/client 0.4.1 → 0.5.0-rc.0
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 +75 -48
- package/dist/index.cjs +1088 -413
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +327 -275
- package/dist/index.d.ts +327 -275
- package/dist/index.js +1087 -414
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,60 +4,12 @@ import { Actor, HttpAgent } from '@icp-sdk/core/agent';
|
|
|
4
4
|
import { Principal } from '@icp-sdk/core/principal';
|
|
5
5
|
import { base64, base64nopad } from '@scure/base';
|
|
6
6
|
import { idlLabelToId } from '@icp-sdk/core/candid';
|
|
7
|
-
import {
|
|
7
|
+
import { AccountIdentifier, SubAccount } from '@icp-sdk/canisters/ledger/icp';
|
|
8
|
+
import { decodeIcrcAccount, encodeIcrcAccount } from '@icp-sdk/canisters/ledger/icrc';
|
|
8
9
|
import { validate, Network } from 'bitcoin-address-validation';
|
|
9
10
|
|
|
10
11
|
// src/client.ts
|
|
11
12
|
|
|
12
|
-
// src/core/types.ts
|
|
13
|
-
var Environment = {
|
|
14
|
-
mainnet: "mainnet"
|
|
15
|
-
};
|
|
16
|
-
var Asset = {
|
|
17
|
-
BTC: "BTC",
|
|
18
|
-
SOL: "SOL",
|
|
19
|
-
USDC: "USDC",
|
|
20
|
-
USDT: "USDT"
|
|
21
|
-
};
|
|
22
|
-
var Chain = {
|
|
23
|
-
BTC: "BTC",
|
|
24
|
-
ETH: "ETH"
|
|
25
|
-
};
|
|
26
|
-
var SupplyAction = {
|
|
27
|
-
deposit: "deposit",
|
|
28
|
-
repayment: "repayment"
|
|
29
|
-
};
|
|
30
|
-
var OutflowType = {
|
|
31
|
-
borrow: "borrow",
|
|
32
|
-
feeClaim: "feeClaim",
|
|
33
|
-
withdrawal: "withdrawal"
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// src/core/config.ts
|
|
37
|
-
var MAINNET_HOST = "https://icp-api.io";
|
|
38
|
-
var DEFAULT_API_BASE_URL = "https://app.liquidium.fi/api/sdk";
|
|
39
|
-
var DEFAULT_ENVIRONMENT = Environment.mainnet;
|
|
40
|
-
var MAINNET_CANISTER_IDS = {
|
|
41
|
-
lending: "hyk4r-jqaaa-aaaar-qb4ca-cai",
|
|
42
|
-
btcPool: "hkmli-faaaa-aaaar-qb4ba-cai",
|
|
43
|
-
ercPool: "hnnn4-iyaaa-aaaar-qb4bq-cai",
|
|
44
|
-
ethDeposit: "z5jz7-nyaaa-aaaar-qb6pq-cai",
|
|
45
|
-
instantLoans: "u5rm3-niaaa-aaaar-qb7eq-cai"
|
|
46
|
-
};
|
|
47
|
-
var CANISTER_IDS_BY_ENVIRONMENT = {
|
|
48
|
-
mainnet: MAINNET_CANISTER_IDS
|
|
49
|
-
};
|
|
50
|
-
function resolveHost(override) {
|
|
51
|
-
return override ?? MAINNET_HOST;
|
|
52
|
-
}
|
|
53
|
-
function resolveCanisterIds(environment = DEFAULT_ENVIRONMENT, overrides) {
|
|
54
|
-
return { ...CANISTER_IDS_BY_ENVIRONMENT[environment], ...overrides };
|
|
55
|
-
}
|
|
56
|
-
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
57
|
-
var CK_CANISTER_IDS = {
|
|
58
|
-
btcMinter: "mqygn-kiaaa-aaaar-qaadq-cai",
|
|
59
|
-
btcLedger: "mxzaz-hqaaa-aaaar-qaada-cai"};
|
|
60
|
-
|
|
61
13
|
// src/core/errors.ts
|
|
62
14
|
var LiquidiumErrorCode = {
|
|
63
15
|
// Protocol errors
|
|
@@ -128,6 +80,127 @@ var LiquidiumError = class extends Error {
|
|
|
128
80
|
}
|
|
129
81
|
};
|
|
130
82
|
|
|
83
|
+
// src/core/types.ts
|
|
84
|
+
var Environment = {
|
|
85
|
+
mainnet: "mainnet"
|
|
86
|
+
};
|
|
87
|
+
var Asset = {
|
|
88
|
+
BTC: "BTC",
|
|
89
|
+
ICP: "ICP",
|
|
90
|
+
USDC: "USDC",
|
|
91
|
+
USDT: "USDT"
|
|
92
|
+
};
|
|
93
|
+
var Chain = {
|
|
94
|
+
BTC: "BTC",
|
|
95
|
+
ETH: "ETH",
|
|
96
|
+
ICP: "ICP"
|
|
97
|
+
};
|
|
98
|
+
function isAssetIdentifier(identifier) {
|
|
99
|
+
switch (identifier.chain) {
|
|
100
|
+
case Chain.BTC:
|
|
101
|
+
return identifier.asset === Asset.BTC;
|
|
102
|
+
case Chain.ETH:
|
|
103
|
+
return identifier.asset === Asset.USDC || identifier.asset === Asset.USDT;
|
|
104
|
+
case Chain.ICP:
|
|
105
|
+
return identifier.asset === Asset.BTC || identifier.asset === Asset.ICP || identifier.asset === Asset.USDC || identifier.asset === Asset.USDT;
|
|
106
|
+
default:
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
var SupplyAction = {
|
|
111
|
+
deposit: "deposit",
|
|
112
|
+
repayment: "repayment"
|
|
113
|
+
};
|
|
114
|
+
var OutflowType = {
|
|
115
|
+
borrow: "borrow",
|
|
116
|
+
feeClaim: "feeClaim",
|
|
117
|
+
withdrawal: "withdrawal"
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// src/core/config.ts
|
|
121
|
+
var MAINNET_HOST = "https://icp-api.io";
|
|
122
|
+
var DEFAULT_API_BASE_URL = "https://app.liquidium.fi/api/sdk";
|
|
123
|
+
var DEFAULT_ENVIRONMENT = Environment.mainnet;
|
|
124
|
+
var MAINNET_CANISTER_IDS = {
|
|
125
|
+
lending: "hyk4r-jqaaa-aaaar-qb4ca-cai",
|
|
126
|
+
pools: {
|
|
127
|
+
btc: "hkmli-faaaa-aaaar-qb4ba-cai",
|
|
128
|
+
usdt: "hnnn4-iyaaa-aaaar-qb4bq-cai",
|
|
129
|
+
usdc: "6sna2-oiaaa-aaaar-qb66q-cai",
|
|
130
|
+
icp: "r2pk3-4yaaa-aaaar-qb7zq-cai"
|
|
131
|
+
},
|
|
132
|
+
ethDeposit: "z5jz7-nyaaa-aaaar-qb6pq-cai",
|
|
133
|
+
instantLoans: "u5rm3-niaaa-aaaar-qb7eq-cai"
|
|
134
|
+
};
|
|
135
|
+
var CANISTER_IDS_BY_ENVIRONMENT = {
|
|
136
|
+
mainnet: MAINNET_CANISTER_IDS
|
|
137
|
+
};
|
|
138
|
+
var SUPPORTED_CANISTER_ID_OVERRIDE_KEYS = /* @__PURE__ */ new Set([
|
|
139
|
+
"lending",
|
|
140
|
+
"pools",
|
|
141
|
+
"ethDeposit",
|
|
142
|
+
"instantLoans"
|
|
143
|
+
]);
|
|
144
|
+
var SUPPORTED_POOL_CANISTER_ID_OVERRIDE_KEYS = /* @__PURE__ */ new Set([
|
|
145
|
+
"btc",
|
|
146
|
+
"usdt",
|
|
147
|
+
"usdc",
|
|
148
|
+
"icp"
|
|
149
|
+
]);
|
|
150
|
+
function resolveHost(override) {
|
|
151
|
+
return override ?? MAINNET_HOST;
|
|
152
|
+
}
|
|
153
|
+
function resolveCanisterIds(environment = DEFAULT_ENVIRONMENT, overrides) {
|
|
154
|
+
const defaults = CANISTER_IDS_BY_ENVIRONMENT[environment];
|
|
155
|
+
validateCanisterIdOverrides(overrides);
|
|
156
|
+
const pools = {
|
|
157
|
+
...defaults.pools,
|
|
158
|
+
...overrides?.pools
|
|
159
|
+
};
|
|
160
|
+
return {
|
|
161
|
+
lending: overrides?.lending ?? defaults.lending,
|
|
162
|
+
pools,
|
|
163
|
+
ethDeposit: overrides?.ethDeposit ?? defaults.ethDeposit,
|
|
164
|
+
instantLoans: overrides?.instantLoans ?? defaults.instantLoans
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function validateCanisterIdOverrides(overrides) {
|
|
168
|
+
if (!overrides) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (const key of Object.keys(overrides)) {
|
|
172
|
+
if (!SUPPORTED_CANISTER_ID_OVERRIDE_KEYS.has(key)) {
|
|
173
|
+
throw new LiquidiumError(
|
|
174
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
175
|
+
`Unsupported canisterIds override: ${key}`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (!overrides.pools) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
for (const key of Object.keys(overrides.pools)) {
|
|
183
|
+
if (!SUPPORTED_POOL_CANISTER_ID_OVERRIDE_KEYS.has(key)) {
|
|
184
|
+
throw new LiquidiumError(
|
|
185
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
186
|
+
`Unsupported canisterIds.pools override: ${key}`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
192
|
+
var CK_CANISTER_IDS = {
|
|
193
|
+
BTC: {
|
|
194
|
+
minter: "mqygn-kiaaa-aaaar-qaadq-cai",
|
|
195
|
+
ledger: "mxzaz-hqaaa-aaaar-qaada-cai"},
|
|
196
|
+
USDT: {
|
|
197
|
+
ledger: "cngnf-vqaaa-aaaar-qag4q-cai"},
|
|
198
|
+
USDC: {
|
|
199
|
+
ledger: "xevnm-gaaaa-aaaar-qafnq-cai"},
|
|
200
|
+
ICP: {
|
|
201
|
+
ledger: "ryjl3-tyaaa-aaaaa-aaaba-cai"}
|
|
202
|
+
};
|
|
203
|
+
|
|
131
204
|
// src/core/transports/api-client.ts
|
|
132
205
|
var DOM_EXCEPTION_ABORT_ERROR_NAME = "AbortError";
|
|
133
206
|
var HTTP_HEADER_CONTENT_TYPE = "content-type";
|
|
@@ -981,9 +1054,6 @@ function getVariantKey(variant) {
|
|
|
981
1054
|
}
|
|
982
1055
|
|
|
983
1056
|
// src/core/wallet-actions.ts
|
|
984
|
-
var TransferMode = {
|
|
985
|
-
native: "native"
|
|
986
|
-
};
|
|
987
1057
|
var WalletExecutionKind = {
|
|
988
1058
|
signMessage: "sign-message"
|
|
989
1059
|
};
|
|
@@ -1014,8 +1084,7 @@ function executeWith(options) {
|
|
|
1014
1084
|
chain: options.chain,
|
|
1015
1085
|
message: action.message,
|
|
1016
1086
|
account: options.account ?? action.account,
|
|
1017
|
-
actionType: action.actionType
|
|
1018
|
-
transferMode: action.transferMode
|
|
1087
|
+
actionType: action.actionType
|
|
1019
1088
|
});
|
|
1020
1089
|
return action.submit({
|
|
1021
1090
|
signature,
|
|
@@ -1238,7 +1307,6 @@ var AccountsModule = class {
|
|
|
1238
1307
|
kind: WalletActionKind.createAccount,
|
|
1239
1308
|
executionKind: WalletExecutionKind.signMessage,
|
|
1240
1309
|
actionType: WalletActionKind.createAccount,
|
|
1241
|
-
transferMode: TransferMode.native,
|
|
1242
1310
|
account: normalizedAccount,
|
|
1243
1311
|
message: createInitializeAccountMessage(expiryTimestamp, nonce),
|
|
1244
1312
|
data: {
|
|
@@ -1329,8 +1397,8 @@ function mapCanisterWalletToWallet(canisterWallet) {
|
|
|
1329
1397
|
);
|
|
1330
1398
|
}
|
|
1331
1399
|
}
|
|
1332
|
-
var KNOWN_ASSET_TAGS = ["BTC", "USDC", "USDT"];
|
|
1333
|
-
var KNOWN_CHAIN_TAGS = ["BTC", "ETH"];
|
|
1400
|
+
var KNOWN_ASSET_TAGS = ["BTC", "ICP", "USDC", "USDT"];
|
|
1401
|
+
var KNOWN_CHAIN_TAGS = ["BTC", "ETH", "ICP"];
|
|
1334
1402
|
function extractVariantTag(variant, knownTags) {
|
|
1335
1403
|
const [key] = Object.keys(variant);
|
|
1336
1404
|
if (!key) {
|
|
@@ -1909,17 +1977,14 @@ function mapInstantLoanLookupError(error) {
|
|
|
1909
1977
|
}
|
|
1910
1978
|
function mapActivity(wire) {
|
|
1911
1979
|
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
|
|
1919
|
-
};
|
|
1920
1980
|
if (isInflowOperation(wire.status.operation)) {
|
|
1921
1981
|
const activity = {
|
|
1922
|
-
|
|
1982
|
+
id: wire.id,
|
|
1983
|
+
poolId: wire.poolId,
|
|
1984
|
+
asset: wire.asset,
|
|
1985
|
+
chain: wire.chain,
|
|
1986
|
+
amount,
|
|
1987
|
+
timestampMs: wire.timestampMs,
|
|
1923
1988
|
status: wire.status
|
|
1924
1989
|
};
|
|
1925
1990
|
if (wire.txids) {
|
|
@@ -1932,7 +1997,12 @@ function mapActivity(wire) {
|
|
|
1932
1997
|
}
|
|
1933
1998
|
if (isOutflowOperation(wire.status.operation)) {
|
|
1934
1999
|
const activity = {
|
|
1935
|
-
|
|
2000
|
+
id: wire.id,
|
|
2001
|
+
poolId: wire.poolId,
|
|
2002
|
+
asset: wire.asset,
|
|
2003
|
+
chain: wire.chain,
|
|
2004
|
+
amount,
|
|
2005
|
+
timestampMs: wire.timestampMs,
|
|
1936
2006
|
status: wire.status
|
|
1937
2007
|
};
|
|
1938
2008
|
if (wire.txids) {
|
|
@@ -2108,6 +2178,72 @@ function validateHistoryStateFilter(state) {
|
|
|
2108
2178
|
);
|
|
2109
2179
|
}
|
|
2110
2180
|
}
|
|
2181
|
+
var LiquidiumAccountType = {
|
|
2182
|
+
ChainAddress: "ChainAddress",
|
|
2183
|
+
IcPrincipal: "IcPrincipal",
|
|
2184
|
+
IcpAccountIdentifier: "IcpAccountIdentifier",
|
|
2185
|
+
IcrcAccount: "IcrcAccount"
|
|
2186
|
+
};
|
|
2187
|
+
function createIcrcAccount(params) {
|
|
2188
|
+
return {
|
|
2189
|
+
type: "IcrcAccount",
|
|
2190
|
+
owner: params.owner.toText(),
|
|
2191
|
+
subaccount: params.subaccount,
|
|
2192
|
+
address: encodeIcrcAccount({
|
|
2193
|
+
owner: params.owner,
|
|
2194
|
+
subaccount: params.subaccount
|
|
2195
|
+
})
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
function mapCanisterAccountToLiquidiumAccount(account) {
|
|
2199
|
+
if ("Native" in account) {
|
|
2200
|
+
return { type: "IcPrincipal", address: account.Native.toText() };
|
|
2201
|
+
}
|
|
2202
|
+
if ("AccountIdentifier" in account) {
|
|
2203
|
+
return {
|
|
2204
|
+
type: "IcpAccountIdentifier",
|
|
2205
|
+
address: account.AccountIdentifier
|
|
2206
|
+
};
|
|
2207
|
+
}
|
|
2208
|
+
if ("Icrc" in account) {
|
|
2209
|
+
const subaccount = normalizeOptionalSubaccount(account.Icrc.subaccount[0]);
|
|
2210
|
+
return {
|
|
2211
|
+
type: "IcrcAccount",
|
|
2212
|
+
owner: account.Icrc.owner.toText(),
|
|
2213
|
+
subaccount,
|
|
2214
|
+
address: encodeIcrcAccount({
|
|
2215
|
+
owner: account.Icrc.owner,
|
|
2216
|
+
subaccount
|
|
2217
|
+
})
|
|
2218
|
+
};
|
|
2219
|
+
}
|
|
2220
|
+
return { type: "ChainAddress", address: account.External };
|
|
2221
|
+
}
|
|
2222
|
+
function decodeIcrcAccountAddress(address) {
|
|
2223
|
+
const decoded = decodeIcrcAccount(address);
|
|
2224
|
+
const owner = Principal.fromText(decoded.owner.toText());
|
|
2225
|
+
const subaccount = decoded.subaccount ? Uint8Array.from(decoded.subaccount) : void 0;
|
|
2226
|
+
return {
|
|
2227
|
+
owner,
|
|
2228
|
+
subaccount,
|
|
2229
|
+
account: createIcrcAccount({ owner, subaccount })
|
|
2230
|
+
};
|
|
2231
|
+
}
|
|
2232
|
+
function encodeIcpAccountIdentifier(params) {
|
|
2233
|
+
return AccountIdentifier.fromPrincipal({
|
|
2234
|
+
principal: params.owner,
|
|
2235
|
+
subAccount: params.subaccount ? SubAccount.fromBytes(params.subaccount) : void 0
|
|
2236
|
+
}).toHex();
|
|
2237
|
+
}
|
|
2238
|
+
function normalizeIcpAccountIdentifier(address) {
|
|
2239
|
+
return AccountIdentifier.fromHex(address).toHex();
|
|
2240
|
+
}
|
|
2241
|
+
function normalizeOptionalSubaccount(subaccount) {
|
|
2242
|
+
if (!subaccount) {
|
|
2243
|
+
return void 0;
|
|
2244
|
+
}
|
|
2245
|
+
return subaccount instanceof Uint8Array ? subaccount : Uint8Array.from(subaccount);
|
|
2246
|
+
}
|
|
2111
2247
|
|
|
2112
2248
|
// src/core/status.ts
|
|
2113
2249
|
function createLiquidiumStatus(params) {
|
|
@@ -2157,6 +2293,7 @@ function throwInvalidApiResponseField(field) {
|
|
|
2157
2293
|
// src/core/utils/asset-decimals.ts
|
|
2158
2294
|
var ASSET_NATIVE_DECIMALS = {
|
|
2159
2295
|
BTC: 8n,
|
|
2296
|
+
ICP: 8n,
|
|
2160
2297
|
USDC: 6n,
|
|
2161
2298
|
USDT: 6n,
|
|
2162
2299
|
SOL: 9n
|
|
@@ -2552,7 +2689,7 @@ var idlFactory2 = ({ IDL }) => {
|
|
|
2552
2689
|
|
|
2553
2690
|
// src/core/canisters/ckbtc/minter.ts
|
|
2554
2691
|
function createCkBtcMinterActor(canisterContext) {
|
|
2555
|
-
const canisterId = CK_CANISTER_IDS.
|
|
2692
|
+
const canisterId = CK_CANISTER_IDS.BTC.minter;
|
|
2556
2693
|
return Actor.createActor(idlFactory2, {
|
|
2557
2694
|
agent: canisterContext.agent,
|
|
2558
2695
|
canisterId
|
|
@@ -3003,55 +3140,43 @@ var EvmSupplyApprovalStrategy = {
|
|
|
3003
3140
|
};
|
|
3004
3141
|
|
|
3005
3142
|
// src/modules/lending/_internal/supply-targets.ts
|
|
3006
|
-
async function
|
|
3007
|
-
const
|
|
3008
|
-
|
|
3009
|
-
|
|
3143
|
+
async function resolveSupplyTargetForPool(canisterContext, request, selectedPool) {
|
|
3144
|
+
const identifier = resolveSupplyAssetIdentifier({
|
|
3145
|
+
asset: selectedPool.asset,
|
|
3146
|
+
poolChain: selectedPool.chain,
|
|
3147
|
+
transferChain: request.chain ?? selectedPool.chain
|
|
3148
|
+
});
|
|
3010
3149
|
const mechanism = resolveSupplyMechanism({
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
requestedMechanism: request.mechanism
|
|
3150
|
+
identifier,
|
|
3151
|
+
mechanism: request.mechanism
|
|
3014
3152
|
});
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
asset,
|
|
3023
|
-
chain,
|
|
3024
|
-
action: request.action
|
|
3025
|
-
}
|
|
3026
|
-
);
|
|
3027
|
-
case SupplyPlanType.contractInteraction:
|
|
3028
|
-
return getIcrcAccountSupplyTarget(request.profileId, {
|
|
3029
|
-
poolId: request.poolId,
|
|
3030
|
-
asset,
|
|
3031
|
-
chain,
|
|
3032
|
-
action: request.action
|
|
3033
|
-
});
|
|
3153
|
+
const targetRequest = {
|
|
3154
|
+
...identifier,
|
|
3155
|
+
poolId: request.poolId,
|
|
3156
|
+
action: request.action
|
|
3157
|
+
};
|
|
3158
|
+
if (mechanism === SupplyPlanType.contractInteraction) {
|
|
3159
|
+
return getIcrcAccountSupplyTarget(request.profileId, targetRequest);
|
|
3034
3160
|
}
|
|
3161
|
+
if (identifier.chain === Chain.ICP) {
|
|
3162
|
+
return identifier.asset === Asset.ICP ? getIcpLedgerSupplyTarget(request.profileId, targetRequest) : getIcrcAccountSupplyTarget(request.profileId, targetRequest);
|
|
3163
|
+
}
|
|
3164
|
+
return await getChainAddressSupplyTarget(
|
|
3165
|
+
canisterContext,
|
|
3166
|
+
request.profileId,
|
|
3167
|
+
targetRequest
|
|
3168
|
+
);
|
|
3035
3169
|
}
|
|
3036
3170
|
function resolveSupplyMechanism(params) {
|
|
3037
|
-
if (params.
|
|
3038
|
-
if (params.requestedMechanism === SupplyPlanType.contractInteraction) {
|
|
3039
|
-
throw new LiquidiumError(
|
|
3040
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3041
|
-
"Contract-interaction supply is not supported for BTC on BTC"
|
|
3042
|
-
);
|
|
3043
|
-
}
|
|
3171
|
+
if (params.mechanism !== SupplyPlanType.contractInteraction) {
|
|
3044
3172
|
return SupplyPlanType.transfer;
|
|
3045
3173
|
}
|
|
3046
|
-
if (
|
|
3047
|
-
|
|
3048
|
-
return params.requestedMechanism;
|
|
3049
|
-
}
|
|
3050
|
-
return SupplyPlanType.transfer;
|
|
3174
|
+
if (params.identifier.chain === Chain.ETH && (params.identifier.asset === Asset.USDC || params.identifier.asset === Asset.USDT)) {
|
|
3175
|
+
return SupplyPlanType.contractInteraction;
|
|
3051
3176
|
}
|
|
3052
3177
|
throw new LiquidiumError(
|
|
3053
3178
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3054
|
-
`
|
|
3179
|
+
`Contract-interaction supply is not supported for ${params.identifier.asset} on ${params.identifier.chain}`
|
|
3055
3180
|
);
|
|
3056
3181
|
}
|
|
3057
3182
|
function isEthStablecoin(asset, chain) {
|
|
@@ -3123,9 +3248,33 @@ async function getPoolById(canisterContext, poolId) {
|
|
|
3123
3248
|
}
|
|
3124
3249
|
return decodedPool;
|
|
3125
3250
|
}
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3251
|
+
function resolveSupplyAssetIdentifier(params) {
|
|
3252
|
+
if (params.asset === Asset.BTC && params.poolChain === Chain.BTC) {
|
|
3253
|
+
if (params.transferChain === Chain.BTC) {
|
|
3254
|
+
return { asset: Asset.BTC, chain: Chain.BTC };
|
|
3255
|
+
}
|
|
3256
|
+
if (params.transferChain === Chain.ICP) {
|
|
3257
|
+
return { asset: Asset.BTC, chain: Chain.ICP };
|
|
3258
|
+
}
|
|
3259
|
+
}
|
|
3260
|
+
if ((params.asset === Asset.USDC || params.asset === Asset.USDT) && params.poolChain === Chain.ETH) {
|
|
3261
|
+
if (params.transferChain === Chain.ETH) {
|
|
3262
|
+
return { asset: params.asset, chain: Chain.ETH };
|
|
3263
|
+
}
|
|
3264
|
+
if (params.transferChain === Chain.ICP) {
|
|
3265
|
+
return { asset: params.asset, chain: Chain.ICP };
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
if (params.asset === Asset.ICP && params.poolChain === Chain.ICP && params.transferChain === Chain.ICP) {
|
|
3269
|
+
return { asset: Asset.ICP, chain: Chain.ICP };
|
|
3270
|
+
}
|
|
3271
|
+
throw new LiquidiumError(
|
|
3272
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3273
|
+
`Supply is not supported for ${params.asset} pool on ${params.poolChain} using ${params.transferChain}`
|
|
3274
|
+
);
|
|
3275
|
+
}
|
|
3276
|
+
async function getChainAddressSupplyTarget(canisterContext, profileId, request) {
|
|
3277
|
+
if (request.chain === Chain.ETH) {
|
|
3129
3278
|
const tokenAddress = getEthStablecoinContractAddress(request.asset);
|
|
3130
3279
|
const subaccount2 = encodeInflowSubaccount({
|
|
3131
3280
|
action: request.action,
|
|
@@ -3144,7 +3293,6 @@ async function getNativeAddressSupplyTarget(canisterContext, profileId, request)
|
|
|
3144
3293
|
throw mapDepositAccountErrorToLiquidiumError(result.Err);
|
|
3145
3294
|
}
|
|
3146
3295
|
return {
|
|
3147
|
-
type: "nativeAddress",
|
|
3148
3296
|
poolId: request.poolId,
|
|
3149
3297
|
asset: request.asset,
|
|
3150
3298
|
chain: request.chain,
|
|
@@ -3152,11 +3300,11 @@ async function getNativeAddressSupplyTarget(canisterContext, profileId, request)
|
|
|
3152
3300
|
address: result.Ok
|
|
3153
3301
|
};
|
|
3154
3302
|
}
|
|
3155
|
-
const configuredBtcPoolId = canisterContext.canisterIds.
|
|
3303
|
+
const configuredBtcPoolId = canisterContext.canisterIds.pools.btc;
|
|
3156
3304
|
if (request.poolId !== configuredBtcPoolId) {
|
|
3157
3305
|
throw new LiquidiumError(
|
|
3158
3306
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3159
|
-
`
|
|
3307
|
+
`Chain-address BTC inflow targets require the configured BTC pool ${configuredBtcPoolId}, received ${request.poolId}`
|
|
3160
3308
|
);
|
|
3161
3309
|
}
|
|
3162
3310
|
const subaccount = encodeInflowSubaccount({
|
|
@@ -3169,56 +3317,42 @@ async function getNativeAddressSupplyTarget(canisterContext, profileId, request)
|
|
|
3169
3317
|
subaccount: [subaccount]
|
|
3170
3318
|
}
|
|
3171
3319
|
);
|
|
3172
|
-
return {
|
|
3173
|
-
type: "nativeAddress",
|
|
3174
|
-
poolId: request.poolId,
|
|
3175
|
-
asset: request.asset,
|
|
3176
|
-
chain: request.chain,
|
|
3177
|
-
action: request.action,
|
|
3178
|
-
address
|
|
3179
|
-
};
|
|
3320
|
+
return { ...request, address };
|
|
3180
3321
|
}
|
|
3181
3322
|
function getIcrcAccountSupplyTarget(profileId, request) {
|
|
3182
|
-
|
|
3323
|
+
const account = createInflowIcrcAccount(profileId, request);
|
|
3324
|
+
return { ...request, address: account.address };
|
|
3325
|
+
}
|
|
3326
|
+
function getIcpLedgerSupplyTarget(profileId, request) {
|
|
3183
3327
|
const poolPrincipal = Principal.fromText(request.poolId);
|
|
3184
3328
|
const subaccount = encodeInflowSubaccount({
|
|
3185
3329
|
action: request.action,
|
|
3186
3330
|
principal: Principal.fromText(profileId)
|
|
3187
3331
|
});
|
|
3332
|
+
const account = createIcrcAccount({
|
|
3333
|
+
owner: poolPrincipal,
|
|
3334
|
+
subaccount
|
|
3335
|
+
});
|
|
3188
3336
|
return {
|
|
3189
|
-
type: "icrcAccount",
|
|
3190
3337
|
poolId: request.poolId,
|
|
3191
|
-
asset:
|
|
3192
|
-
chain:
|
|
3338
|
+
asset: Asset.ICP,
|
|
3339
|
+
chain: Chain.ICP,
|
|
3193
3340
|
action: request.action,
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
account: encodeIcrcAccount({
|
|
3341
|
+
address: account.address,
|
|
3342
|
+
icpAccountIdentifier: encodeIcpAccountIdentifier({
|
|
3197
3343
|
owner: poolPrincipal,
|
|
3198
3344
|
subaccount
|
|
3199
3345
|
})
|
|
3200
3346
|
};
|
|
3201
3347
|
}
|
|
3202
|
-
function
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3211
|
-
`Native address inflow targets are not supported for ${asset} on ${chain}`
|
|
3212
|
-
);
|
|
3213
|
-
}
|
|
3214
|
-
function assertSupportsIcrcAccountInflowTarget(asset) {
|
|
3215
|
-
if (asset === Asset.BTC || asset === Asset.USDT || asset === Asset.USDC) {
|
|
3216
|
-
return;
|
|
3217
|
-
}
|
|
3218
|
-
throw new LiquidiumError(
|
|
3219
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
3220
|
-
`ICRC account inflow targets are not supported for ${asset}`
|
|
3221
|
-
);
|
|
3348
|
+
function createInflowIcrcAccount(profileId, request) {
|
|
3349
|
+
return createIcrcAccount({
|
|
3350
|
+
owner: Principal.fromText(request.poolId),
|
|
3351
|
+
subaccount: encodeInflowSubaccount({
|
|
3352
|
+
action: request.action,
|
|
3353
|
+
principal: Principal.fromText(profileId)
|
|
3354
|
+
})
|
|
3355
|
+
});
|
|
3222
3356
|
}
|
|
3223
3357
|
|
|
3224
3358
|
// src/core/borrow-minimums.ts
|
|
@@ -3692,25 +3826,20 @@ function isEthStablecoin2(asset) {
|
|
|
3692
3826
|
}
|
|
3693
3827
|
|
|
3694
3828
|
// src/modules/instant-loans/_internal/address-validation.ts
|
|
3695
|
-
function validateInstantLoanBorrowDestination(address, asset) {
|
|
3829
|
+
function validateInstantLoanBorrowDestination(address, asset, chain) {
|
|
3696
3830
|
return normalizeExternalAddress({
|
|
3697
3831
|
address,
|
|
3698
3832
|
asset,
|
|
3699
|
-
chain
|
|
3833
|
+
chain
|
|
3700
3834
|
});
|
|
3701
3835
|
}
|
|
3702
|
-
function validateInstantLoanRefundDestination(address, asset) {
|
|
3836
|
+
function validateInstantLoanRefundDestination(address, asset, chain) {
|
|
3703
3837
|
return normalizeExternalAddress({
|
|
3704
3838
|
address,
|
|
3705
3839
|
asset,
|
|
3706
|
-
chain
|
|
3840
|
+
chain
|
|
3707
3841
|
});
|
|
3708
3842
|
}
|
|
3709
|
-
function getChainForInstantLoanAsset(asset) {
|
|
3710
|
-
if (asset === Asset.BTC) return Chain.BTC;
|
|
3711
|
-
if (asset === Asset.USDC || asset === Asset.USDT) return Chain.ETH;
|
|
3712
|
-
return asset;
|
|
3713
|
-
}
|
|
3714
3843
|
|
|
3715
3844
|
// src/modules/instant-loans/instant-loans.ts
|
|
3716
3845
|
var REPAYMENT_BUFFER_SECONDS = 86400n;
|
|
@@ -3723,10 +3852,32 @@ var INSTANT_LOAN_FIND_QUERY_MAX_LENGTH = 256;
|
|
|
3723
3852
|
var INSTANT_LOAN_WIRE_CONTEXT = "instant loan";
|
|
3724
3853
|
var INSTANT_LOAN_ASSETS = [
|
|
3725
3854
|
Asset.BTC,
|
|
3726
|
-
Asset.
|
|
3855
|
+
Asset.ICP,
|
|
3727
3856
|
Asset.USDC,
|
|
3728
3857
|
Asset.USDT
|
|
3729
3858
|
];
|
|
3859
|
+
var INSTANT_LOAN_CHAINS = [
|
|
3860
|
+
Chain.BTC,
|
|
3861
|
+
Chain.ETH,
|
|
3862
|
+
Chain.ICP
|
|
3863
|
+
];
|
|
3864
|
+
var ICP_ACCOUNT_IDENTIFIER_HEX_LENGTH = 64;
|
|
3865
|
+
var InstantLoanCreatedError = class extends Error {
|
|
3866
|
+
code = "INSTANT_LOAN_HYDRATION_FAILED";
|
|
3867
|
+
loanId;
|
|
3868
|
+
ref;
|
|
3869
|
+
cause;
|
|
3870
|
+
constructor(loanId, cause) {
|
|
3871
|
+
const ref = publicIdFromInt(loanId);
|
|
3872
|
+
super(
|
|
3873
|
+
`Instant loan ${ref} was created, but its enriched state could not be loaded`
|
|
3874
|
+
);
|
|
3875
|
+
this.name = "InstantLoanCreatedError";
|
|
3876
|
+
this.loanId = loanId;
|
|
3877
|
+
this.ref = ref;
|
|
3878
|
+
this.cause = cause;
|
|
3879
|
+
}
|
|
3880
|
+
};
|
|
3730
3881
|
var InstantLoansModule = class {
|
|
3731
3882
|
constructor(canisterContext, apiClient, activities, lending, positions) {
|
|
3732
3883
|
this.canisterContext = canisterContext;
|
|
@@ -3749,37 +3900,39 @@ var InstantLoansModule = class {
|
|
|
3749
3900
|
* selected pool decimals, and call `client.quote.calculateLtv(...)` before
|
|
3750
3901
|
* creation to block invalid LTV input.
|
|
3751
3902
|
*
|
|
3752
|
-
* `
|
|
3753
|
-
* `
|
|
3903
|
+
* `borrow.destination` receives the borrowed asset after the loan starts.
|
|
3904
|
+
* `refund.destination` receives collateral refunds or withdrawals. Use
|
|
3754
3905
|
* `depositWindowSeconds` for the user-facing collateral deposit timeout; the
|
|
3755
3906
|
* SDK maps it to the canister's internal `ltv_timer_s` field.
|
|
3756
3907
|
*
|
|
3757
|
-
* @param request -
|
|
3908
|
+
* @param request - Collateral, borrow, refund, LTV limit, timeout, and inflow options.
|
|
3758
3909
|
* @returns Hydrated loan state plus generated initial-deposit and repayment quote targets.
|
|
3759
3910
|
*/
|
|
3760
3911
|
async create(request) {
|
|
3761
3912
|
validateCreateRequest(request);
|
|
3762
|
-
const borrowDestination = {
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3913
|
+
const borrowDestination = resolveInstantLoanDestination({
|
|
3914
|
+
destination: request.borrow.destination,
|
|
3915
|
+
asset: request.borrow.asset,
|
|
3916
|
+
role: "borrow",
|
|
3917
|
+
chain: request.borrow.chain,
|
|
3918
|
+
normalizeExternalDestination: validateInstantLoanBorrowDestination
|
|
3919
|
+
});
|
|
3920
|
+
const refundDestination = resolveInstantLoanDestination({
|
|
3921
|
+
destination: request.refund.destination,
|
|
3922
|
+
asset: request.collateral.asset,
|
|
3923
|
+
role: "refund",
|
|
3924
|
+
chain: request.refund.chain,
|
|
3925
|
+
normalizeExternalDestination: validateInstantLoanRefundDestination
|
|
3926
|
+
});
|
|
3774
3927
|
const apiClient = this.requireApi("Instant loan creation");
|
|
3775
3928
|
await this.validateInstantLoanLtvPolicy(request);
|
|
3776
3929
|
const response = await apiClient.post(SdkApiPath.instantLoans, {
|
|
3777
|
-
collateralPoolId: request.
|
|
3778
|
-
borrowPoolId: request.
|
|
3779
|
-
collateralAsset: request.
|
|
3780
|
-
borrowAsset: request.
|
|
3781
|
-
collateralAmount: request.
|
|
3782
|
-
borrowAmount: request.
|
|
3930
|
+
collateralPoolId: request.collateral.poolId,
|
|
3931
|
+
borrowPoolId: request.borrow.poolId,
|
|
3932
|
+
collateralAsset: request.collateral.asset,
|
|
3933
|
+
borrowAsset: request.borrow.asset,
|
|
3934
|
+
collateralAmount: request.collateral.amount.toString(),
|
|
3935
|
+
borrowAmount: request.borrow.amount.toString(),
|
|
3783
3936
|
ltvMaxBps: request.ltvMaxBps.toString(),
|
|
3784
3937
|
depositWindowSeconds: request.depositWindowSeconds.toString(),
|
|
3785
3938
|
borrowDestination,
|
|
@@ -3789,15 +3942,21 @@ var InstantLoansModule = class {
|
|
|
3789
3942
|
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
3790
3943
|
label: "loan ID"
|
|
3791
3944
|
});
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3945
|
+
try {
|
|
3946
|
+
const collateralAmount = parseUnsignedApiBigint(
|
|
3947
|
+
response.loan.collateral.amountHint,
|
|
3948
|
+
{
|
|
3949
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
3950
|
+
label: "collateral amount"
|
|
3951
|
+
}
|
|
3952
|
+
);
|
|
3953
|
+
const record = await this.getLoanRecord(loanId);
|
|
3954
|
+
return await this.mapLoanRecord(record, collateralAmount, {
|
|
3955
|
+
borrowChain: request.borrow.chain
|
|
3956
|
+
});
|
|
3957
|
+
} catch (cause) {
|
|
3958
|
+
throw new InstantLoanCreatedError(loanId, cause);
|
|
3959
|
+
}
|
|
3801
3960
|
}
|
|
3802
3961
|
/**
|
|
3803
3962
|
* Resolves canonical canister state by loan id or short reference.
|
|
@@ -3963,7 +4122,16 @@ var InstantLoansModule = class {
|
|
|
3963
4122
|
throw mapCanisterCallErrorToLiquidiumError("get_loan", error);
|
|
3964
4123
|
}
|
|
3965
4124
|
}
|
|
3966
|
-
async mapLoanRecord(record, collateralAmount) {
|
|
4125
|
+
async mapLoanRecord(record, collateralAmount, chainOptions = {}) {
|
|
4126
|
+
const borrowDestination = accountFromCanister(record.borrow_destination);
|
|
4127
|
+
const collateralAsset = parseInstantLoanAsset(
|
|
4128
|
+
record.lend_asset,
|
|
4129
|
+
"collateral asset"
|
|
4130
|
+
);
|
|
4131
|
+
const borrowAsset = parseInstantLoanAsset(
|
|
4132
|
+
record.borrow_asset,
|
|
4133
|
+
"borrow asset"
|
|
4134
|
+
);
|
|
3967
4135
|
return await this.hydrateLoan({
|
|
3968
4136
|
loanId: record.id,
|
|
3969
4137
|
profileId: record.lending_profile.toText(),
|
|
@@ -3972,17 +4140,18 @@ var InstantLoansModule = class {
|
|
|
3972
4140
|
collateralPoolId: record.lend_pool_id.toText(),
|
|
3973
4141
|
collateralAmount,
|
|
3974
4142
|
borrowPoolId: record.borrow_pool_id.toText(),
|
|
3975
|
-
collateralAsset
|
|
3976
|
-
borrowAsset
|
|
4143
|
+
collateralAsset,
|
|
4144
|
+
borrowAsset,
|
|
3977
4145
|
borrowAmount: record.borrow_amount,
|
|
3978
|
-
borrowDestination
|
|
4146
|
+
borrowDestination,
|
|
3979
4147
|
refundDestination: accountFromCanister(record.refund_destination),
|
|
3980
4148
|
started: record.started,
|
|
3981
4149
|
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
3982
4150
|
expiryTimestamp: record.expires_at[0] ?? deriveDepositExpiryTimestamp({
|
|
3983
4151
|
depositDetectedTimestamp: record.deposit_detected_ts[0] ?? null,
|
|
3984
4152
|
depositWindowSeconds: record.ltv_timer_s
|
|
3985
|
-
})
|
|
4153
|
+
}),
|
|
4154
|
+
borrowChain: chainOptions.borrowChain ?? inferInstantLoanDeliveryChain(borrowDestination, borrowAsset)
|
|
3986
4155
|
});
|
|
3987
4156
|
}
|
|
3988
4157
|
async getCollateralAmountHint(loanId) {
|
|
@@ -4002,24 +4171,22 @@ var InstantLoansModule = class {
|
|
|
4002
4171
|
const collateralAsset = input.collateralAsset;
|
|
4003
4172
|
const borrowAsset = input.borrowAsset;
|
|
4004
4173
|
const [
|
|
4005
|
-
|
|
4006
|
-
|
|
4174
|
+
depositTargetSet,
|
|
4175
|
+
repaymentTargetSet,
|
|
4007
4176
|
collateralPosition,
|
|
4008
4177
|
borrowPosition,
|
|
4009
4178
|
borrowPoolRate,
|
|
4010
4179
|
activeActivities
|
|
4011
4180
|
] = await Promise.all([
|
|
4012
|
-
|
|
4181
|
+
this.resolveInstantLoanInflowTargets({
|
|
4013
4182
|
profileId,
|
|
4014
4183
|
poolId: collateralPoolId,
|
|
4015
|
-
action: SupplyAction.deposit
|
|
4016
|
-
mechanism: SupplyPlanType.transfer
|
|
4184
|
+
action: SupplyAction.deposit
|
|
4017
4185
|
}),
|
|
4018
|
-
|
|
4186
|
+
this.resolveInstantLoanInflowTargets({
|
|
4019
4187
|
profileId,
|
|
4020
4188
|
poolId: borrowPoolId,
|
|
4021
|
-
action: SupplyAction.repayment
|
|
4022
|
-
mechanism: SupplyPlanType.transfer
|
|
4189
|
+
action: SupplyAction.repayment
|
|
4023
4190
|
}),
|
|
4024
4191
|
this.positions.getPosition(profileId, collateralPoolId),
|
|
4025
4192
|
this.positions.getPosition(profileId, borrowPoolId),
|
|
@@ -4031,8 +4198,6 @@ var InstantLoansModule = class {
|
|
|
4031
4198
|
borrowPosition,
|
|
4032
4199
|
borrowPoolRate.borrowRate
|
|
4033
4200
|
);
|
|
4034
|
-
const repaymentInflowFee = totalDebtAmount > 0n ? await this.estimateRepaymentInflowFee(borrowAsset, repayTarget.chain) : { totalFee: 0n, estimateAvailable: false };
|
|
4035
|
-
const repaymentAmount = totalDebtAmount + interestBufferAmount + repaymentInflowFee.totalFee;
|
|
4036
4201
|
const currentCollateralAmount = collateralPosition?.deposited ?? 0n;
|
|
4037
4202
|
const collateralAmount = input.collateralAmount;
|
|
4038
4203
|
const collateralDecimals = collateralPosition?.depositedDecimals ?? getAssetNativeDecimals(collateralAsset);
|
|
@@ -4052,22 +4217,28 @@ var InstantLoansModule = class {
|
|
|
4052
4217
|
collateralAmount,
|
|
4053
4218
|
decimals: collateralDecimals,
|
|
4054
4219
|
asset: collateralAsset,
|
|
4055
|
-
|
|
4220
|
+
targets: depositTargetSet.targets,
|
|
4056
4221
|
detectedTimestamp: input.depositDetectedTimestamp,
|
|
4057
4222
|
expiryTimestamp: input.expiryTimestamp
|
|
4058
4223
|
});
|
|
4224
|
+
const repaymentTargets = await this.createRepaymentTargetQuotes({
|
|
4225
|
+
baseRepaymentAmount: totalDebtAmount + interestBufferAmount,
|
|
4226
|
+
asset: borrowAsset,
|
|
4227
|
+
targets: repaymentTargetSet.targets
|
|
4228
|
+
});
|
|
4059
4229
|
const repayment = {
|
|
4060
|
-
amount: repaymentAmount,
|
|
4061
4230
|
decimals: borrowedDecimals,
|
|
4062
4231
|
debtAmount: totalDebtAmount,
|
|
4063
4232
|
interestBufferAmount,
|
|
4064
4233
|
interestBufferSeconds: REPAYMENT_BUFFER_SECONDS,
|
|
4065
|
-
inflowFeeAmount: repaymentInflowFee.totalFee,
|
|
4066
|
-
inflowFeeEstimateAvailable: repaymentInflowFee.estimateAvailable,
|
|
4067
4234
|
asset: borrowAsset,
|
|
4068
|
-
|
|
4069
|
-
target: repayTarget
|
|
4235
|
+
targets: repaymentTargets
|
|
4070
4236
|
};
|
|
4237
|
+
const borrowIdentifier = getInstantLoanAssetIdentifier(
|
|
4238
|
+
borrowAsset,
|
|
4239
|
+
input.borrowChain,
|
|
4240
|
+
"borrow"
|
|
4241
|
+
);
|
|
4071
4242
|
return {
|
|
4072
4243
|
loanId: input.loanId,
|
|
4073
4244
|
ref: publicIdFromInt(input.loanId),
|
|
@@ -4078,16 +4249,14 @@ var InstantLoansModule = class {
|
|
|
4078
4249
|
depositWindowSeconds: input.depositWindowSeconds
|
|
4079
4250
|
},
|
|
4080
4251
|
collateral: {
|
|
4081
|
-
poolId: collateralPoolId,
|
|
4082
4252
|
asset: collateralAsset,
|
|
4083
|
-
|
|
4253
|
+
poolId: collateralPoolId,
|
|
4084
4254
|
decimals: collateralDecimals,
|
|
4085
4255
|
amount: collateralAmount
|
|
4086
4256
|
},
|
|
4087
4257
|
borrow: {
|
|
4258
|
+
...borrowIdentifier,
|
|
4088
4259
|
poolId: borrowPoolId,
|
|
4089
|
-
asset: borrowAsset,
|
|
4090
|
-
chain: repayTarget.chain,
|
|
4091
4260
|
decimals: borrowedDecimals,
|
|
4092
4261
|
amount: input.borrowAmount,
|
|
4093
4262
|
destination: input.borrowDestination
|
|
@@ -4107,37 +4276,86 @@ var InstantLoansModule = class {
|
|
|
4107
4276
|
};
|
|
4108
4277
|
}
|
|
4109
4278
|
async createInitialDepositQuote(input) {
|
|
4110
|
-
const
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4279
|
+
const targets = {};
|
|
4280
|
+
for (const chain of INSTANT_LOAN_CHAINS) {
|
|
4281
|
+
const target = input.targets[chain];
|
|
4282
|
+
if (!target) continue;
|
|
4283
|
+
assertTargetAsset(target, input.asset);
|
|
4284
|
+
const inflowFee = await this.lending.estimateInflowFee(target);
|
|
4285
|
+
targets[chain] = {
|
|
4286
|
+
amount: input.collateralAmount + inflowFee.totalFee,
|
|
4287
|
+
inflowFeeAmount: inflowFee.totalFee,
|
|
4288
|
+
target
|
|
4289
|
+
};
|
|
4290
|
+
}
|
|
4114
4291
|
return {
|
|
4115
|
-
amount: input.collateralAmount + inflowFee.totalFee,
|
|
4116
4292
|
decimals: input.decimals,
|
|
4117
4293
|
collateralAmount: input.collateralAmount,
|
|
4118
|
-
inflowFeeAmount: inflowFee.totalFee,
|
|
4119
4294
|
asset: input.asset,
|
|
4120
|
-
|
|
4121
|
-
target: input.target,
|
|
4295
|
+
targets,
|
|
4122
4296
|
detectedTimestamp: input.detectedTimestamp,
|
|
4123
4297
|
expiryTimestamp: input.expiryTimestamp
|
|
4124
4298
|
};
|
|
4125
4299
|
}
|
|
4126
|
-
async
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4300
|
+
async resolveInstantLoanInflowTargets(request) {
|
|
4301
|
+
const selectedPool = await getPoolById(
|
|
4302
|
+
this.canisterContext,
|
|
4303
|
+
request.poolId
|
|
4304
|
+
);
|
|
4305
|
+
const baseRequest = {
|
|
4306
|
+
profileId: request.profileId,
|
|
4307
|
+
poolId: request.poolId,
|
|
4308
|
+
action: request.action,
|
|
4309
|
+
mechanism: SupplyPlanType.transfer
|
|
4310
|
+
};
|
|
4311
|
+
const poolChainTarget = await resolveSupplyTargetForPool(
|
|
4312
|
+
this.canisterContext,
|
|
4313
|
+
baseRequest,
|
|
4314
|
+
selectedPool
|
|
4315
|
+
);
|
|
4316
|
+
const poolChain = poolChainTarget.chain;
|
|
4317
|
+
const targets = {
|
|
4318
|
+
[poolChain]: poolChainTarget
|
|
4319
|
+
};
|
|
4320
|
+
if (poolChain === Chain.ICP) {
|
|
4321
|
+
return { targets };
|
|
4322
|
+
}
|
|
4323
|
+
const icpTarget = await resolveSupplyTargetForPool(
|
|
4324
|
+
this.canisterContext,
|
|
4325
|
+
{ ...baseRequest, chain: Chain.ICP },
|
|
4326
|
+
selectedPool
|
|
4327
|
+
);
|
|
4328
|
+
targets[Chain.ICP] = icpTarget;
|
|
4329
|
+
return { targets };
|
|
4330
|
+
}
|
|
4331
|
+
async createRepaymentTargetQuotes(input) {
|
|
4332
|
+
const quotes = {};
|
|
4333
|
+
for (const chain of INSTANT_LOAN_CHAINS) {
|
|
4334
|
+
const target = input.targets[chain];
|
|
4335
|
+
if (!target) continue;
|
|
4336
|
+
assertTargetAsset(target, input.asset);
|
|
4337
|
+
const repaymentInflowFee = input.baseRepaymentAmount > 0n ? await this.estimateRepaymentInflowFee(target) : { totalFee: 0n, estimateAvailable: false };
|
|
4338
|
+
quotes[chain] = {
|
|
4339
|
+
amount: input.baseRepaymentAmount + repaymentInflowFee.totalFee,
|
|
4340
|
+
inflowFeeAmount: repaymentInflowFee.totalFee,
|
|
4341
|
+
inflowFeeEstimateAvailable: repaymentInflowFee.estimateAvailable,
|
|
4342
|
+
target
|
|
4343
|
+
};
|
|
4344
|
+
}
|
|
4345
|
+
return quotes;
|
|
4346
|
+
}
|
|
4347
|
+
async estimateRepaymentInflowFee(target) {
|
|
4348
|
+
try {
|
|
4349
|
+
const fee = await this.lending.estimateInflowFee(target);
|
|
4350
|
+
return { totalFee: fee.totalFee, estimateAvailable: true };
|
|
4351
|
+
} catch {
|
|
4352
|
+
return {
|
|
4353
|
+
totalFee: getRepaymentInflowFeeFallback(target.asset, target.chain),
|
|
4354
|
+
estimateAvailable: false
|
|
4355
|
+
};
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
requireApi(action) {
|
|
4141
4359
|
if (!this.apiClient) {
|
|
4142
4360
|
throw new LiquidiumError(
|
|
4143
4361
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
@@ -4168,10 +4386,10 @@ var InstantLoansModule = class {
|
|
|
4168
4386
|
]);
|
|
4169
4387
|
const ltvCalculation = new QuoteModule().calculateLtv(
|
|
4170
4388
|
{
|
|
4171
|
-
borrowAmount: request.
|
|
4172
|
-
borrowPoolId: request.
|
|
4173
|
-
collateralAmount: request.
|
|
4174
|
-
collateralPoolId: request.
|
|
4389
|
+
borrowAmount: request.borrow.amount,
|
|
4390
|
+
borrowPoolId: request.borrow.poolId,
|
|
4391
|
+
collateralAmount: request.collateral.amount,
|
|
4392
|
+
collateralPoolId: request.collateral.poolId
|
|
4175
4393
|
},
|
|
4176
4394
|
pools,
|
|
4177
4395
|
assetPrices
|
|
@@ -4193,6 +4411,15 @@ function getRepaymentInflowFeeFallback(asset, chain) {
|
|
|
4193
4411
|
}
|
|
4194
4412
|
return 0n;
|
|
4195
4413
|
}
|
|
4414
|
+
function assertTargetAsset(target, expectedAsset) {
|
|
4415
|
+
if (target.asset === expectedAsset) {
|
|
4416
|
+
return;
|
|
4417
|
+
}
|
|
4418
|
+
throw new LiquidiumError(
|
|
4419
|
+
LiquidiumErrorCode.INTERNAL,
|
|
4420
|
+
`Instant loan pool target asset ${target.asset} does not match ${expectedAsset}`
|
|
4421
|
+
);
|
|
4422
|
+
}
|
|
4196
4423
|
function calculateInterestBufferAmount(borrowPosition, annualBorrowRate) {
|
|
4197
4424
|
const totalDebtAmount = calculateTotalDebtAmount(borrowPosition);
|
|
4198
4425
|
if (totalDebtAmount <= 0n || annualBorrowRate <= 0n) {
|
|
@@ -4285,13 +4512,23 @@ function deriveDepositExpiryTimestamp(input) {
|
|
|
4285
4512
|
return input.depositDetectedTimestamp + input.depositWindowSeconds;
|
|
4286
4513
|
}
|
|
4287
4514
|
function validateCreateRequest(request) {
|
|
4288
|
-
|
|
4515
|
+
getInstantLoanAssetIdentifier(
|
|
4516
|
+
request.borrow.asset,
|
|
4517
|
+
request.borrow.chain,
|
|
4518
|
+
"borrow"
|
|
4519
|
+
);
|
|
4520
|
+
getInstantLoanAssetIdentifier(
|
|
4521
|
+
request.collateral.asset,
|
|
4522
|
+
request.refund.chain,
|
|
4523
|
+
"refund"
|
|
4524
|
+
);
|
|
4525
|
+
if (request.collateral.amount <= 0n) {
|
|
4289
4526
|
throw new LiquidiumError(
|
|
4290
4527
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4291
4528
|
"Instant loan collateral amount must be greater than zero"
|
|
4292
4529
|
);
|
|
4293
4530
|
}
|
|
4294
|
-
if (request.
|
|
4531
|
+
if (request.borrow.amount <= 0n) {
|
|
4295
4532
|
throw new LiquidiumError(
|
|
4296
4533
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4297
4534
|
"Instant loan borrow amount must be greater than zero"
|
|
@@ -4316,45 +4553,200 @@ function throwLtvCalculationError(error) {
|
|
|
4316
4553
|
error?.message ?? "Unable to calculate instant loan LTV"
|
|
4317
4554
|
);
|
|
4318
4555
|
}
|
|
4319
|
-
function
|
|
4320
|
-
|
|
4321
|
-
|
|
4556
|
+
function inferInstantLoanDeliveryChain(destination, asset) {
|
|
4557
|
+
if (destination.type !== "ChainAddress") {
|
|
4558
|
+
return Chain.ICP;
|
|
4559
|
+
}
|
|
4560
|
+
if (asset === Asset.BTC) {
|
|
4561
|
+
return Chain.BTC;
|
|
4562
|
+
}
|
|
4563
|
+
if (asset === Asset.USDC || asset === Asset.USDT) {
|
|
4564
|
+
return Chain.ETH;
|
|
4565
|
+
}
|
|
4566
|
+
return Chain.ICP;
|
|
4567
|
+
}
|
|
4568
|
+
function resolveInstantLoanDestination(params) {
|
|
4569
|
+
getInstantLoanAssetIdentifier(params.asset, params.chain, params.role);
|
|
4570
|
+
if (typeof params.destination === "string") {
|
|
4571
|
+
return resolveInstantLoanStringDestination({
|
|
4572
|
+
destination: params.destination,
|
|
4573
|
+
asset: params.asset,
|
|
4574
|
+
role: params.role,
|
|
4575
|
+
chain: params.chain,
|
|
4576
|
+
normalizeExternalDestination: params.normalizeExternalDestination
|
|
4577
|
+
});
|
|
4578
|
+
}
|
|
4579
|
+
assertInstantLoanDestinationTypeMatchesChain({
|
|
4580
|
+
destinationType: params.destination.type,
|
|
4581
|
+
asset: params.asset,
|
|
4582
|
+
role: params.role,
|
|
4583
|
+
chain: params.chain
|
|
4584
|
+
});
|
|
4585
|
+
switch (params.destination.type) {
|
|
4586
|
+
case "ChainAddress":
|
|
4587
|
+
assertExternalInstantLoanDestinationSupported(params.asset);
|
|
4588
|
+
return {
|
|
4589
|
+
External: params.normalizeExternalDestination(
|
|
4590
|
+
normalizeInstantLoanDestinationAddress(params.destination.address),
|
|
4591
|
+
params.asset,
|
|
4592
|
+
params.chain
|
|
4593
|
+
)
|
|
4594
|
+
};
|
|
4595
|
+
case "IcPrincipal":
|
|
4596
|
+
return {
|
|
4597
|
+
Native: normalizeInstantLoanPrincipal(
|
|
4598
|
+
normalizeInstantLoanDestinationAddress(params.destination.address)
|
|
4599
|
+
)
|
|
4600
|
+
};
|
|
4601
|
+
case "IcpAccountIdentifier":
|
|
4602
|
+
return parseAccountIdentifierInstantLoanDestination(
|
|
4603
|
+
normalizeInstantLoanDestinationAddress(params.destination.address)
|
|
4604
|
+
);
|
|
4605
|
+
case "IcrcAccount":
|
|
4606
|
+
return parseIcrcInstantLoanDestination(
|
|
4607
|
+
normalizeInstantLoanDestinationAddress(params.destination.address)
|
|
4608
|
+
);
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
function resolveInstantLoanStringDestination(params) {
|
|
4612
|
+
const address = normalizeInstantLoanDestinationAddress(params.destination);
|
|
4613
|
+
if (params.chain === Chain.ICP && params.asset !== Asset.ICP) {
|
|
4614
|
+
try {
|
|
4615
|
+
return parsePrincipalInstantLoanDestination(address);
|
|
4616
|
+
} catch {
|
|
4617
|
+
throwInvalidCkInstantLoanDestination(params.role);
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
if (params.chain !== Chain.ICP) {
|
|
4621
|
+
assertExternalInstantLoanDestinationSupported(params.asset);
|
|
4622
|
+
return {
|
|
4623
|
+
External: params.normalizeExternalDestination(
|
|
4624
|
+
address,
|
|
4625
|
+
params.asset,
|
|
4626
|
+
params.chain
|
|
4627
|
+
)
|
|
4628
|
+
};
|
|
4629
|
+
}
|
|
4630
|
+
for (const parser of [
|
|
4631
|
+
parseAccountIdentifierInstantLoanDestination,
|
|
4632
|
+
parsePrincipalInstantLoanDestination,
|
|
4633
|
+
parseIcrcInstantLoanDestination
|
|
4634
|
+
]) {
|
|
4635
|
+
try {
|
|
4636
|
+
return parser(address);
|
|
4637
|
+
} catch {
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
throwInvalidIcpInstantLoanDestination();
|
|
4641
|
+
}
|
|
4642
|
+
function getInstantLoanAssetIdentifier(asset, chain, role) {
|
|
4643
|
+
const identifier = { asset, chain };
|
|
4644
|
+
if (isAssetIdentifier(identifier)) {
|
|
4645
|
+
return identifier;
|
|
4646
|
+
}
|
|
4647
|
+
throw new LiquidiumError(
|
|
4648
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4649
|
+
`${chain} instant loan ${role} delivery is not supported for ${asset}`
|
|
4650
|
+
);
|
|
4651
|
+
}
|
|
4652
|
+
function assertInstantLoanDestinationTypeMatchesChain(params) {
|
|
4653
|
+
if (params.chain === Chain.ICP && params.asset !== Asset.ICP) {
|
|
4654
|
+
if (params.destinationType === "IcPrincipal") {
|
|
4655
|
+
return;
|
|
4656
|
+
}
|
|
4657
|
+
throwInvalidCkInstantLoanDestination(params.role);
|
|
4658
|
+
}
|
|
4659
|
+
if (params.chain === Chain.ICP && params.asset === Asset.ICP) {
|
|
4660
|
+
if (params.destinationType !== "ChainAddress") {
|
|
4661
|
+
return;
|
|
4662
|
+
}
|
|
4663
|
+
throwInvalidIcpInstantLoanDestination();
|
|
4664
|
+
}
|
|
4665
|
+
if (params.destinationType === "ChainAddress") {
|
|
4666
|
+
return;
|
|
4667
|
+
}
|
|
4668
|
+
if (params.destinationType === "IcPrincipal") {
|
|
4322
4669
|
throw new LiquidiumError(
|
|
4323
4670
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4324
|
-
|
|
4671
|
+
`${params.chain} instant loan ${params.role} destination must be an external chain address for ${params.asset}`
|
|
4325
4672
|
);
|
|
4326
4673
|
}
|
|
4327
|
-
|
|
4674
|
+
throw new LiquidiumError(
|
|
4675
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4676
|
+
`${params.asset} instant loan ${params.role} destination only supports ChainAddress or IcPrincipal destinations`
|
|
4677
|
+
);
|
|
4328
4678
|
}
|
|
4329
|
-
function
|
|
4330
|
-
|
|
4331
|
-
|
|
4679
|
+
function throwInvalidCkInstantLoanDestination(role) {
|
|
4680
|
+
throw new LiquidiumError(
|
|
4681
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4682
|
+
`ICP instant loan ${role} destination must be an IC principal`
|
|
4683
|
+
);
|
|
4684
|
+
}
|
|
4685
|
+
function assertExternalInstantLoanDestinationSupported(asset) {
|
|
4686
|
+
if (asset !== Asset.ICP) {
|
|
4687
|
+
return;
|
|
4332
4688
|
}
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4689
|
+
throwInvalidIcpInstantLoanDestination();
|
|
4690
|
+
}
|
|
4691
|
+
function throwInvalidIcpInstantLoanDestination() {
|
|
4692
|
+
throw new LiquidiumError(
|
|
4693
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
4694
|
+
"ICP instant loan destination must be an IC principal, ICP account identifier, or ICRC account"
|
|
4695
|
+
);
|
|
4696
|
+
}
|
|
4697
|
+
function parsePrincipalInstantLoanDestination(address) {
|
|
4698
|
+
return { Native: normalizeInstantLoanPrincipal(address) };
|
|
4699
|
+
}
|
|
4700
|
+
function parseAccountIdentifierInstantLoanDestination(address) {
|
|
4701
|
+
if (address.length !== ICP_ACCOUNT_IDENTIFIER_HEX_LENGTH) {
|
|
4702
|
+
throw new LiquidiumError(
|
|
4703
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
4704
|
+
"Invalid ICP account identifier"
|
|
4705
|
+
);
|
|
4338
4706
|
}
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
owner: account.Icrc.owner,
|
|
4347
|
-
subaccount
|
|
4348
|
-
})
|
|
4349
|
-
};
|
|
4707
|
+
try {
|
|
4708
|
+
return { AccountIdentifier: normalizeIcpAccountIdentifier(address) };
|
|
4709
|
+
} catch {
|
|
4710
|
+
throw new LiquidiumError(
|
|
4711
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
4712
|
+
"Invalid ICP account identifier"
|
|
4713
|
+
);
|
|
4350
4714
|
}
|
|
4351
|
-
return { type: "External", address: account.External };
|
|
4352
4715
|
}
|
|
4353
|
-
function
|
|
4354
|
-
|
|
4355
|
-
|
|
4716
|
+
function parseIcrcInstantLoanDestination(address) {
|
|
4717
|
+
let decoded;
|
|
4718
|
+
try {
|
|
4719
|
+
decoded = decodeIcrcAccountAddress(address);
|
|
4720
|
+
} catch {
|
|
4721
|
+
throw new LiquidiumError(
|
|
4722
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
4723
|
+
"Invalid instant loan ICRC destination"
|
|
4724
|
+
);
|
|
4725
|
+
}
|
|
4726
|
+
return { Icrc: decoded.account.address };
|
|
4727
|
+
}
|
|
4728
|
+
function normalizeInstantLoanPrincipal(address) {
|
|
4729
|
+
try {
|
|
4730
|
+
return Principal.fromText(address).toText();
|
|
4731
|
+
} catch {
|
|
4732
|
+
throw new LiquidiumError(
|
|
4733
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
4734
|
+
"Invalid instant loan IC principal destination"
|
|
4735
|
+
);
|
|
4356
4736
|
}
|
|
4357
|
-
|
|
4737
|
+
}
|
|
4738
|
+
function normalizeInstantLoanDestinationAddress(address) {
|
|
4739
|
+
const trimmedAddress = address.trim();
|
|
4740
|
+
if (!trimmedAddress) {
|
|
4741
|
+
throw new LiquidiumError(
|
|
4742
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
4743
|
+
"Instant loan account address must be non-empty"
|
|
4744
|
+
);
|
|
4745
|
+
}
|
|
4746
|
+
return trimmedAddress;
|
|
4747
|
+
}
|
|
4748
|
+
function accountFromCanister(account) {
|
|
4749
|
+
return mapCanisterAccountToLiquidiumAccount(account);
|
|
4358
4750
|
}
|
|
4359
4751
|
function mapInstantLoanEvent(event) {
|
|
4360
4752
|
return {
|
|
@@ -4371,7 +4763,10 @@ function mapInstantLoanEventType(eventType) {
|
|
|
4371
4763
|
type: "LoanCreated",
|
|
4372
4764
|
loanId: event.loan_id,
|
|
4373
4765
|
borrowDestination: accountFromCanister(event.borrow_destination),
|
|
4374
|
-
collateralAsset:
|
|
4766
|
+
collateralAsset: parseInstantLoanAsset(
|
|
4767
|
+
event.lend_asset,
|
|
4768
|
+
"event collateral asset"
|
|
4769
|
+
),
|
|
4375
4770
|
borrowAmount: event.borrow_amount,
|
|
4376
4771
|
collateralPoolId: event.lend_pool_id.toText(),
|
|
4377
4772
|
refundDestination: accountFromCanister(event.refund_destination),
|
|
@@ -4379,7 +4774,10 @@ function mapInstantLoanEventType(eventType) {
|
|
|
4379
4774
|
depositWindowSeconds: event.ltv_timer_s,
|
|
4380
4775
|
profileId: event.lending_profile.toText(),
|
|
4381
4776
|
borrowPoolId: event.borrow_pool_id.toText(),
|
|
4382
|
-
borrowAsset:
|
|
4777
|
+
borrowAsset: parseInstantLoanAsset(
|
|
4778
|
+
event.borrow_asset,
|
|
4779
|
+
"event borrow asset"
|
|
4780
|
+
)
|
|
4383
4781
|
};
|
|
4384
4782
|
}
|
|
4385
4783
|
if ("FullLendWithdrawalRequested" in eventType) {
|
|
@@ -4546,6 +4944,12 @@ function mapCandidateWire(wire) {
|
|
|
4546
4944
|
})
|
|
4547
4945
|
};
|
|
4548
4946
|
}
|
|
4947
|
+
function parseInstantLoanAsset(value, label) {
|
|
4948
|
+
return parseApiStringUnion(value, INSTANT_LOAN_ASSETS, {
|
|
4949
|
+
context: INSTANT_LOAN_WIRE_CONTEXT,
|
|
4950
|
+
label
|
|
4951
|
+
});
|
|
4952
|
+
}
|
|
4549
4953
|
function mapInstantLoansErrorToLiquidiumError(error) {
|
|
4550
4954
|
const [key, payload] = Object.entries(error)[0];
|
|
4551
4955
|
switch (key) {
|
|
@@ -4687,11 +5091,25 @@ function encodeBytes32Hex(bytes) {
|
|
|
4687
5091
|
var idlFactory4 = ({ IDL }) => IDL.Service({
|
|
4688
5092
|
icrc1_fee: IDL.Func([], [IDL.Nat], ["query"])
|
|
4689
5093
|
});
|
|
4690
|
-
function
|
|
4691
|
-
|
|
5094
|
+
function createIcrcLedgerActor(params) {
|
|
5095
|
+
if (!params.canisterId) {
|
|
5096
|
+
throw new LiquidiumError(
|
|
5097
|
+
LiquidiumErrorCode.SERVICE_UNAVAILABLE,
|
|
5098
|
+
`${params.ledgerName} ledger canister ID is not configured`
|
|
5099
|
+
);
|
|
5100
|
+
}
|
|
4692
5101
|
return Actor.createActor(idlFactory4, {
|
|
4693
|
-
agent: canisterContext.agent,
|
|
4694
|
-
canisterId
|
|
5102
|
+
agent: params.canisterContext.agent,
|
|
5103
|
+
canisterId: params.canisterId
|
|
5104
|
+
});
|
|
5105
|
+
}
|
|
5106
|
+
|
|
5107
|
+
// src/core/canisters/ckbtc/ledger.ts
|
|
5108
|
+
function createCkBtcLedgerActor(canisterContext) {
|
|
5109
|
+
return createIcrcLedgerActor({
|
|
5110
|
+
canisterContext,
|
|
5111
|
+
canisterId: CK_CANISTER_IDS.BTC.ledger,
|
|
5112
|
+
ledgerName: "ckBTC"
|
|
4695
5113
|
});
|
|
4696
5114
|
}
|
|
4697
5115
|
|
|
@@ -4720,11 +5138,51 @@ function accountTypeToString(accountType) {
|
|
|
4720
5138
|
switch (accountType.type) {
|
|
4721
5139
|
case "External":
|
|
4722
5140
|
return `Address:${accountType.data}`;
|
|
5141
|
+
case "Icrc":
|
|
5142
|
+
return `Icrc:${accountType.data}`;
|
|
5143
|
+
case "AccountIdentifier":
|
|
5144
|
+
return `AccountId:${accountType.data}`;
|
|
4723
5145
|
case "Native":
|
|
4724
5146
|
return `Principal:${accountType.data}`;
|
|
4725
5147
|
}
|
|
4726
5148
|
}
|
|
4727
5149
|
|
|
5150
|
+
// src/core/pool-ledger-assets.ts
|
|
5151
|
+
function getPoolLedgerAssetRoute(params) {
|
|
5152
|
+
if (params.asset === Asset.BTC && (params.chain === Chain.BTC || params.chain === Chain.ICP)) {
|
|
5153
|
+
return {
|
|
5154
|
+
ledgerCanisterId: CK_CANISTER_IDS.BTC.ledger,
|
|
5155
|
+
asset: Asset.BTC,
|
|
5156
|
+
chain: params.chain
|
|
5157
|
+
};
|
|
5158
|
+
}
|
|
5159
|
+
if (params.asset === Asset.USDT && (params.chain === Chain.ETH || params.chain === Chain.ICP)) {
|
|
5160
|
+
return {
|
|
5161
|
+
ledgerCanisterId: CK_CANISTER_IDS.USDT.ledger,
|
|
5162
|
+
asset: Asset.USDT,
|
|
5163
|
+
chain: params.chain
|
|
5164
|
+
};
|
|
5165
|
+
}
|
|
5166
|
+
if (params.asset === Asset.USDC && (params.chain === Chain.ETH || params.chain === Chain.ICP)) {
|
|
5167
|
+
return {
|
|
5168
|
+
ledgerCanisterId: CK_CANISTER_IDS.USDC.ledger,
|
|
5169
|
+
asset: Asset.USDC,
|
|
5170
|
+
chain: params.chain
|
|
5171
|
+
};
|
|
5172
|
+
}
|
|
5173
|
+
if (params.asset === Asset.ICP && params.chain === Chain.ICP) {
|
|
5174
|
+
return {
|
|
5175
|
+
ledgerCanisterId: CK_CANISTER_IDS.ICP.ledger,
|
|
5176
|
+
asset: Asset.ICP,
|
|
5177
|
+
chain: Chain.ICP
|
|
5178
|
+
};
|
|
5179
|
+
}
|
|
5180
|
+
throw new LiquidiumError(
|
|
5181
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5182
|
+
`IC ledger transfers are not supported for ${params.asset} on ${params.chain}`
|
|
5183
|
+
);
|
|
5184
|
+
}
|
|
5185
|
+
|
|
4728
5186
|
// src/core/withdraw-minimums.ts
|
|
4729
5187
|
var MINIMUM_BTC_WITHDRAW_AMOUNT_SATS = 5000n;
|
|
4730
5188
|
var MINIMUM_STABLECOIN_WITHDRAW_AMOUNT_BASE_UNITS = 1000000n;
|
|
@@ -4842,48 +5300,61 @@ var SupplyFlowExecutor = class {
|
|
|
4842
5300
|
}
|
|
4843
5301
|
params;
|
|
4844
5302
|
async create(request) {
|
|
4845
|
-
const
|
|
5303
|
+
const requestedMechanism = request.mechanism ?? null;
|
|
5304
|
+
if (requestedMechanism === null && request.walletAdapter === void 0 && (request.account !== void 0 || request.amount !== void 0)) {
|
|
5305
|
+
throw new LiquidiumError(
|
|
5306
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5307
|
+
"Wallet-executed supply requires walletAdapter, account, and amount"
|
|
5308
|
+
);
|
|
5309
|
+
}
|
|
5310
|
+
const selectedPool = await getPoolById(
|
|
4846
5311
|
this.params.canisterContext,
|
|
4847
|
-
request
|
|
5312
|
+
request.poolId
|
|
4848
5313
|
);
|
|
4849
|
-
const
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
5314
|
+
const target = await resolveSupplyTargetForPool(
|
|
5315
|
+
this.params.canisterContext,
|
|
5316
|
+
{
|
|
5317
|
+
profileId: request.profileId,
|
|
5318
|
+
poolId: request.poolId,
|
|
5319
|
+
action: request.action,
|
|
5320
|
+
mechanism: requestedMechanism,
|
|
5321
|
+
chain: request.chain
|
|
5322
|
+
},
|
|
5323
|
+
selectedPool
|
|
5324
|
+
);
|
|
5325
|
+
const mechanism = requestedMechanism === SupplyPlanType.contractInteraction ? SupplyPlanType.contractInteraction : SupplyPlanType.transfer;
|
|
4861
5326
|
const defaultSubmitInflowRequest = getDefaultSubmitInflowRequest({
|
|
4862
5327
|
action: request.action,
|
|
4863
|
-
chain: mechanism === SupplyPlanType.contractInteraction ? Chain.ETH :
|
|
5328
|
+
chain: mechanism === SupplyPlanType.contractInteraction ? Chain.ETH : target.chain
|
|
4864
5329
|
});
|
|
4865
5330
|
let txid;
|
|
4866
5331
|
switch (mechanism) {
|
|
4867
5332
|
case SupplyPlanType.transfer:
|
|
4868
|
-
if (request
|
|
4869
|
-
txid = await this.
|
|
5333
|
+
if (isWalletTransferSupplyRequest(request)) {
|
|
5334
|
+
txid = await this.sendAndSubmitTransferSupplyInflow({
|
|
4870
5335
|
request,
|
|
4871
|
-
|
|
5336
|
+
target,
|
|
4872
5337
|
defaultSubmitInflowRequest
|
|
4873
5338
|
});
|
|
4874
5339
|
}
|
|
4875
5340
|
break;
|
|
4876
5341
|
case SupplyPlanType.contractInteraction:
|
|
5342
|
+
if (!isContractInteractionSupplyRequest(request)) {
|
|
5343
|
+
throw new LiquidiumError(
|
|
5344
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5345
|
+
"Contract-interaction supply requires contract-interaction request fields"
|
|
5346
|
+
);
|
|
5347
|
+
}
|
|
4877
5348
|
txid = await this.executeContractSupply({
|
|
4878
5349
|
request,
|
|
4879
|
-
|
|
5350
|
+
target,
|
|
4880
5351
|
defaultSubmitInflowRequest
|
|
4881
5352
|
});
|
|
4882
5353
|
break;
|
|
4883
5354
|
}
|
|
4884
5355
|
return {
|
|
4885
5356
|
type: mechanism,
|
|
4886
|
-
target
|
|
5357
|
+
target,
|
|
4887
5358
|
txid,
|
|
4888
5359
|
status: createLiquidiumStatus({
|
|
4889
5360
|
operation: mapSupplyActionToStatusOperation(request.action),
|
|
@@ -4891,7 +5362,7 @@ var SupplyFlowExecutor = class {
|
|
|
4891
5362
|
}),
|
|
4892
5363
|
submit: async (submitRequest) => {
|
|
4893
5364
|
return await this.submitSupplyFlowInflow({
|
|
4894
|
-
|
|
5365
|
+
target,
|
|
4895
5366
|
mechanism,
|
|
4896
5367
|
defaultSubmitInflowRequest,
|
|
4897
5368
|
submitRequest
|
|
@@ -4900,7 +5371,10 @@ var SupplyFlowExecutor = class {
|
|
|
4900
5371
|
};
|
|
4901
5372
|
}
|
|
4902
5373
|
async getEvmSupplyContext(request) {
|
|
4903
|
-
const selectedPool = await
|
|
5374
|
+
const selectedPool = await getPoolById(
|
|
5375
|
+
this.params.canisterContext,
|
|
5376
|
+
request.poolId
|
|
5377
|
+
);
|
|
4904
5378
|
return await this.getEvmSupplyContextForPool({
|
|
4905
5379
|
request,
|
|
4906
5380
|
asset: selectedPool.asset,
|
|
@@ -4964,14 +5438,8 @@ var SupplyFlowExecutor = class {
|
|
|
4964
5438
|
approvalStrategy
|
|
4965
5439
|
};
|
|
4966
5440
|
}
|
|
4967
|
-
async
|
|
4968
|
-
const { request,
|
|
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
|
-
}
|
|
5441
|
+
async sendAndSubmitTransferSupplyInflow(params) {
|
|
5442
|
+
const { request, target, defaultSubmitInflowRequest } = params;
|
|
4975
5443
|
if (!request.walletAdapter) {
|
|
4976
5444
|
throw new LiquidiumError(
|
|
4977
5445
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
@@ -4991,16 +5459,27 @@ var SupplyFlowExecutor = class {
|
|
|
4991
5459
|
"Wallet-executed supply requires a positive amount"
|
|
4992
5460
|
);
|
|
4993
5461
|
}
|
|
4994
|
-
const txid = await this.
|
|
5462
|
+
const txid = target.chain === Chain.ICP ? await this.sendIcrcSupplyTransaction({
|
|
4995
5463
|
walletAdapter: request.walletAdapter,
|
|
4996
|
-
|
|
4997
|
-
|
|
5464
|
+
asset: target.asset,
|
|
5465
|
+
chain: target.chain,
|
|
5466
|
+
transfer: {
|
|
5467
|
+
ledgerCanisterId: getPoolLedgerAssetRoute(target).ledgerCanisterId,
|
|
5468
|
+
to: decodeIcrcAccountAddress(target.address).account,
|
|
5469
|
+
amount: request.amount
|
|
5470
|
+
},
|
|
5471
|
+
senderAccount: account,
|
|
5472
|
+
action: request.action
|
|
5473
|
+
}) : await this.sendChainAddressSupplyTransaction({
|
|
5474
|
+
walletAdapter: request.walletAdapter,
|
|
5475
|
+
chain: target.chain,
|
|
5476
|
+
toAddress: target.address,
|
|
4998
5477
|
amount: request.amount,
|
|
4999
5478
|
senderAccount: account,
|
|
5000
|
-
asset:
|
|
5479
|
+
asset: target.asset,
|
|
5001
5480
|
action: request.action
|
|
5002
5481
|
});
|
|
5003
|
-
if (shouldSubmitInflow({
|
|
5482
|
+
if (shouldSubmitInflow({ target, mechanism: SupplyPlanType.transfer })) {
|
|
5004
5483
|
try {
|
|
5005
5484
|
await this.submitInflowWithRetry(txid, defaultSubmitInflowRequest);
|
|
5006
5485
|
} catch {
|
|
@@ -5027,11 +5506,11 @@ var SupplyFlowExecutor = class {
|
|
|
5027
5506
|
});
|
|
5028
5507
|
}
|
|
5029
5508
|
async executeContractSupply(params) {
|
|
5030
|
-
const { request,
|
|
5031
|
-
if (
|
|
5509
|
+
const { request, target, defaultSubmitInflowRequest } = params;
|
|
5510
|
+
if (!isEthStablecoin(target.asset, target.chain)) {
|
|
5032
5511
|
throw new LiquidiumError(
|
|
5033
5512
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5034
|
-
"Contract-interaction supply is only supported for ETH
|
|
5513
|
+
"Contract-interaction supply is only supported for ETH stablecoin targets"
|
|
5035
5514
|
);
|
|
5036
5515
|
}
|
|
5037
5516
|
const walletAddressInput = request.account?.trim();
|
|
@@ -5070,8 +5549,8 @@ var SupplyFlowExecutor = class {
|
|
|
5070
5549
|
amount: request.amount,
|
|
5071
5550
|
action: request.action
|
|
5072
5551
|
},
|
|
5073
|
-
asset:
|
|
5074
|
-
chain:
|
|
5552
|
+
asset: target.asset,
|
|
5553
|
+
chain: target.chain
|
|
5075
5554
|
});
|
|
5076
5555
|
const supplyAmount = BigInt(evmSupplyContext.amount);
|
|
5077
5556
|
if (BigInt(evmSupplyContext.balance) < supplyAmount) {
|
|
@@ -5127,7 +5606,7 @@ var SupplyFlowExecutor = class {
|
|
|
5127
5606
|
amount: supplyAmount,
|
|
5128
5607
|
poolId: request.poolId,
|
|
5129
5608
|
profileId: request.profileId,
|
|
5130
|
-
destinationAccount:
|
|
5609
|
+
destinationAccount: target.address,
|
|
5131
5610
|
action: request.action
|
|
5132
5611
|
}),
|
|
5133
5612
|
`supply-${request.action}-deposit-erc20`
|
|
@@ -5138,7 +5617,7 @@ var SupplyFlowExecutor = class {
|
|
|
5138
5617
|
}
|
|
5139
5618
|
return depositTxid;
|
|
5140
5619
|
}
|
|
5141
|
-
async
|
|
5620
|
+
async sendChainAddressSupplyTransaction(params) {
|
|
5142
5621
|
switch (params.chain) {
|
|
5143
5622
|
case Chain.BTC: {
|
|
5144
5623
|
if (!params.walletAdapter.sendBtcTransaction) {
|
|
@@ -5152,8 +5631,7 @@ var SupplyFlowExecutor = class {
|
|
|
5152
5631
|
toAddress: params.toAddress,
|
|
5153
5632
|
amountSats: params.amount,
|
|
5154
5633
|
account: params.senderAccount,
|
|
5155
|
-
actionType: `supply-${params.action}
|
|
5156
|
-
transferMode: TransferMode.native
|
|
5634
|
+
actionType: `supply-${params.action}`
|
|
5157
5635
|
});
|
|
5158
5636
|
}
|
|
5159
5637
|
case Chain.ETH: {
|
|
@@ -5168,7 +5646,6 @@ var SupplyFlowExecutor = class {
|
|
|
5168
5646
|
chain: Chain.ETH,
|
|
5169
5647
|
account: params.senderAccount,
|
|
5170
5648
|
actionType: `supply-${params.action}`,
|
|
5171
|
-
transferMode: TransferMode.native,
|
|
5172
5649
|
transaction: createTransferErc20Transaction({
|
|
5173
5650
|
tokenAddress: getEthStablecoinContractAddress(params.asset),
|
|
5174
5651
|
recipientAddress: params.toAddress,
|
|
@@ -5180,7 +5657,6 @@ var SupplyFlowExecutor = class {
|
|
|
5180
5657
|
chain: Chain.ETH,
|
|
5181
5658
|
account: params.senderAccount,
|
|
5182
5659
|
actionType: `supply-${params.action}`,
|
|
5183
|
-
transferMode: TransferMode.native,
|
|
5184
5660
|
transaction: {
|
|
5185
5661
|
to: params.toAddress,
|
|
5186
5662
|
value: params.amount.toString()
|
|
@@ -5190,10 +5666,32 @@ var SupplyFlowExecutor = class {
|
|
|
5190
5666
|
default:
|
|
5191
5667
|
throw new LiquidiumError(
|
|
5192
5668
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5193
|
-
`
|
|
5669
|
+
`Chain-address wallet execution is not supported for ${params.chain}`
|
|
5194
5670
|
);
|
|
5195
5671
|
}
|
|
5196
5672
|
}
|
|
5673
|
+
async sendIcrcSupplyTransaction(params) {
|
|
5674
|
+
if (!params.walletAdapter.sendIcrcTransfer) {
|
|
5675
|
+
throw new LiquidiumError(
|
|
5676
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5677
|
+
"ICRC wallet adapter does not support ledger transfers"
|
|
5678
|
+
);
|
|
5679
|
+
}
|
|
5680
|
+
const route = getPoolLedgerAssetRoute({
|
|
5681
|
+
asset: params.asset,
|
|
5682
|
+
chain: params.chain
|
|
5683
|
+
});
|
|
5684
|
+
return await params.walletAdapter.sendIcrcTransfer({
|
|
5685
|
+
chain: Chain.ICP,
|
|
5686
|
+
asset: route.asset,
|
|
5687
|
+
transfer: {
|
|
5688
|
+
...params.transfer,
|
|
5689
|
+
ledgerCanisterId: route.ledgerCanisterId
|
|
5690
|
+
},
|
|
5691
|
+
account: params.senderAccount,
|
|
5692
|
+
actionType: `supply-${params.action}`
|
|
5693
|
+
});
|
|
5694
|
+
}
|
|
5197
5695
|
async submitInflowWithRetry(txid, extraRequest) {
|
|
5198
5696
|
if (!extraRequest) {
|
|
5199
5697
|
throw new LiquidiumError(
|
|
@@ -5222,7 +5720,6 @@ var SupplyFlowExecutor = class {
|
|
|
5222
5720
|
chain: Chain.ETH,
|
|
5223
5721
|
account: walletAddress,
|
|
5224
5722
|
actionType,
|
|
5225
|
-
transferMode: TransferMode.native,
|
|
5226
5723
|
transaction: request
|
|
5227
5724
|
});
|
|
5228
5725
|
}
|
|
@@ -5311,13 +5808,19 @@ function getUnknownErrorMessage(error) {
|
|
|
5311
5808
|
}
|
|
5312
5809
|
function getDefaultSubmitInflowRequest(params) {
|
|
5313
5810
|
if (params.chain !== Chain.BTC && params.chain !== Chain.ETH) {
|
|
5314
|
-
return
|
|
5811
|
+
return null;
|
|
5315
5812
|
}
|
|
5316
5813
|
return {
|
|
5317
5814
|
chain: params.chain,
|
|
5318
5815
|
operation: mapSupplyActionToStatusOperation(params.action)
|
|
5319
5816
|
};
|
|
5320
5817
|
}
|
|
5818
|
+
function isWalletTransferSupplyRequest(request) {
|
|
5819
|
+
return request.mechanism !== SupplyPlanType.contractInteraction && request.walletAdapter !== void 0;
|
|
5820
|
+
}
|
|
5821
|
+
function isContractInteractionSupplyRequest(request) {
|
|
5822
|
+
return request.mechanism === SupplyPlanType.contractInteraction;
|
|
5823
|
+
}
|
|
5321
5824
|
function mapSupplyActionToStatusOperation(action) {
|
|
5322
5825
|
return action === SupplyAction.repayment ? "repayment" : "deposit";
|
|
5323
5826
|
}
|
|
@@ -5325,7 +5828,10 @@ function shouldSubmitInflow(params) {
|
|
|
5325
5828
|
if (params.mechanism !== SupplyPlanType.transfer) {
|
|
5326
5829
|
return true;
|
|
5327
5830
|
}
|
|
5328
|
-
|
|
5831
|
+
if (params.target.chain === Chain.ICP) {
|
|
5832
|
+
return false;
|
|
5833
|
+
}
|
|
5834
|
+
return !isEthStablecoin(params.target.asset, params.target.chain);
|
|
5329
5835
|
}
|
|
5330
5836
|
function mapCanisterOutflowDetails(outflow) {
|
|
5331
5837
|
const rawOutflowType = getVariantKey(outflow.outflow_type);
|
|
@@ -5339,41 +5845,31 @@ function mapCanisterOutflowDetails(outflow) {
|
|
|
5339
5845
|
};
|
|
5340
5846
|
}
|
|
5341
5847
|
function mapCanisterAccountType(receiver) {
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
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
|
-
};
|
|
5848
|
+
return mapCanisterAccountToLiquidiumAccount(receiver);
|
|
5849
|
+
}
|
|
5850
|
+
function parseOutflowDestination(params) {
|
|
5851
|
+
const destination = normalizeOutflowDestinationInput(params.destination);
|
|
5852
|
+
const parsedAccount = destination.type ? parseOutflowDestinationWithHint(destination) : parseOutflowDestinationAutomatically(destination.address);
|
|
5853
|
+
assertDestinationTypeSupportedByChain({
|
|
5854
|
+
accountType: parsedAccount.accountType,
|
|
5855
|
+
poolChain: params.poolChain,
|
|
5856
|
+
destinationChain: params.destinationChain
|
|
5857
|
+
});
|
|
5858
|
+
if (parsedAccount.accountType !== "ChainAddress") {
|
|
5859
|
+
return parsedAccount;
|
|
5365
5860
|
}
|
|
5861
|
+
const externalAddress = normalizeExternalAddress({
|
|
5862
|
+
address: parsedAccount.address,
|
|
5863
|
+
asset: params.asset,
|
|
5864
|
+
chain: params.destinationChain
|
|
5865
|
+
});
|
|
5366
5866
|
return {
|
|
5367
|
-
|
|
5368
|
-
|
|
5867
|
+
address: externalAddress,
|
|
5868
|
+
accountType: "ChainAddress",
|
|
5869
|
+
canisterAccount: { External: externalAddress },
|
|
5870
|
+
messageAccount: { type: "External", data: externalAddress }
|
|
5369
5871
|
};
|
|
5370
5872
|
}
|
|
5371
|
-
function normalizeOptionalSubaccount2(subaccount) {
|
|
5372
|
-
if (!subaccount) {
|
|
5373
|
-
return void 0;
|
|
5374
|
-
}
|
|
5375
|
-
return subaccount instanceof Uint8Array ? subaccount : Uint8Array.from(subaccount);
|
|
5376
|
-
}
|
|
5377
5873
|
function normalizeOutflowType(rawOutflowType) {
|
|
5378
5874
|
switch (rawOutflowType) {
|
|
5379
5875
|
case "Withdraw":
|
|
@@ -5396,6 +5892,117 @@ function mapWalletChainToLendingChain(chain) {
|
|
|
5396
5892
|
case Chain.ETH:
|
|
5397
5893
|
return { ETH: null };
|
|
5398
5894
|
}
|
|
5895
|
+
throw new LiquidiumError(
|
|
5896
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5897
|
+
`Message signing is not supported for ${String(chain)}`
|
|
5898
|
+
);
|
|
5899
|
+
}
|
|
5900
|
+
function normalizeOutflowDestinationInput(destination) {
|
|
5901
|
+
if (typeof destination === "string") {
|
|
5902
|
+
return { address: destination, type: null };
|
|
5903
|
+
}
|
|
5904
|
+
return destination;
|
|
5905
|
+
}
|
|
5906
|
+
function parseOutflowDestinationWithHint(destination) {
|
|
5907
|
+
try {
|
|
5908
|
+
switch (destination.type) {
|
|
5909
|
+
case "ChainAddress":
|
|
5910
|
+
return parseExternalDestination(destination.address);
|
|
5911
|
+
case "IcPrincipal":
|
|
5912
|
+
return parseIcPrincipalDestination(destination.address);
|
|
5913
|
+
case "IcrcAccount":
|
|
5914
|
+
return parseIcrcDestination(destination.address);
|
|
5915
|
+
case "IcpAccountIdentifier":
|
|
5916
|
+
return parseAccountIdentifierDestination(destination.address);
|
|
5917
|
+
default:
|
|
5918
|
+
throw new LiquidiumError(
|
|
5919
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5920
|
+
`Unsupported outflow account type: ${String(destination.type)}`
|
|
5921
|
+
);
|
|
5922
|
+
}
|
|
5923
|
+
} catch (error) {
|
|
5924
|
+
if (error instanceof LiquidiumError) {
|
|
5925
|
+
throw error;
|
|
5926
|
+
}
|
|
5927
|
+
throw new LiquidiumError(
|
|
5928
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
5929
|
+
`Invalid ${destination.type} outflow destination`
|
|
5930
|
+
);
|
|
5931
|
+
}
|
|
5932
|
+
}
|
|
5933
|
+
function parseOutflowDestinationAutomatically(address) {
|
|
5934
|
+
const parsers = [
|
|
5935
|
+
parseAccountIdentifierDestination,
|
|
5936
|
+
parseIcPrincipalDestination,
|
|
5937
|
+
parseIcrcDestination
|
|
5938
|
+
];
|
|
5939
|
+
for (const parser of parsers) {
|
|
5940
|
+
try {
|
|
5941
|
+
return parser(address);
|
|
5942
|
+
} catch {
|
|
5943
|
+
}
|
|
5944
|
+
}
|
|
5945
|
+
return parseExternalDestination(address);
|
|
5946
|
+
}
|
|
5947
|
+
function parseExternalDestination(address) {
|
|
5948
|
+
return {
|
|
5949
|
+
address,
|
|
5950
|
+
accountType: "ChainAddress",
|
|
5951
|
+
canisterAccount: { External: address },
|
|
5952
|
+
messageAccount: { type: "External", data: address }
|
|
5953
|
+
};
|
|
5954
|
+
}
|
|
5955
|
+
function parseIcPrincipalDestination(address) {
|
|
5956
|
+
const principal = Principal.fromText(address);
|
|
5957
|
+
const principalText = principal.toText();
|
|
5958
|
+
return {
|
|
5959
|
+
address: principalText,
|
|
5960
|
+
accountType: "IcPrincipal",
|
|
5961
|
+
canisterAccount: { Native: principal },
|
|
5962
|
+
messageAccount: { type: "Native", data: principalText }
|
|
5963
|
+
};
|
|
5964
|
+
}
|
|
5965
|
+
function parseIcrcDestination(address) {
|
|
5966
|
+
const decoded = decodeIcrcAccountAddress(address);
|
|
5967
|
+
return {
|
|
5968
|
+
address: decoded.account.address,
|
|
5969
|
+
accountType: "IcrcAccount",
|
|
5970
|
+
canisterAccount: {
|
|
5971
|
+
Icrc: {
|
|
5972
|
+
owner: decoded.owner,
|
|
5973
|
+
subaccount: decoded.subaccount ? [decoded.subaccount] : []
|
|
5974
|
+
}
|
|
5975
|
+
},
|
|
5976
|
+
messageAccount: { type: "Icrc", data: decoded.account.address }
|
|
5977
|
+
};
|
|
5978
|
+
}
|
|
5979
|
+
function parseAccountIdentifierDestination(address) {
|
|
5980
|
+
const accountIdentifier = normalizeIcpAccountIdentifier(address);
|
|
5981
|
+
return {
|
|
5982
|
+
address: accountIdentifier,
|
|
5983
|
+
accountType: "IcpAccountIdentifier",
|
|
5984
|
+
canisterAccount: { AccountIdentifier: accountIdentifier },
|
|
5985
|
+
messageAccount: { type: "AccountIdentifier", data: accountIdentifier }
|
|
5986
|
+
};
|
|
5987
|
+
}
|
|
5988
|
+
function assertDestinationTypeSupportedByChain(params) {
|
|
5989
|
+
if (params.poolChain === Chain.BTC || params.poolChain === Chain.ETH) {
|
|
5990
|
+
if (params.destinationChain === params.poolChain && params.accountType === "ChainAddress") {
|
|
5991
|
+
return;
|
|
5992
|
+
}
|
|
5993
|
+
if (params.destinationChain === Chain.ICP && params.accountType === "IcPrincipal") {
|
|
5994
|
+
return;
|
|
5995
|
+
}
|
|
5996
|
+
}
|
|
5997
|
+
if (params.poolChain === Chain.ICP && params.destinationChain === Chain.ICP) {
|
|
5998
|
+
if (params.accountType === "IcpAccountIdentifier" || params.accountType === "IcrcAccount" || params.accountType === "IcPrincipal") {
|
|
5999
|
+
return;
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
throw new LiquidiumError(
|
|
6003
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
6004
|
+
"Target pool does not support this address type"
|
|
6005
|
+
);
|
|
5399
6006
|
}
|
|
5400
6007
|
|
|
5401
6008
|
// src/modules/lending/lending.ts
|
|
@@ -5417,16 +6024,13 @@ var LendingModule = class {
|
|
|
5417
6024
|
* @returns A signable {@link WithdrawAction} with `submit` wired to the canister.
|
|
5418
6025
|
*/
|
|
5419
6026
|
async prepareWithdraw(request) {
|
|
5420
|
-
const
|
|
6027
|
+
const destination = resolveOutflowDestinationInput({
|
|
6028
|
+
receiver: request.receiver,
|
|
6029
|
+
errorMessage: "Withdraw requires a custom outflow account"
|
|
6030
|
+
});
|
|
5421
6031
|
const signerAccount = normalizeEvmAddress(
|
|
5422
6032
|
request.signerWalletAddress.trim()
|
|
5423
6033
|
);
|
|
5424
|
-
if (!destinationAccount) {
|
|
5425
|
-
throw new LiquidiumError(
|
|
5426
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5427
|
-
"Withdraw requires a custom outflow account"
|
|
5428
|
-
);
|
|
5429
|
-
}
|
|
5430
6034
|
if (!signerAccount) {
|
|
5431
6035
|
throw new LiquidiumError(
|
|
5432
6036
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
@@ -5439,7 +6043,10 @@ var LendingModule = class {
|
|
|
5439
6043
|
"Withdraw amount must be greater than 0"
|
|
5440
6044
|
);
|
|
5441
6045
|
}
|
|
5442
|
-
const selectedPool = await
|
|
6046
|
+
const selectedPool = await getPoolById(
|
|
6047
|
+
this.canisterContext,
|
|
6048
|
+
request.poolId
|
|
6049
|
+
);
|
|
5443
6050
|
const selectedAsset = selectedPool.asset;
|
|
5444
6051
|
const minimumWithdrawAmountError = getWithdrawAmountMinimumValidationError({
|
|
5445
6052
|
amount: request.amount,
|
|
@@ -5451,41 +6058,52 @@ var LendingModule = class {
|
|
|
5451
6058
|
minimumWithdrawAmountError.message
|
|
5452
6059
|
);
|
|
5453
6060
|
}
|
|
5454
|
-
const
|
|
5455
|
-
|
|
6061
|
+
const receiver = parseOutflowDestination({
|
|
6062
|
+
destination,
|
|
5456
6063
|
asset: selectedAsset,
|
|
5457
|
-
|
|
6064
|
+
poolChain: selectedPool.chain,
|
|
6065
|
+
destinationChain: request.chain
|
|
5458
6066
|
});
|
|
5459
6067
|
const lendingActor = createLendingActor(this.canisterContext);
|
|
5460
6068
|
try {
|
|
5461
6069
|
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
5462
6070
|
const nonce = await lendingActor.get_nonce(signerAccount);
|
|
5463
|
-
const
|
|
6071
|
+
const withdrawActionData = {
|
|
5464
6072
|
profileId: request.profileId,
|
|
5465
6073
|
poolId: request.poolId,
|
|
5466
6074
|
amount: request.amount,
|
|
5467
|
-
|
|
6075
|
+
chain: request.chain,
|
|
6076
|
+
receiver: {
|
|
6077
|
+
address: receiver.address,
|
|
6078
|
+
type: receiver.accountType
|
|
6079
|
+
},
|
|
5468
6080
|
signerWalletAddress: signerAccount,
|
|
5469
6081
|
expiryTimestamp
|
|
5470
6082
|
};
|
|
6083
|
+
const withdrawSubmissionData = {
|
|
6084
|
+
...withdrawActionData,
|
|
6085
|
+
receiverAccount: receiver.canisterAccount
|
|
6086
|
+
};
|
|
5471
6087
|
return {
|
|
5472
6088
|
kind: WalletActionKind.createWithdraw,
|
|
5473
6089
|
executionKind: WalletExecutionKind.signMessage,
|
|
5474
6090
|
actionType: WalletActionKind.createWithdraw,
|
|
5475
|
-
transferMode: TransferMode.native,
|
|
5476
6091
|
account: signerAccount,
|
|
5477
6092
|
message: createWithdrawAssetMessage(
|
|
5478
6093
|
{
|
|
5479
6094
|
pool_id: request.poolId,
|
|
5480
6095
|
amount: request.amount.toString(),
|
|
5481
|
-
account:
|
|
6096
|
+
account: receiver.messageAccount,
|
|
5482
6097
|
expiry_timestamp: expiryTimestamp
|
|
5483
6098
|
},
|
|
5484
6099
|
nonce
|
|
5485
6100
|
),
|
|
5486
|
-
data:
|
|
6101
|
+
data: withdrawActionData,
|
|
5487
6102
|
submit: async (signatureInfo) => {
|
|
5488
|
-
return await this.submitWithdraw(
|
|
6103
|
+
return await this.submitWithdraw(
|
|
6104
|
+
withdrawSubmissionData,
|
|
6105
|
+
signatureInfo
|
|
6106
|
+
);
|
|
5489
6107
|
}
|
|
5490
6108
|
};
|
|
5491
6109
|
} catch (error) {
|
|
@@ -5502,7 +6120,7 @@ var LendingModule = class {
|
|
|
5502
6120
|
{
|
|
5503
6121
|
data: {
|
|
5504
6122
|
expiry_timestamp: request.expiryTimestamp,
|
|
5505
|
-
account:
|
|
6123
|
+
account: request.receiverAccount,
|
|
5506
6124
|
pool_id: Principal.fromText(request.poolId),
|
|
5507
6125
|
amount: request.amount
|
|
5508
6126
|
},
|
|
@@ -5558,16 +6176,13 @@ var LendingModule = class {
|
|
|
5558
6176
|
* @returns A signable {@link BorrowAction} with `submit` wired to the canister.
|
|
5559
6177
|
*/
|
|
5560
6178
|
async prepareBorrow(request) {
|
|
5561
|
-
const
|
|
6179
|
+
const destination = resolveOutflowDestinationInput({
|
|
6180
|
+
receiver: request.receiver,
|
|
6181
|
+
errorMessage: "Borrow requires a custom outflow account"
|
|
6182
|
+
});
|
|
5562
6183
|
const signerAccount = normalizeEvmAddress(
|
|
5563
6184
|
request.signerWalletAddress.trim()
|
|
5564
6185
|
);
|
|
5565
|
-
if (!destinationAccount) {
|
|
5566
|
-
throw new LiquidiumError(
|
|
5567
|
-
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
5568
|
-
"Borrow requires a custom outflow account"
|
|
5569
|
-
);
|
|
5570
|
-
}
|
|
5571
6186
|
if (!signerAccount) {
|
|
5572
6187
|
throw new LiquidiumError(
|
|
5573
6188
|
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
@@ -5580,7 +6195,10 @@ var LendingModule = class {
|
|
|
5580
6195
|
"Borrow amount must be greater than 0"
|
|
5581
6196
|
);
|
|
5582
6197
|
}
|
|
5583
|
-
const selectedPool = await
|
|
6198
|
+
const selectedPool = await getPoolById(
|
|
6199
|
+
this.canisterContext,
|
|
6200
|
+
request.poolId
|
|
6201
|
+
);
|
|
5584
6202
|
const selectedAsset = selectedPool.asset;
|
|
5585
6203
|
const minimumBorrowAmountError = getBorrowAmountMinimumValidationError({
|
|
5586
6204
|
amount: request.amount,
|
|
@@ -5592,41 +6210,49 @@ var LendingModule = class {
|
|
|
5592
6210
|
minimumBorrowAmountError.message
|
|
5593
6211
|
);
|
|
5594
6212
|
}
|
|
5595
|
-
const
|
|
5596
|
-
|
|
6213
|
+
const receiver = parseOutflowDestination({
|
|
6214
|
+
destination,
|
|
5597
6215
|
asset: selectedAsset,
|
|
5598
|
-
|
|
6216
|
+
poolChain: selectedPool.chain,
|
|
6217
|
+
destinationChain: request.chain
|
|
5599
6218
|
});
|
|
5600
6219
|
const lendingActor = createLendingActor(this.canisterContext);
|
|
5601
6220
|
try {
|
|
5602
6221
|
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
5603
6222
|
const nonce = await lendingActor.get_nonce(signerAccount);
|
|
5604
|
-
const
|
|
6223
|
+
const borrowActionData = {
|
|
5605
6224
|
profileId: request.profileId,
|
|
5606
6225
|
poolId: request.poolId,
|
|
5607
6226
|
amount: request.amount,
|
|
5608
|
-
|
|
6227
|
+
chain: request.chain,
|
|
6228
|
+
receiver: {
|
|
6229
|
+
address: receiver.address,
|
|
6230
|
+
type: receiver.accountType
|
|
6231
|
+
},
|
|
5609
6232
|
signerWalletAddress: signerAccount,
|
|
5610
6233
|
expiryTimestamp
|
|
5611
6234
|
};
|
|
6235
|
+
const borrowSubmissionData = {
|
|
6236
|
+
...borrowActionData,
|
|
6237
|
+
receiverAccount: receiver.canisterAccount
|
|
6238
|
+
};
|
|
5612
6239
|
return {
|
|
5613
6240
|
kind: WalletActionKind.createBorrow,
|
|
5614
6241
|
executionKind: WalletExecutionKind.signMessage,
|
|
5615
6242
|
actionType: WalletActionKind.createBorrow,
|
|
5616
|
-
transferMode: TransferMode.native,
|
|
5617
6243
|
account: signerAccount,
|
|
5618
6244
|
message: createBorrowAssetMessage(
|
|
5619
6245
|
{
|
|
5620
6246
|
pool_id: request.poolId,
|
|
5621
6247
|
amount: request.amount.toString(),
|
|
5622
|
-
account:
|
|
6248
|
+
account: receiver.messageAccount,
|
|
5623
6249
|
expiry_timestamp: expiryTimestamp
|
|
5624
6250
|
},
|
|
5625
6251
|
nonce
|
|
5626
6252
|
),
|
|
5627
|
-
data:
|
|
6253
|
+
data: borrowActionData,
|
|
5628
6254
|
submit: async (signatureInfo) => {
|
|
5629
|
-
return await this.submitBorrow(
|
|
6255
|
+
return await this.submitBorrow(borrowSubmissionData, signatureInfo);
|
|
5630
6256
|
}
|
|
5631
6257
|
};
|
|
5632
6258
|
} catch (error) {
|
|
@@ -5643,7 +6269,7 @@ var LendingModule = class {
|
|
|
5643
6269
|
).borrow_assets(Principal.fromText(request.profileId), {
|
|
5644
6270
|
data: {
|
|
5645
6271
|
expiry_timestamp: request.expiryTimestamp,
|
|
5646
|
-
account:
|
|
6272
|
+
account: request.receiverAccount,
|
|
5647
6273
|
pool_id: Principal.fromText(request.poolId),
|
|
5648
6274
|
amount: request.amount
|
|
5649
6275
|
},
|
|
@@ -5761,11 +6387,18 @@ var LendingModule = class {
|
|
|
5761
6387
|
*
|
|
5762
6388
|
* ETH stablecoin deposit-address estimates are served by the deposit-address
|
|
5763
6389
|
* canister. BTC estimates include the ckBTC minter deposit fee and ledger fee.
|
|
6390
|
+
* ICP-chain estimates return the corresponding ICRC ledger fee.
|
|
5764
6391
|
*
|
|
5765
6392
|
* @param request - Asset and chain pair to estimate for.
|
|
5766
6393
|
* @returns Total fee estimate rounded up in the asset's base units.
|
|
5767
6394
|
*/
|
|
5768
6395
|
async estimateInflowFee(request) {
|
|
6396
|
+
if (request.chain === Chain.ICP) {
|
|
6397
|
+
const ledgerFee = await this.estimateIcrcLedgerFee(request);
|
|
6398
|
+
return {
|
|
6399
|
+
totalFee: roundInflowFeeEstimate(request, ledgerFee)
|
|
6400
|
+
};
|
|
6401
|
+
}
|
|
5769
6402
|
if (isEthStablecoin(request.asset, request.chain)) {
|
|
5770
6403
|
const result = await createDepositAccountsActor(
|
|
5771
6404
|
this.canisterContext
|
|
@@ -5795,6 +6428,14 @@ var LendingModule = class {
|
|
|
5795
6428
|
]);
|
|
5796
6429
|
return { totalFee: minterFee + ledgerFee };
|
|
5797
6430
|
}
|
|
6431
|
+
async estimateIcrcLedgerFee(request) {
|
|
6432
|
+
const route = getInflowFeeLedgerAssetRoute(request);
|
|
6433
|
+
return await createIcrcLedgerActor({
|
|
6434
|
+
canisterContext: this.canisterContext,
|
|
6435
|
+
canisterId: route.ledgerCanisterId,
|
|
6436
|
+
ledgerName: `${request.asset} ${request.chain}`
|
|
6437
|
+
}).icrc1_fee();
|
|
6438
|
+
}
|
|
5798
6439
|
/**
|
|
5799
6440
|
* Submits an inflow transaction id for faster indexing.
|
|
5800
6441
|
*
|
|
@@ -5804,6 +6445,12 @@ var LendingModule = class {
|
|
|
5804
6445
|
* @returns Acknowledgement including the submitted `txid`.
|
|
5805
6446
|
*/
|
|
5806
6447
|
async submitInflow(request) {
|
|
6448
|
+
if (request.chain !== void 0 && request.chain !== Chain.BTC && request.chain !== Chain.ETH) {
|
|
6449
|
+
throw new LiquidiumError(
|
|
6450
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
6451
|
+
`Inflow submission is not supported for ${String(request.chain)}`
|
|
6452
|
+
);
|
|
6453
|
+
}
|
|
5807
6454
|
const apiClient = this.requireApi();
|
|
5808
6455
|
const response = await apiClient.post(SdkApiPath.inflow, request);
|
|
5809
6456
|
return {
|
|
@@ -5843,30 +6490,39 @@ var LendingModule = class {
|
|
|
5843
6490
|
return new SupplyFlowExecutor({
|
|
5844
6491
|
canisterContext: this.canisterContext,
|
|
5845
6492
|
evmReadClient: this.evmReadClient,
|
|
5846
|
-
getPoolById: async (poolId) => await this.getPoolById(poolId),
|
|
5847
6493
|
requireApi: () => {
|
|
5848
6494
|
this.requireApi();
|
|
5849
6495
|
},
|
|
5850
6496
|
submitInflow: async (request) => await this.submitInflow(request)
|
|
5851
6497
|
});
|
|
5852
6498
|
}
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
6499
|
+
};
|
|
6500
|
+
function getInflowFeeLedgerAssetRoute(request) {
|
|
6501
|
+
if (request.chain !== Chain.ICP) {
|
|
6502
|
+
throw new LiquidiumError(
|
|
6503
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
6504
|
+
`IC ledger inflow fees are not supported for ${request.asset} on ${request.chain}`
|
|
5859
6505
|
);
|
|
5860
|
-
const decodedPool = selectedPool ? decodeFlexiblePool(selectedPool) : null;
|
|
5861
|
-
if (!decodedPool) {
|
|
5862
|
-
throw new LiquidiumError(
|
|
5863
|
-
LiquidiumErrorCode.POOL_NOT_FOUND,
|
|
5864
|
-
`Pool not found: ${poolId}`
|
|
5865
|
-
);
|
|
5866
|
-
}
|
|
5867
|
-
return decodedPool;
|
|
5868
6506
|
}
|
|
5869
|
-
|
|
6507
|
+
return getPoolLedgerAssetRoute(request);
|
|
6508
|
+
}
|
|
6509
|
+
function resolveOutflowDestinationInput(params) {
|
|
6510
|
+
const receiver = params.receiver;
|
|
6511
|
+
const address = typeof receiver === "string" ? receiver.trim() : receiver.address.trim();
|
|
6512
|
+
if (!address) {
|
|
6513
|
+
throw new LiquidiumError(
|
|
6514
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
6515
|
+
params.errorMessage
|
|
6516
|
+
);
|
|
6517
|
+
}
|
|
6518
|
+
if (typeof receiver === "string") {
|
|
6519
|
+
return address;
|
|
6520
|
+
}
|
|
6521
|
+
return {
|
|
6522
|
+
address,
|
|
6523
|
+
type: receiver.type
|
|
6524
|
+
};
|
|
6525
|
+
}
|
|
5870
6526
|
function mapExpectedOutflowDetails(details, expectedOutflowType, operation) {
|
|
5871
6527
|
if (details.outflowType !== expectedOutflowType) {
|
|
5872
6528
|
throw new LiquidiumError(
|
|
@@ -5960,6 +6616,12 @@ function formatPrice(price, decimals) {
|
|
|
5960
6616
|
|
|
5961
6617
|
// src/modules/market/market.ts
|
|
5962
6618
|
var ZERO_POOL_RATE = [0n, 0n, 0n];
|
|
6619
|
+
var BACKING_POOL_CHAIN_BY_ASSET = {
|
|
6620
|
+
[Asset.BTC]: Chain.BTC,
|
|
6621
|
+
[Asset.ICP]: Chain.ICP,
|
|
6622
|
+
[Asset.USDC]: Chain.ETH,
|
|
6623
|
+
[Asset.USDT]: Chain.ETH
|
|
6624
|
+
};
|
|
5963
6625
|
var MarketModule = class {
|
|
5964
6626
|
constructor(canisterContext) {
|
|
5965
6627
|
this.canisterContext = canisterContext;
|
|
@@ -6017,15 +6679,26 @@ var MarketModule = class {
|
|
|
6017
6679
|
}
|
|
6018
6680
|
}
|
|
6019
6681
|
/**
|
|
6020
|
-
* Resolves a single pool for the given
|
|
6682
|
+
* Resolves a single backing pool for the given Chain + Asset identifier.
|
|
6683
|
+
*
|
|
6684
|
+
* Native and chain-key identifiers share a pool. For example, both
|
|
6685
|
+
* `ETH/USDT` and `ICP/USDT` resolve to the USDT lending pool.
|
|
6021
6686
|
*
|
|
6022
6687
|
* @param query - The market asset and chain pair to match.
|
|
6023
6688
|
* @returns The single pool that matches the requested asset and chain.
|
|
6024
6689
|
*/
|
|
6025
6690
|
async findPool(query) {
|
|
6691
|
+
const identifier = { chain: query.chain, asset: query.asset };
|
|
6692
|
+
if (!isAssetIdentifier(identifier)) {
|
|
6693
|
+
throw new LiquidiumError(
|
|
6694
|
+
LiquidiumErrorCode.VALIDATION_ERROR,
|
|
6695
|
+
`Unsupported asset identifier: ${identifier.chain}/${identifier.asset}`
|
|
6696
|
+
);
|
|
6697
|
+
}
|
|
6026
6698
|
const pools = await this.listPools();
|
|
6699
|
+
const backingPoolChain = BACKING_POOL_CHAIN_BY_ASSET[identifier.asset];
|
|
6027
6700
|
const matchedPools = pools.filter(
|
|
6028
|
-
(pool) => pool.asset ===
|
|
6701
|
+
(pool) => pool.asset === identifier.asset && pool.chain === backingPoolChain
|
|
6029
6702
|
);
|
|
6030
6703
|
if (matchedPools.length === 0) {
|
|
6031
6704
|
throw new LiquidiumError(
|
|
@@ -6446,6 +7119,6 @@ function resolveEvmReadClient(config) {
|
|
|
6446
7119
|
});
|
|
6447
7120
|
}
|
|
6448
7121
|
|
|
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,
|
|
7122
|
+
export { AccountsModule, ActivitiesModule, ActivityFilter, Asset, CK_ETH_DEPOSIT_CONTRACT_ADDRESS, Chain, Environment, EvmSupplyApprovalStrategy, HistoryModule, InstantLoanCreatedError, InstantLoansModule, LendingModule, LiquidiumAccountType, 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, USDC_CONTRACT_ADDRESS, USDT_CONTRACT_ADDRESS, WalletActionKind, WalletExecutionKind, createTransferErc20Transaction, executeWith, getMinimumBorrowAmount, getMinimumWithdrawAmount, intFromPublicId, isAssetIdentifier, publicIdFromInt };
|
|
6450
7123
|
//# sourceMappingURL=index.js.map
|
|
6451
7124
|
//# sourceMappingURL=index.js.map
|