btc-wallet 0.3.10 → 0.3.11
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.js +213 -119
- package/dist/index.js.map +3 -3
- package/dist/utils/nearUtils.d.ts +1 -2
- package/esm/index.js +213 -119
- package/esm/index.js.map +2 -2
- package/package.json +1 -1
@@ -1,7 +1,6 @@
|
|
1
1
|
import type { ProviderService } from '@near-wallet-selector/core/src/lib/services';
|
2
|
-
import { providers } from 'near-api-js';
|
3
2
|
export declare function nearCallFunction<T>(contractId: string, methodName: string, args: any, options: {
|
4
3
|
network?: string;
|
5
4
|
provider?: ProviderService;
|
6
5
|
}): Promise<T>;
|
7
|
-
export declare function pollTransactionStatuses(network: string, hashes: string[]): Promise<
|
6
|
+
export declare function pollTransactionStatuses(network: string, hashes: string[]): Promise<any[]>;
|
package/esm/index.js
CHANGED
@@ -2714,9 +2714,7 @@ var nearRpcUrls = {
|
|
2714
2714
|
"https://near.drpc.org"
|
2715
2715
|
],
|
2716
2716
|
testnet: [
|
2717
|
-
"https://rpc.testnet.near.org"
|
2718
|
-
"https://near-testnet.lava.build",
|
2719
|
-
"https://near-testnet.drpc.org"
|
2717
|
+
"https://rpc.testnet.near.org"
|
2720
2718
|
]
|
2721
2719
|
};
|
2722
2720
|
var btcRpcUrls = {
|
@@ -2820,29 +2818,38 @@ function pollTransactionStatuses(network, hashes) {
|
|
2820
2818
|
(url) => new providers.JsonRpcProvider({ url })
|
2821
2819
|
)
|
2822
2820
|
);
|
2823
|
-
const maxAttempts =
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2821
|
+
const maxAttempts = 30;
|
2822
|
+
let currentAttempt = 0;
|
2823
|
+
const pendingHashes = new Set(hashes);
|
2824
|
+
const results = /* @__PURE__ */ new Map();
|
2825
|
+
while (pendingHashes.size > 0 && currentAttempt < maxAttempts) {
|
2826
|
+
currentAttempt++;
|
2827
|
+
const promises = Array.from(pendingHashes).map((hash) => __async(this, null, function* () {
|
2828
2828
|
try {
|
2829
2829
|
const result = yield provider.txStatus(hash, "unused", "FINAL");
|
2830
2830
|
if (result && result.status) {
|
2831
2831
|
console.log(`Transaction ${hash} result:`, result);
|
2832
|
-
|
2832
|
+
results.set(hash, result);
|
2833
|
+
pendingHashes.delete(hash);
|
2833
2834
|
}
|
2834
2835
|
} catch (error) {
|
2835
2836
|
console.error(`Failed to fetch transaction status for ${hash}: ${error.message}`);
|
2836
2837
|
}
|
2837
|
-
|
2838
|
-
|
2838
|
+
}));
|
2839
|
+
yield Promise.all(promises);
|
2840
|
+
if (pendingHashes.size > 0) {
|
2841
|
+
if (currentAttempt === maxAttempts) {
|
2842
|
+
throw new Error(
|
2843
|
+
`Transactions not found after max attempts: ${Array.from(pendingHashes).join(", ")}`
|
2844
|
+
);
|
2839
2845
|
}
|
2846
|
+
console.log(
|
2847
|
+
`Waiting for ${pendingHashes.size} transactions, retrying ${maxAttempts - currentAttempt} more times`
|
2848
|
+
);
|
2840
2849
|
yield delay(1e4);
|
2841
|
-
console.log(`RPC request failed for ${hash}, retrying ${maxAttempts - attempt} more times`);
|
2842
2850
|
}
|
2843
|
-
}
|
2844
|
-
|
2845
|
-
return results;
|
2851
|
+
}
|
2852
|
+
return hashes.map((hash) => results.get(hash));
|
2846
2853
|
});
|
2847
2854
|
}
|
2848
2855
|
|
@@ -3048,80 +3055,31 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
|
|
3048
3055
|
return __async(this, null, function* () {
|
3049
3056
|
const btcContext = window.btcContext;
|
3050
3057
|
const accountId = state.getAccount();
|
3051
|
-
const
|
3052
|
-
|
3053
|
-
const
|
3054
|
-
request_type: "view_access_key",
|
3055
|
-
account_id: accountId,
|
3056
|
-
public_key: publicKey,
|
3057
|
-
finality: "final"
|
3058
|
-
});
|
3059
|
-
const accessKey = __spreadProps(__spreadValues({}, rawAccessKey), {
|
3060
|
-
nonce: BigInt(rawAccessKey.nonce || 0)
|
3061
|
-
});
|
3062
|
-
const publicKeyFormat = PublicKey.from(publicKey);
|
3063
|
-
const { result_data: nearNonceFromApi } = yield getNearNonceFromApi(
|
3064
|
-
currentConfig.base_url,
|
3065
|
-
accountId
|
3066
|
-
);
|
3067
|
-
const { transferGasTransaction, useNearPayGas } = yield getGasConfig();
|
3058
|
+
const trans = [...params.transactions];
|
3059
|
+
console.log("raw trans:", trans);
|
3060
|
+
const { transferGasTransaction, useNearPayGas, gasLimit } = yield calculateGasStrategy(trans);
|
3068
3061
|
console.log("transferGasTransaction:", transferGasTransaction);
|
3069
3062
|
console.log("useNearPayGas:", useNearPayGas);
|
3070
|
-
|
3071
|
-
|
3072
|
-
|
3073
|
-
|
3074
|
-
|
3075
|
-
|
3076
|
-
|
3077
|
-
nearNonceNumber = BigInt(nearNonceFromApi) > nearNonceNumber ? BigInt(nearNonceFromApi) : nearNonceNumber;
|
3078
|
-
}
|
3079
|
-
const newActions = transaction.actions.map((action) => {
|
3080
|
-
switch (action.type) {
|
3081
|
-
case "FunctionCall":
|
3082
|
-
return functionCall(
|
3083
|
-
action.params.methodName,
|
3084
|
-
action.params.args,
|
3085
|
-
BigInt(action.params.gas),
|
3086
|
-
BigInt(action.params.deposit)
|
3087
|
-
);
|
3088
|
-
case "Transfer":
|
3089
|
-
return transfer(BigInt(action.params.deposit));
|
3090
|
-
}
|
3091
|
-
}).filter(Boolean);
|
3092
|
-
const _transaction = transactions.createTransaction(
|
3093
|
-
accountId,
|
3094
|
-
publicKeyFormat,
|
3095
|
-
transaction.receiverId,
|
3096
|
-
BigInt(nearNonceNumber) + BigInt(index),
|
3097
|
-
newActions,
|
3098
|
-
baseDecode(header.hash)
|
3099
|
-
);
|
3100
|
-
const txBytes = encodeTransaction(_transaction);
|
3101
|
-
const txHex = Array.from(
|
3102
|
-
txBytes,
|
3103
|
-
(byte) => ("0" + (byte & 255).toString(16)).slice(-2)
|
3104
|
-
).join("");
|
3105
|
-
console.log("txHex:", txHex);
|
3106
|
-
const hash = bs58.encode(new Uint8Array(sha256.array(txBytes)));
|
3107
|
-
return { txBytes, txHex, hash };
|
3108
|
-
});
|
3109
|
-
const accountInfo = yield nearCall2(
|
3110
|
-
currentConfig.accountContractId,
|
3111
|
-
"get_account",
|
3112
|
-
{ account_id: accountId }
|
3063
|
+
console.log("gasLimit:", gasLimit);
|
3064
|
+
if (transferGasTransaction) {
|
3065
|
+
trans.unshift(transferGasTransaction);
|
3066
|
+
}
|
3067
|
+
console.log("calculateGasStrategy trans:", trans);
|
3068
|
+
const newTrans = yield Promise.all(
|
3069
|
+
trans.map((transaction, index) => convertTransactionToTxHex(transaction, index))
|
3113
3070
|
);
|
3114
3071
|
const { result_data: nonceFromApi } = yield getNonceFromApi(
|
3115
3072
|
currentConfig.base_url,
|
3116
3073
|
accountId
|
3117
3074
|
);
|
3075
|
+
const accountInfo = yield getAccountInfo();
|
3118
3076
|
const nonce = Number(nonceFromApi) > Number(accountInfo.nonce) ? String(nonceFromApi) : String(accountInfo.nonce);
|
3119
3077
|
const intention = {
|
3120
3078
|
chain_id: "397",
|
3121
3079
|
csna: accountId,
|
3122
|
-
near_transactions:
|
3080
|
+
near_transactions: newTrans.map((t) => t.txHex),
|
3123
3081
|
gas_token: currentConfig.token,
|
3124
|
-
gas_limit:
|
3082
|
+
gas_limit: gasLimit,
|
3125
3083
|
use_near_pay_gas: useNearPayGas,
|
3126
3084
|
nonce
|
3127
3085
|
};
|
@@ -3133,7 +3091,7 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
|
|
3133
3091
|
data: toHex(strIntention)
|
3134
3092
|
});
|
3135
3093
|
if (result.result_code === 0) {
|
3136
|
-
const hash =
|
3094
|
+
const hash = newTrans.map((t) => t.hash);
|
3137
3095
|
console.log("txHash:", hash);
|
3138
3096
|
const result2 = yield pollTransactionStatuses(options.network.networkId, hash);
|
3139
3097
|
return result2;
|
@@ -3142,8 +3100,71 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
|
|
3142
3100
|
}
|
3143
3101
|
});
|
3144
3102
|
}
|
3145
|
-
function
|
3103
|
+
function getAccountInfo() {
|
3104
|
+
return __async(this, null, function* () {
|
3105
|
+
const accountId = state.getAccount();
|
3106
|
+
const accountInfo = yield nearCall2(
|
3107
|
+
currentConfig.accountContractId,
|
3108
|
+
"get_account",
|
3109
|
+
{ account_id: accountId }
|
3110
|
+
);
|
3111
|
+
return accountInfo;
|
3112
|
+
});
|
3113
|
+
}
|
3114
|
+
function createGasTokenTransfer(accountId, amount) {
|
3115
|
+
return __async(this, null, function* () {
|
3116
|
+
return {
|
3117
|
+
signerId: accountId,
|
3118
|
+
receiverId: currentConfig.token,
|
3119
|
+
actions: [
|
3120
|
+
{
|
3121
|
+
type: "FunctionCall",
|
3122
|
+
params: {
|
3123
|
+
methodName: "ft_transfer_call",
|
3124
|
+
args: {
|
3125
|
+
receiver_id: currentConfig.accountContractId,
|
3126
|
+
amount,
|
3127
|
+
msg: JSON.stringify("Deposit")
|
3128
|
+
},
|
3129
|
+
gas: new Big(50).mul(__pow(10, 12)).toFixed(0),
|
3130
|
+
deposit: "1"
|
3131
|
+
}
|
3132
|
+
}
|
3133
|
+
]
|
3134
|
+
};
|
3135
|
+
});
|
3136
|
+
}
|
3137
|
+
function recalculateGasWithTransfer(transferTx, transactions2, useNearPayGas, perTxFee) {
|
3138
|
+
return __async(this, null, function* () {
|
3139
|
+
const { txHex: transferTxHex } = yield convertTransactionToTxHex(transferTx);
|
3140
|
+
let newGasLimit;
|
3141
|
+
if (useNearPayGas && perTxFee) {
|
3142
|
+
newGasLimit = new Big(perTxFee).mul(transactions2.length + 1).toFixed(0);
|
3143
|
+
} else {
|
3144
|
+
newGasLimit = yield getPredictedGasAmount(
|
3145
|
+
currentConfig.accountContractId,
|
3146
|
+
currentConfig.token,
|
3147
|
+
[transferTxHex, ...transactions2.map((t) => t.txHex)]
|
3148
|
+
);
|
3149
|
+
}
|
3150
|
+
transferTx.actions[0].params.args.amount = newGasLimit;
|
3151
|
+
return { transferGasTransaction: transferTx, useNearPayGas, gasLimit: newGasLimit };
|
3152
|
+
});
|
3153
|
+
}
|
3154
|
+
function getPredictedGasAmount(accountContractId, tokenId, transactions2) {
|
3155
|
+
return __async(this, null, function* () {
|
3156
|
+
const predictedGas = yield nearCall2(accountContractId, "predict_txs_gas_token_amount", {
|
3157
|
+
gas_token_id: tokenId,
|
3158
|
+
near_transactions: transactions2
|
3159
|
+
});
|
3160
|
+
const predictedGasAmount = new Big(predictedGas).mul(1.2).toFixed(0);
|
3161
|
+
console.log("predictedGas:", predictedGasAmount);
|
3162
|
+
return predictedGasAmount;
|
3163
|
+
});
|
3164
|
+
}
|
3165
|
+
function calculateGasStrategy(transactions2) {
|
3146
3166
|
return __async(this, null, function* () {
|
3167
|
+
var _a;
|
3147
3168
|
const accountId = state.getAccount();
|
3148
3169
|
const nearAccount = yield provider.query({
|
3149
3170
|
request_type: "view_account",
|
@@ -3151,39 +3172,107 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
|
|
3151
3172
|
finality: "final"
|
3152
3173
|
});
|
3153
3174
|
const availableBalance = parseFloat(nearAccount.amount) / __pow(10, 24);
|
3175
|
+
console.log("available near balance:", availableBalance);
|
3176
|
+
const accountInfo = yield getAccountInfo();
|
3177
|
+
const gasTokenBalance = accountInfo.gas_token[currentConfig.token] || "0";
|
3178
|
+
console.log("available gas token balance:", gasTokenBalance);
|
3179
|
+
const convertTx = yield Promise.all(
|
3180
|
+
transactions2.map((transaction, index) => convertTransactionToTxHex(transaction, index))
|
3181
|
+
);
|
3154
3182
|
if (availableBalance > 0.2) {
|
3155
|
-
|
3183
|
+
const gasTokens = yield nearCall2(
|
3184
|
+
currentConfig.accountContractId,
|
3185
|
+
"list_gas_token",
|
3186
|
+
{ token_ids: [currentConfig.token] }
|
3187
|
+
);
|
3188
|
+
console.log("list_gas_token gas tokens:", gasTokens);
|
3189
|
+
const perTxFee = Math.max(
|
3190
|
+
Number(((_a = gasTokens[currentConfig.token]) == null ? void 0 : _a.per_tx_protocol_fee) || 0),
|
3191
|
+
100
|
3192
|
+
);
|
3193
|
+
console.log("perTxFee:", perTxFee);
|
3194
|
+
const protocolFee = new Big(perTxFee || "0").mul(convertTx.length).toFixed(0);
|
3195
|
+
console.log("protocolFee:", protocolFee);
|
3196
|
+
if (new Big(gasTokenBalance).gte(protocolFee)) {
|
3197
|
+
console.log("use near pay gas and enough gas token balance");
|
3198
|
+
return { useNearPayGas: true, gasLimit: protocolFee };
|
3199
|
+
} else {
|
3200
|
+
console.log("use near pay gas and not enough gas token balance");
|
3201
|
+
const transferTx = yield createGasTokenTransfer(accountId, protocolFee);
|
3202
|
+
return recalculateGasWithTransfer(transferTx, convertTx, true, perTxFee.toString());
|
3203
|
+
}
|
3156
3204
|
} else {
|
3157
|
-
|
3158
|
-
|
3159
|
-
|
3160
|
-
|
3161
|
-
|
3162
|
-
|
3163
|
-
|
3164
|
-
|
3165
|
-
|
3166
|
-
type: "FunctionCall",
|
3167
|
-
params: {
|
3168
|
-
methodName: "ft_transfer_call",
|
3169
|
-
args: {
|
3170
|
-
receiver_id: currentConfig.accountContractId,
|
3171
|
-
amount: currentConfig.gasTokenLimit,
|
3172
|
-
msg: "Deposit"
|
3173
|
-
},
|
3174
|
-
gas: new Big(50).mul(__pow(10, 12)).toFixed(0),
|
3175
|
-
deposit: "1"
|
3176
|
-
}
|
3177
|
-
}
|
3178
|
-
]
|
3179
|
-
};
|
3180
|
-
return { transferGasTransaction, useNearPayGas: false };
|
3205
|
+
console.log("near balance is not enough, predict the gas token amount required");
|
3206
|
+
const adjustedGas = yield getPredictedGasAmount(
|
3207
|
+
currentConfig.accountContractId,
|
3208
|
+
currentConfig.token,
|
3209
|
+
convertTx.map((t) => t.txHex)
|
3210
|
+
);
|
3211
|
+
if (new Big(gasTokenBalance).gte(adjustedGas)) {
|
3212
|
+
console.log("use gas token and gas token balance is enough");
|
3213
|
+
return { useNearPayGas: false, gasLimit: adjustedGas };
|
3181
3214
|
} else {
|
3182
|
-
|
3215
|
+
console.log("use gas token and gas token balance is not enough, need to transfer");
|
3216
|
+
const transferTx = yield createGasTokenTransfer(accountId, adjustedGas);
|
3217
|
+
return recalculateGasWithTransfer(transferTx, convertTx, false);
|
3183
3218
|
}
|
3184
3219
|
}
|
3185
3220
|
});
|
3186
3221
|
}
|
3222
|
+
function convertTransactionToTxHex(transaction, index = 0) {
|
3223
|
+
return __async(this, null, function* () {
|
3224
|
+
const accountId = state.getAccount();
|
3225
|
+
const publicKey = state.getPublicKey();
|
3226
|
+
const publicKeyFormat = PublicKey.from(publicKey);
|
3227
|
+
const { header } = yield provider.block({
|
3228
|
+
finality: "final"
|
3229
|
+
});
|
3230
|
+
const rawAccessKey = yield provider.query({
|
3231
|
+
request_type: "view_access_key",
|
3232
|
+
account_id: accountId,
|
3233
|
+
public_key: publicKey,
|
3234
|
+
finality: "final"
|
3235
|
+
});
|
3236
|
+
const accessKey = __spreadProps(__spreadValues({}, rawAccessKey), {
|
3237
|
+
nonce: BigInt(rawAccessKey.nonce || 0)
|
3238
|
+
});
|
3239
|
+
const { result_data: nearNonceFromApi } = yield getNearNonceFromApi(
|
3240
|
+
currentConfig.base_url,
|
3241
|
+
accountId
|
3242
|
+
);
|
3243
|
+
let nearNonceNumber = accessKey.nonce + BigInt(1);
|
3244
|
+
if (nearNonceFromApi) {
|
3245
|
+
nearNonceNumber = BigInt(nearNonceFromApi) > nearNonceNumber ? BigInt(nearNonceFromApi) : nearNonceNumber;
|
3246
|
+
}
|
3247
|
+
const newActions = transaction.actions.map((action) => {
|
3248
|
+
switch (action.type) {
|
3249
|
+
case "FunctionCall":
|
3250
|
+
return functionCall(
|
3251
|
+
action.params.methodName,
|
3252
|
+
action.params.args,
|
3253
|
+
BigInt(action.params.gas),
|
3254
|
+
BigInt(action.params.deposit)
|
3255
|
+
);
|
3256
|
+
case "Transfer":
|
3257
|
+
return transfer(BigInt(action.params.deposit));
|
3258
|
+
}
|
3259
|
+
}).filter(Boolean);
|
3260
|
+
const _transaction = transactions.createTransaction(
|
3261
|
+
accountId,
|
3262
|
+
publicKeyFormat,
|
3263
|
+
transaction.receiverId,
|
3264
|
+
BigInt(nearNonceNumber) + BigInt(index),
|
3265
|
+
newActions,
|
3266
|
+
baseDecode(header.hash)
|
3267
|
+
);
|
3268
|
+
const txBytes = encodeTransaction(_transaction);
|
3269
|
+
const txHex = Array.from(txBytes, (byte) => ("0" + (byte & 255).toString(16)).slice(-2)).join(
|
3270
|
+
""
|
3271
|
+
);
|
3272
|
+
const hash = bs58.encode(new Uint8Array(sha256.array(txBytes)));
|
3273
|
+
return { txBytes, txHex, hash };
|
3274
|
+
});
|
3275
|
+
}
|
3187
3276
|
function initWalletButton(network, wallet2) {
|
3188
3277
|
return __async(this, null, function* () {
|
3189
3278
|
const checkAndSetupWalletButton = () => {
|
@@ -3216,6 +3305,14 @@ function uploadBTCTx(url, data) {
|
|
3216
3305
|
body: data
|
3217
3306
|
});
|
3218
3307
|
}
|
3308
|
+
function toHex(originalString) {
|
3309
|
+
const charArray = originalString.split("");
|
3310
|
+
const asciiArray = charArray.map((char) => char.charCodeAt(0));
|
3311
|
+
const hexArray = asciiArray.map((code) => code.toString(16));
|
3312
|
+
let hexString = hexArray.join("");
|
3313
|
+
hexString = hexString.replace(/(^0+)/g, "");
|
3314
|
+
return hexString;
|
3315
|
+
}
|
3219
3316
|
function setupBTCWallet({
|
3220
3317
|
iconUrl = "https://assets.deltatrade.ai/assets/chain/btc.svg",
|
3221
3318
|
deprecated = false,
|
@@ -3243,14 +3340,6 @@ function setupBTCWallet({
|
|
3243
3340
|
});
|
3244
3341
|
return btcWallet;
|
3245
3342
|
}
|
3246
|
-
function toHex(originalString) {
|
3247
|
-
const charArray = originalString.split("");
|
3248
|
-
const asciiArray = charArray.map((char) => char.charCodeAt(0));
|
3249
|
-
const hexArray = asciiArray.map((code) => code.toString(16));
|
3250
|
-
let hexString = hexArray.join("");
|
3251
|
-
hexString = hexString.replace(/(^0+)/g, "");
|
3252
|
-
return hexString;
|
3253
|
-
}
|
3254
3343
|
|
3255
3344
|
// src/core/btcUtils.ts
|
3256
3345
|
import Big2 from "big.js";
|
@@ -3330,18 +3419,23 @@ function getBtcGasPrice() {
|
|
3330
3419
|
}
|
3331
3420
|
function getBtcBalance() {
|
3332
3421
|
return __async(this, null, function* () {
|
3333
|
-
const { account } = yield retryOperation(getBtcProvider, (
|
3422
|
+
const { account } = yield retryOperation(getBtcProvider, (res) => !!res.account);
|
3334
3423
|
if (!account) {
|
3335
3424
|
console.error("BTC Account is not available.");
|
3336
3425
|
return { rawBalance: 0, balance: 0, maxSpendableBalance: 0 };
|
3337
3426
|
}
|
3338
3427
|
const btcRpcUrl = yield getBtcRpcUrl();
|
3339
|
-
const
|
3340
|
-
const rawBalance =
|
3428
|
+
const utxos = yield fetch(`${btcRpcUrl}/address/${account}/utxo`).then((res) => res.json());
|
3429
|
+
const rawBalance = (utxos == null ? void 0 : utxos.reduce((acc, cur) => acc + cur.value, 0)) || 0;
|
3341
3430
|
const balance = rawBalance / __pow(10, 8);
|
3342
3431
|
const feeRate = yield getBtcGasPrice();
|
3343
|
-
const
|
3344
|
-
const
|
3432
|
+
const inputSize = ((utxos == null ? void 0 : utxos.length) || 0) * 66;
|
3433
|
+
const outputSize = 34;
|
3434
|
+
const overheadSize = 10;
|
3435
|
+
const estimatedTxSize = inputSize + outputSize + overheadSize;
|
3436
|
+
const estimatedFee = estimatedTxSize * feeRate / __pow(10, 8);
|
3437
|
+
console.log("estimated fee:", estimatedFee);
|
3438
|
+
const availableBalance = Math.max(0, balance - estimatedFee);
|
3345
3439
|
return {
|
3346
3440
|
rawBalance,
|
3347
3441
|
balance,
|
@@ -3468,7 +3562,7 @@ function executeBTCDepositAndAction(_0) {
|
|
3468
3562
|
|
3469
3563
|
// src/index.ts
|
3470
3564
|
var getVersion = () => {
|
3471
|
-
return "0.3.
|
3565
|
+
return "0.3.11";
|
3472
3566
|
};
|
3473
3567
|
if (typeof window !== "undefined") {
|
3474
3568
|
window.__PARTICLE_BTC_CONNECT_VERSION = getVersion();
|