@liquidium/client 0.7.0 → 0.7.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/dist/index.cjs +105 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -4
- package/dist/index.d.ts +15 -4
- package/dist/index.js +105 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { Identity, HttpAgent } from '@icp-sdk/core/agent';
|
|
2
2
|
import { PublicClient } from 'viem';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Minimal viem-compatible client shape required for SDK EVM read calls.
|
|
6
|
+
*
|
|
7
|
+
* When `getCode` is present and `chain` identifies Ethereum mainnet, the SDK
|
|
8
|
+
* uses it for a best-effort native ETH contract-destination check. Provider
|
|
9
|
+
* failures fail open and do not block the outflow.
|
|
10
|
+
*/
|
|
11
|
+
interface EvmReadClient {
|
|
12
|
+
readContract: PublicClient["readContract"];
|
|
13
|
+
chain?: PublicClient["chain"];
|
|
14
|
+
getCode?: PublicClient["getCode"];
|
|
15
|
+
}
|
|
6
16
|
/**
|
|
7
17
|
* Runtime options for `new LiquidiumClient(config)`.
|
|
8
18
|
*
|
|
@@ -30,11 +40,11 @@ interface LiquidiumClientConfig {
|
|
|
30
40
|
fetch?: typeof fetch;
|
|
31
41
|
/** Per-request timeout for SDK API calls in milliseconds. */
|
|
32
42
|
timeoutMs?: number;
|
|
33
|
-
/** Ethereum RPC URL used for public ERC-20 reads
|
|
43
|
+
/** Ethereum RPC URL used for best-effort native ETH outflow checks and public ERC-20 reads. */
|
|
34
44
|
evmRpcUrl?: string;
|
|
35
45
|
/** Optional headers for RPC providers that authenticate via HTTP headers. */
|
|
36
46
|
evmRpcHeaders?: Record<string, string>;
|
|
37
|
-
/** Existing viem
|
|
47
|
+
/** Existing viem client; mainnet `chain` and `getCode` enable native ETH outflow checks. */
|
|
38
48
|
evmPublicClient?: EvmReadClient;
|
|
39
49
|
}
|
|
40
50
|
/** Pool canister principal text values grouped by pool asset. */
|
|
@@ -2305,6 +2315,7 @@ declare const LiquidiumErrorCode: {
|
|
|
2305
2315
|
readonly WITHDRAW_TOO_LOW: "WITHDRAW_TOO_LOW";
|
|
2306
2316
|
readonly REPAYMENT_EXCEEDS_DEBT: "REPAYMENT_EXCEEDS_DEBT";
|
|
2307
2317
|
readonly INVALID_ADDRESS: "INVALID_ADDRESS";
|
|
2318
|
+
readonly CONTRACT_DESTINATION_UNSUPPORTED: "CONTRACT_DESTINATION_UNSUPPORTED";
|
|
2308
2319
|
readonly DEPOSIT_ADDRESS_ERROR: "DEPOSIT_ADDRESS_ERROR";
|
|
2309
2320
|
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
2310
2321
|
readonly SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import { Identity, HttpAgent } from '@icp-sdk/core/agent';
|
|
2
2
|
import { PublicClient } from 'viem';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Minimal viem-compatible client shape required for SDK EVM read calls.
|
|
6
|
+
*
|
|
7
|
+
* When `getCode` is present and `chain` identifies Ethereum mainnet, the SDK
|
|
8
|
+
* uses it for a best-effort native ETH contract-destination check. Provider
|
|
9
|
+
* failures fail open and do not block the outflow.
|
|
10
|
+
*/
|
|
11
|
+
interface EvmReadClient {
|
|
12
|
+
readContract: PublicClient["readContract"];
|
|
13
|
+
chain?: PublicClient["chain"];
|
|
14
|
+
getCode?: PublicClient["getCode"];
|
|
15
|
+
}
|
|
6
16
|
/**
|
|
7
17
|
* Runtime options for `new LiquidiumClient(config)`.
|
|
8
18
|
*
|
|
@@ -30,11 +40,11 @@ interface LiquidiumClientConfig {
|
|
|
30
40
|
fetch?: typeof fetch;
|
|
31
41
|
/** Per-request timeout for SDK API calls in milliseconds. */
|
|
32
42
|
timeoutMs?: number;
|
|
33
|
-
/** Ethereum RPC URL used for public ERC-20 reads
|
|
43
|
+
/** Ethereum RPC URL used for best-effort native ETH outflow checks and public ERC-20 reads. */
|
|
34
44
|
evmRpcUrl?: string;
|
|
35
45
|
/** Optional headers for RPC providers that authenticate via HTTP headers. */
|
|
36
46
|
evmRpcHeaders?: Record<string, string>;
|
|
37
|
-
/** Existing viem
|
|
47
|
+
/** Existing viem client; mainnet `chain` and `getCode` enable native ETH outflow checks. */
|
|
38
48
|
evmPublicClient?: EvmReadClient;
|
|
39
49
|
}
|
|
40
50
|
/** Pool canister principal text values grouped by pool asset. */
|
|
@@ -2305,6 +2315,7 @@ declare const LiquidiumErrorCode: {
|
|
|
2305
2315
|
readonly WITHDRAW_TOO_LOW: "WITHDRAW_TOO_LOW";
|
|
2306
2316
|
readonly REPAYMENT_EXCEEDS_DEBT: "REPAYMENT_EXCEEDS_DEBT";
|
|
2307
2317
|
readonly INVALID_ADDRESS: "INVALID_ADDRESS";
|
|
2318
|
+
readonly CONTRACT_DESTINATION_UNSUPPORTED: "CONTRACT_DESTINATION_UNSUPPORTED";
|
|
2308
2319
|
readonly DEPOSIT_ADDRESS_ERROR: "DEPOSIT_ADDRESS_ERROR";
|
|
2309
2320
|
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
2310
2321
|
readonly SERVICE_UNAVAILABLE: "SERVICE_UNAVAILABLE";
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,7 @@ var LiquidiumErrorCode = {
|
|
|
45
45
|
WITHDRAW_TOO_LOW: "WITHDRAW_TOO_LOW",
|
|
46
46
|
REPAYMENT_EXCEEDS_DEBT: "REPAYMENT_EXCEEDS_DEBT",
|
|
47
47
|
INVALID_ADDRESS: "INVALID_ADDRESS",
|
|
48
|
+
CONTRACT_DESTINATION_UNSUPPORTED: "CONTRACT_DESTINATION_UNSUPPORTED",
|
|
48
49
|
DEPOSIT_ADDRESS_ERROR: "DEPOSIT_ADDRESS_ERROR",
|
|
49
50
|
// Transport
|
|
50
51
|
NETWORK_ERROR: "NETWORK_ERROR",
|
|
@@ -1785,6 +1786,11 @@ var HISTORY_ACTIVITIES = `${SDK_API_V2_PATH}/history/activities`;
|
|
|
1785
1786
|
var HISTORY_USERS = `${SDK_API_V2_PATH}/history/users`;
|
|
1786
1787
|
var INFLOW = `${SDK_API_V2_PATH}/inflow`;
|
|
1787
1788
|
var SIMPLE_LOANS = `${SDK_API_V1_PATH}/instant-loans`;
|
|
1789
|
+
function buildEthereumAddressBytecodePath(request) {
|
|
1790
|
+
return `${SDK_API_V2_PATH}/ethereum/addresses/${encodeURIComponent(
|
|
1791
|
+
request.address
|
|
1792
|
+
)}/bytecode`;
|
|
1793
|
+
}
|
|
1788
1794
|
function buildHistoryUserTransactionsPath(profileId, query) {
|
|
1789
1795
|
const base = `${HISTORY_USERS}/${encodeURIComponent(profileId)}/transactions`;
|
|
1790
1796
|
const qs = query.toString();
|
|
@@ -3341,6 +3347,71 @@ function accountTypeToString(accountType) {
|
|
|
3341
3347
|
return `Principal:${accountType.data}`;
|
|
3342
3348
|
}
|
|
3343
3349
|
}
|
|
3350
|
+
var EMPTY_EVM_BYTECODE = "0x";
|
|
3351
|
+
var LAST_ETHEREUM_MAINNET_PRECOMPILE_ADDRESS = 0x11n;
|
|
3352
|
+
var CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE = "Contract addresses are not supported for native ETH withdrawals or borrowing";
|
|
3353
|
+
var RESERVED_DESTINATION_MESSAGE = "Ethereum outflow destination must not be the zero address or a precompile";
|
|
3354
|
+
async function guardEthereumOutflowDestination({
|
|
3355
|
+
address,
|
|
3356
|
+
apiClient,
|
|
3357
|
+
asset,
|
|
3358
|
+
chain,
|
|
3359
|
+
evmReadClient
|
|
3360
|
+
}) {
|
|
3361
|
+
if (chain !== Chain.ETH) {
|
|
3362
|
+
return;
|
|
3363
|
+
}
|
|
3364
|
+
const normalizedAddress = getAddress(address);
|
|
3365
|
+
if (BigInt(normalizedAddress) <= LAST_ETHEREUM_MAINNET_PRECOMPILE_ADDRESS) {
|
|
3366
|
+
throw new LiquidiumError(
|
|
3367
|
+
LiquidiumErrorCode.INVALID_ADDRESS,
|
|
3368
|
+
RESERVED_DESTINATION_MESSAGE
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
3371
|
+
if (asset !== Asset.ETH) {
|
|
3372
|
+
return;
|
|
3373
|
+
}
|
|
3374
|
+
if (evmReadClient?.chain?.id === mainnet.id && evmReadClient.getCode) {
|
|
3375
|
+
let bytecode;
|
|
3376
|
+
try {
|
|
3377
|
+
bytecode = await evmReadClient.getCode({
|
|
3378
|
+
address: normalizedAddress
|
|
3379
|
+
});
|
|
3380
|
+
} catch {
|
|
3381
|
+
return;
|
|
3382
|
+
}
|
|
3383
|
+
if (bytecode === void 0 || bytecode === EMPTY_EVM_BYTECODE) {
|
|
3384
|
+
return;
|
|
3385
|
+
}
|
|
3386
|
+
if (typeof bytecode !== "string" || !/^0x(?:[0-9a-fA-F]{2})*$/.test(bytecode)) {
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3389
|
+
throw new LiquidiumError(
|
|
3390
|
+
LiquidiumErrorCode.CONTRACT_DESTINATION_UNSUPPORTED,
|
|
3391
|
+
CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE
|
|
3392
|
+
);
|
|
3393
|
+
}
|
|
3394
|
+
if (!apiClient) {
|
|
3395
|
+
return;
|
|
3396
|
+
}
|
|
3397
|
+
let response;
|
|
3398
|
+
try {
|
|
3399
|
+
response = await apiClient.get(
|
|
3400
|
+
buildEthereumAddressBytecodePath({ address: normalizedAddress })
|
|
3401
|
+
);
|
|
3402
|
+
} catch {
|
|
3403
|
+
return;
|
|
3404
|
+
}
|
|
3405
|
+
if (!response || typeof response !== "object" || !("hasDeployedBytecode" in response) || typeof response.hasDeployedBytecode !== "boolean") {
|
|
3406
|
+
return;
|
|
3407
|
+
}
|
|
3408
|
+
if (response.hasDeployedBytecode) {
|
|
3409
|
+
throw new LiquidiumError(
|
|
3410
|
+
LiquidiumErrorCode.CONTRACT_DESTINATION_UNSUPPORTED,
|
|
3411
|
+
CONTRACT_DESTINATION_UNSUPPORTED_MESSAGE
|
|
3412
|
+
);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3344
3415
|
|
|
3345
3416
|
// src/core/pool-ledger-assets.ts
|
|
3346
3417
|
function getPoolLedgerAssetRoute(params) {
|
|
@@ -4723,6 +4794,13 @@ var LendingModule = class {
|
|
|
4723
4794
|
poolChain: selectedPool.chain,
|
|
4724
4795
|
destinationChain: request.chain
|
|
4725
4796
|
});
|
|
4797
|
+
await guardEthereumOutflowDestination({
|
|
4798
|
+
address: receiver.address,
|
|
4799
|
+
apiClient: this.apiClient,
|
|
4800
|
+
asset: selectedAsset,
|
|
4801
|
+
chain: request.chain,
|
|
4802
|
+
evmReadClient: this.evmReadClient
|
|
4803
|
+
});
|
|
4726
4804
|
const lendingActor = createLendingActor(this.canisterContext);
|
|
4727
4805
|
try {
|
|
4728
4806
|
const expiryTimestamp = computeExpiryTimestampFromNow();
|
|
@@ -4741,7 +4819,9 @@ var LendingModule = class {
|
|
|
4741
4819
|
};
|
|
4742
4820
|
const withdrawSubmissionData = {
|
|
4743
4821
|
...withdrawActionData,
|
|
4744
|
-
|
|
4822
|
+
asset: selectedAsset,
|
|
4823
|
+
receiverAccount: receiver.canisterAccount,
|
|
4824
|
+
receiverAddress: receiver.address
|
|
4745
4825
|
};
|
|
4746
4826
|
return {
|
|
4747
4827
|
kind: WalletActionKind.createWithdraw,
|
|
@@ -4773,6 +4853,13 @@ var LendingModule = class {
|
|
|
4773
4853
|
}
|
|
4774
4854
|
}
|
|
4775
4855
|
async submitWithdraw(request, signatureInfo) {
|
|
4856
|
+
await guardEthereumOutflowDestination({
|
|
4857
|
+
address: request.receiverAddress,
|
|
4858
|
+
apiClient: this.apiClient,
|
|
4859
|
+
asset: request.asset,
|
|
4860
|
+
chain: request.chain,
|
|
4861
|
+
evmReadClient: this.evmReadClient
|
|
4862
|
+
});
|
|
4776
4863
|
try {
|
|
4777
4864
|
const result = await createLendingActor(this.canisterContext).withdraw(
|
|
4778
4865
|
Principal.fromText(request.profileId),
|
|
@@ -4877,6 +4964,13 @@ var LendingModule = class {
|
|
|
4877
4964
|
poolChain: selectedPool.chain,
|
|
4878
4965
|
destinationChain: request.chain
|
|
4879
4966
|
});
|
|
4967
|
+
await guardEthereumOutflowDestination({
|
|
4968
|
+
address: receiver.address,
|
|
4969
|
+
apiClient: this.apiClient,
|
|
4970
|
+
asset: selectedAsset,
|
|
4971
|
+
chain: request.chain,
|
|
4972
|
+
evmReadClient: this.evmReadClient
|
|
4973
|
+
});
|
|
4880
4974
|
await this.guardBorrowSameAssetPolicy({
|
|
4881
4975
|
profileId: request.profileId,
|
|
4882
4976
|
pool: selectedPool
|
|
@@ -4899,7 +4993,9 @@ var LendingModule = class {
|
|
|
4899
4993
|
};
|
|
4900
4994
|
const borrowSubmissionData = {
|
|
4901
4995
|
...borrowActionData,
|
|
4902
|
-
|
|
4996
|
+
asset: selectedAsset,
|
|
4997
|
+
receiverAccount: receiver.canisterAccount,
|
|
4998
|
+
receiverAddress: receiver.address
|
|
4903
4999
|
};
|
|
4904
5000
|
return {
|
|
4905
5001
|
kind: WalletActionKind.createBorrow,
|
|
@@ -4928,6 +5024,13 @@ var LendingModule = class {
|
|
|
4928
5024
|
}
|
|
4929
5025
|
}
|
|
4930
5026
|
async submitBorrow(request, signatureInfo) {
|
|
5027
|
+
await guardEthereumOutflowDestination({
|
|
5028
|
+
address: request.receiverAddress,
|
|
5029
|
+
apiClient: this.apiClient,
|
|
5030
|
+
asset: request.asset,
|
|
5031
|
+
chain: request.chain,
|
|
5032
|
+
evmReadClient: this.evmReadClient
|
|
5033
|
+
});
|
|
4931
5034
|
try {
|
|
4932
5035
|
const result = await createLendingActor(
|
|
4933
5036
|
this.canisterContext
|