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 CHANGED
@@ -2754,9 +2754,7 @@ var nearRpcUrls = {
2754
2754
  "https://near.drpc.org"
2755
2755
  ],
2756
2756
  testnet: [
2757
- "https://rpc.testnet.near.org",
2758
- "https://near-testnet.lava.build",
2759
- "https://near-testnet.drpc.org"
2757
+ "https://rpc.testnet.near.org"
2760
2758
  ]
2761
2759
  };
2762
2760
  var btcRpcUrls = {
@@ -2860,29 +2858,38 @@ function pollTransactionStatuses(network, hashes) {
2860
2858
  (url) => new import_near_api_js.providers.JsonRpcProvider({ url })
2861
2859
  )
2862
2860
  );
2863
- const maxAttempts = 3;
2864
- const pollStatus = (hash) => __async(this, null, function* () {
2865
- let attempt = 0;
2866
- while (attempt < maxAttempts) {
2867
- attempt++;
2861
+ const maxAttempts = 30;
2862
+ let currentAttempt = 0;
2863
+ const pendingHashes = new Set(hashes);
2864
+ const results = /* @__PURE__ */ new Map();
2865
+ while (pendingHashes.size > 0 && currentAttempt < maxAttempts) {
2866
+ currentAttempt++;
2867
+ const promises = Array.from(pendingHashes).map((hash) => __async(this, null, function* () {
2868
2868
  try {
2869
2869
  const result = yield provider.txStatus(hash, "unused", "FINAL");
2870
2870
  if (result && result.status) {
2871
2871
  console.log(`Transaction ${hash} result:`, result);
2872
- return result;
2872
+ results.set(hash, result);
2873
+ pendingHashes.delete(hash);
2873
2874
  }
2874
2875
  } catch (error) {
2875
2876
  console.error(`Failed to fetch transaction status for ${hash}: ${error.message}`);
2876
2877
  }
2877
- if (attempt === maxAttempts) {
2878
- throw new Error(`Transaction not found after max attempts: ${hash}`);
2878
+ }));
2879
+ yield Promise.all(promises);
2880
+ if (pendingHashes.size > 0) {
2881
+ if (currentAttempt === maxAttempts) {
2882
+ throw new Error(
2883
+ `Transactions not found after max attempts: ${Array.from(pendingHashes).join(", ")}`
2884
+ );
2879
2885
  }
2886
+ console.log(
2887
+ `Waiting for ${pendingHashes.size} transactions, retrying ${maxAttempts - currentAttempt} more times`
2888
+ );
2880
2889
  yield delay(1e4);
2881
- console.log(`RPC request failed for ${hash}, retrying ${maxAttempts - attempt} more times`);
2882
2890
  }
2883
- });
2884
- const results = yield Promise.all(hashes.map((hash) => pollStatus(hash)));
2885
- return results;
2891
+ }
2892
+ return hashes.map((hash) => results.get(hash));
2886
2893
  });
2887
2894
  }
2888
2895
 
@@ -3088,80 +3095,31 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3088
3095
  return __async(this, null, function* () {
3089
3096
  const btcContext = window.btcContext;
3090
3097
  const accountId = state.getAccount();
3091
- const publicKey = state.getPublicKey();
3092
- const { header } = yield provider.block({ finality: "final" });
3093
- const rawAccessKey = yield provider.query({
3094
- request_type: "view_access_key",
3095
- account_id: accountId,
3096
- public_key: publicKey,
3097
- finality: "final"
3098
- });
3099
- const accessKey = __spreadProps(__spreadValues({}, rawAccessKey), {
3100
- nonce: BigInt(rawAccessKey.nonce || 0)
3101
- });
3102
- const publicKeyFormat = import_key_pair.PublicKey.from(publicKey);
3103
- const { result_data: nearNonceFromApi } = yield getNearNonceFromApi(
3104
- currentConfig.base_url,
3105
- accountId
3106
- );
3107
- const { transferGasTransaction, useNearPayGas } = yield getGasConfig();
3098
+ const trans = [...params.transactions];
3099
+ console.log("raw trans:", trans);
3100
+ const { transferGasTransaction, useNearPayGas, gasLimit } = yield calculateGasStrategy(trans);
3108
3101
  console.log("transferGasTransaction:", transferGasTransaction);
3109
3102
  console.log("useNearPayGas:", useNearPayGas);
3110
- if (!useNearPayGas && transferGasTransaction) {
3111
- params.transactions.unshift(transferGasTransaction);
3112
- }
3113
- console.log("raw transactions:", params.transactions);
3114
- const newTransactions = params.transactions.map((transaction, index) => {
3115
- let nearNonceNumber = accessKey.nonce + BigInt(1);
3116
- if (nearNonceFromApi) {
3117
- nearNonceNumber = BigInt(nearNonceFromApi) > nearNonceNumber ? BigInt(nearNonceFromApi) : nearNonceNumber;
3118
- }
3119
- const newActions = transaction.actions.map((action) => {
3120
- switch (action.type) {
3121
- case "FunctionCall":
3122
- return functionCall(
3123
- action.params.methodName,
3124
- action.params.args,
3125
- BigInt(action.params.gas),
3126
- BigInt(action.params.deposit)
3127
- );
3128
- case "Transfer":
3129
- return transfer(BigInt(action.params.deposit));
3130
- }
3131
- }).filter(Boolean);
3132
- const _transaction = import_near_api_js2.transactions.createTransaction(
3133
- accountId,
3134
- publicKeyFormat,
3135
- transaction.receiverId,
3136
- BigInt(nearNonceNumber) + BigInt(index),
3137
- newActions,
3138
- (0, import_utils5.baseDecode)(header.hash)
3139
- );
3140
- const txBytes = (0, import_transaction.encodeTransaction)(_transaction);
3141
- const txHex = Array.from(
3142
- txBytes,
3143
- (byte) => ("0" + (byte & 255).toString(16)).slice(-2)
3144
- ).join("");
3145
- console.log("txHex:", txHex);
3146
- const hash = import_bs58.default.encode(new Uint8Array(import_js_sha256.sha256.array(txBytes)));
3147
- return { txBytes, txHex, hash };
3148
- });
3149
- const accountInfo = yield nearCall2(
3150
- currentConfig.accountContractId,
3151
- "get_account",
3152
- { account_id: accountId }
3103
+ console.log("gasLimit:", gasLimit);
3104
+ if (transferGasTransaction) {
3105
+ trans.unshift(transferGasTransaction);
3106
+ }
3107
+ console.log("calculateGasStrategy trans:", trans);
3108
+ const newTrans = yield Promise.all(
3109
+ trans.map((transaction, index) => convertTransactionToTxHex(transaction, index))
3153
3110
  );
3154
3111
  const { result_data: nonceFromApi } = yield getNonceFromApi(
3155
3112
  currentConfig.base_url,
3156
3113
  accountId
3157
3114
  );
3115
+ const accountInfo = yield getAccountInfo();
3158
3116
  const nonce = Number(nonceFromApi) > Number(accountInfo.nonce) ? String(nonceFromApi) : String(accountInfo.nonce);
3159
3117
  const intention = {
3160
3118
  chain_id: "397",
3161
3119
  csna: accountId,
3162
- near_transactions: newTransactions.map((t) => t.txHex),
3120
+ near_transactions: newTrans.map((t) => t.txHex),
3163
3121
  gas_token: currentConfig.token,
3164
- gas_limit: currentConfig.gasTokenLimit,
3122
+ gas_limit: gasLimit,
3165
3123
  use_near_pay_gas: useNearPayGas,
3166
3124
  nonce
3167
3125
  };
@@ -3173,7 +3131,7 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3173
3131
  data: toHex(strIntention)
3174
3132
  });
3175
3133
  if (result.result_code === 0) {
3176
- const hash = newTransactions.map((t) => t.hash);
3134
+ const hash = newTrans.map((t) => t.hash);
3177
3135
  console.log("txHash:", hash);
3178
3136
  const result2 = yield pollTransactionStatuses(options.network.networkId, hash);
3179
3137
  return result2;
@@ -3182,8 +3140,71 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3182
3140
  }
3183
3141
  });
3184
3142
  }
3185
- function getGasConfig() {
3143
+ function getAccountInfo() {
3144
+ return __async(this, null, function* () {
3145
+ const accountId = state.getAccount();
3146
+ const accountInfo = yield nearCall2(
3147
+ currentConfig.accountContractId,
3148
+ "get_account",
3149
+ { account_id: accountId }
3150
+ );
3151
+ return accountInfo;
3152
+ });
3153
+ }
3154
+ function createGasTokenTransfer(accountId, amount) {
3155
+ return __async(this, null, function* () {
3156
+ return {
3157
+ signerId: accountId,
3158
+ receiverId: currentConfig.token,
3159
+ actions: [
3160
+ {
3161
+ type: "FunctionCall",
3162
+ params: {
3163
+ methodName: "ft_transfer_call",
3164
+ args: {
3165
+ receiver_id: currentConfig.accountContractId,
3166
+ amount,
3167
+ msg: JSON.stringify("Deposit")
3168
+ },
3169
+ gas: new import_big.default(50).mul(__pow(10, 12)).toFixed(0),
3170
+ deposit: "1"
3171
+ }
3172
+ }
3173
+ ]
3174
+ };
3175
+ });
3176
+ }
3177
+ function recalculateGasWithTransfer(transferTx, transactions2, useNearPayGas, perTxFee) {
3178
+ return __async(this, null, function* () {
3179
+ const { txHex: transferTxHex } = yield convertTransactionToTxHex(transferTx);
3180
+ let newGasLimit;
3181
+ if (useNearPayGas && perTxFee) {
3182
+ newGasLimit = new import_big.default(perTxFee).mul(transactions2.length + 1).toFixed(0);
3183
+ } else {
3184
+ newGasLimit = yield getPredictedGasAmount(
3185
+ currentConfig.accountContractId,
3186
+ currentConfig.token,
3187
+ [transferTxHex, ...transactions2.map((t) => t.txHex)]
3188
+ );
3189
+ }
3190
+ transferTx.actions[0].params.args.amount = newGasLimit;
3191
+ return { transferGasTransaction: transferTx, useNearPayGas, gasLimit: newGasLimit };
3192
+ });
3193
+ }
3194
+ function getPredictedGasAmount(accountContractId, tokenId, transactions2) {
3195
+ return __async(this, null, function* () {
3196
+ const predictedGas = yield nearCall2(accountContractId, "predict_txs_gas_token_amount", {
3197
+ gas_token_id: tokenId,
3198
+ near_transactions: transactions2
3199
+ });
3200
+ const predictedGasAmount = new import_big.default(predictedGas).mul(1.2).toFixed(0);
3201
+ console.log("predictedGas:", predictedGasAmount);
3202
+ return predictedGasAmount;
3203
+ });
3204
+ }
3205
+ function calculateGasStrategy(transactions2) {
3186
3206
  return __async(this, null, function* () {
3207
+ var _a;
3187
3208
  const accountId = state.getAccount();
3188
3209
  const nearAccount = yield provider.query({
3189
3210
  request_type: "view_account",
@@ -3191,39 +3212,107 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3191
3212
  finality: "final"
3192
3213
  });
3193
3214
  const availableBalance = parseFloat(nearAccount.amount) / __pow(10, 24);
3215
+ console.log("available near balance:", availableBalance);
3216
+ const accountInfo = yield getAccountInfo();
3217
+ const gasTokenBalance = accountInfo.gas_token[currentConfig.token] || "0";
3218
+ console.log("available gas token balance:", gasTokenBalance);
3219
+ const convertTx = yield Promise.all(
3220
+ transactions2.map((transaction, index) => convertTransactionToTxHex(transaction, index))
3221
+ );
3194
3222
  if (availableBalance > 0.2) {
3195
- return { useNearPayGas: true };
3223
+ const gasTokens = yield nearCall2(
3224
+ currentConfig.accountContractId,
3225
+ "list_gas_token",
3226
+ { token_ids: [currentConfig.token] }
3227
+ );
3228
+ console.log("list_gas_token gas tokens:", gasTokens);
3229
+ const perTxFee = Math.max(
3230
+ Number(((_a = gasTokens[currentConfig.token]) == null ? void 0 : _a.per_tx_protocol_fee) || 0),
3231
+ 100
3232
+ );
3233
+ console.log("perTxFee:", perTxFee);
3234
+ const protocolFee = new import_big.default(perTxFee || "0").mul(convertTx.length).toFixed(0);
3235
+ console.log("protocolFee:", protocolFee);
3236
+ if (new import_big.default(gasTokenBalance).gte(protocolFee)) {
3237
+ console.log("use near pay gas and enough gas token balance");
3238
+ return { useNearPayGas: true, gasLimit: protocolFee };
3239
+ } else {
3240
+ console.log("use near pay gas and not enough gas token balance");
3241
+ const transferTx = yield createGasTokenTransfer(accountId, protocolFee);
3242
+ return recalculateGasWithTransfer(transferTx, convertTx, true, perTxFee.toString());
3243
+ }
3196
3244
  } else {
3197
- const gasTokenBalance = yield nearCall2(currentConfig.token, "ft_balance_of", {
3198
- account_id: accountId
3199
- });
3200
- if (new import_big.default(gasTokenBalance).gt(currentConfig.gasTokenLimit)) {
3201
- const transferGasTransaction = {
3202
- signerId: accountId,
3203
- receiverId: currentConfig.token,
3204
- actions: [
3205
- {
3206
- type: "FunctionCall",
3207
- params: {
3208
- methodName: "ft_transfer_call",
3209
- args: {
3210
- receiver_id: currentConfig.accountContractId,
3211
- amount: currentConfig.gasTokenLimit,
3212
- msg: "Deposit"
3213
- },
3214
- gas: new import_big.default(50).mul(__pow(10, 12)).toFixed(0),
3215
- deposit: "1"
3216
- }
3217
- }
3218
- ]
3219
- };
3220
- return { transferGasTransaction, useNearPayGas: false };
3245
+ console.log("near balance is not enough, predict the gas token amount required");
3246
+ const adjustedGas = yield getPredictedGasAmount(
3247
+ currentConfig.accountContractId,
3248
+ currentConfig.token,
3249
+ convertTx.map((t) => t.txHex)
3250
+ );
3251
+ if (new import_big.default(gasTokenBalance).gte(adjustedGas)) {
3252
+ console.log("use gas token and gas token balance is enough");
3253
+ return { useNearPayGas: false, gasLimit: adjustedGas };
3221
3254
  } else {
3222
- throw new Error("No enough gas token balance");
3255
+ console.log("use gas token and gas token balance is not enough, need to transfer");
3256
+ const transferTx = yield createGasTokenTransfer(accountId, adjustedGas);
3257
+ return recalculateGasWithTransfer(transferTx, convertTx, false);
3223
3258
  }
3224
3259
  }
3225
3260
  });
3226
3261
  }
3262
+ function convertTransactionToTxHex(transaction, index = 0) {
3263
+ return __async(this, null, function* () {
3264
+ const accountId = state.getAccount();
3265
+ const publicKey = state.getPublicKey();
3266
+ const publicKeyFormat = import_key_pair.PublicKey.from(publicKey);
3267
+ const { header } = yield provider.block({
3268
+ finality: "final"
3269
+ });
3270
+ const rawAccessKey = yield provider.query({
3271
+ request_type: "view_access_key",
3272
+ account_id: accountId,
3273
+ public_key: publicKey,
3274
+ finality: "final"
3275
+ });
3276
+ const accessKey = __spreadProps(__spreadValues({}, rawAccessKey), {
3277
+ nonce: BigInt(rawAccessKey.nonce || 0)
3278
+ });
3279
+ const { result_data: nearNonceFromApi } = yield getNearNonceFromApi(
3280
+ currentConfig.base_url,
3281
+ accountId
3282
+ );
3283
+ let nearNonceNumber = accessKey.nonce + BigInt(1);
3284
+ if (nearNonceFromApi) {
3285
+ nearNonceNumber = BigInt(nearNonceFromApi) > nearNonceNumber ? BigInt(nearNonceFromApi) : nearNonceNumber;
3286
+ }
3287
+ const newActions = transaction.actions.map((action) => {
3288
+ switch (action.type) {
3289
+ case "FunctionCall":
3290
+ return functionCall(
3291
+ action.params.methodName,
3292
+ action.params.args,
3293
+ BigInt(action.params.gas),
3294
+ BigInt(action.params.deposit)
3295
+ );
3296
+ case "Transfer":
3297
+ return transfer(BigInt(action.params.deposit));
3298
+ }
3299
+ }).filter(Boolean);
3300
+ const _transaction = import_near_api_js2.transactions.createTransaction(
3301
+ accountId,
3302
+ publicKeyFormat,
3303
+ transaction.receiverId,
3304
+ BigInt(nearNonceNumber) + BigInt(index),
3305
+ newActions,
3306
+ (0, import_utils5.baseDecode)(header.hash)
3307
+ );
3308
+ const txBytes = (0, import_transaction.encodeTransaction)(_transaction);
3309
+ const txHex = Array.from(txBytes, (byte) => ("0" + (byte & 255).toString(16)).slice(-2)).join(
3310
+ ""
3311
+ );
3312
+ const hash = import_bs58.default.encode(new Uint8Array(import_js_sha256.sha256.array(txBytes)));
3313
+ return { txBytes, txHex, hash };
3314
+ });
3315
+ }
3227
3316
  function initWalletButton(network, wallet2) {
3228
3317
  return __async(this, null, function* () {
3229
3318
  const checkAndSetupWalletButton = () => {
@@ -3256,6 +3345,14 @@ function uploadBTCTx(url, data) {
3256
3345
  body: data
3257
3346
  });
3258
3347
  }
3348
+ function toHex(originalString) {
3349
+ const charArray = originalString.split("");
3350
+ const asciiArray = charArray.map((char) => char.charCodeAt(0));
3351
+ const hexArray = asciiArray.map((code) => code.toString(16));
3352
+ let hexString = hexArray.join("");
3353
+ hexString = hexString.replace(/(^0+)/g, "");
3354
+ return hexString;
3355
+ }
3259
3356
  function setupBTCWallet({
3260
3357
  iconUrl = "https://assets.deltatrade.ai/assets/chain/btc.svg",
3261
3358
  deprecated = false,
@@ -3283,14 +3380,6 @@ function setupBTCWallet({
3283
3380
  });
3284
3381
  return btcWallet;
3285
3382
  }
3286
- function toHex(originalString) {
3287
- const charArray = originalString.split("");
3288
- const asciiArray = charArray.map((char) => char.charCodeAt(0));
3289
- const hexArray = asciiArray.map((code) => code.toString(16));
3290
- let hexString = hexArray.join("");
3291
- hexString = hexString.replace(/(^0+)/g, "");
3292
- return hexString;
3293
- }
3294
3383
 
3295
3384
  // src/core/btcUtils.ts
3296
3385
  var import_big2 = __toESM(require("big.js"), 1);
@@ -3370,18 +3459,23 @@ function getBtcGasPrice() {
3370
3459
  }
3371
3460
  function getBtcBalance() {
3372
3461
  return __async(this, null, function* () {
3373
- const { account } = yield retryOperation(getBtcProvider, (res2) => !!res2.account);
3462
+ const { account } = yield retryOperation(getBtcProvider, (res) => !!res.account);
3374
3463
  if (!account) {
3375
3464
  console.error("BTC Account is not available.");
3376
3465
  return { rawBalance: 0, balance: 0, maxSpendableBalance: 0 };
3377
3466
  }
3378
3467
  const btcRpcUrl = yield getBtcRpcUrl();
3379
- const res = yield fetch(`${btcRpcUrl}/address/${account}/utxo`).then((res2) => res2.json());
3380
- const rawBalance = res == null ? void 0 : res.reduce((acc, cur) => acc + cur.value, 0);
3468
+ const utxos = yield fetch(`${btcRpcUrl}/address/${account}/utxo`).then((res) => res.json());
3469
+ const rawBalance = (utxos == null ? void 0 : utxos.reduce((acc, cur) => acc + cur.value, 0)) || 0;
3381
3470
  const balance = rawBalance / __pow(10, 8);
3382
3471
  const feeRate = yield getBtcGasPrice();
3383
- const maxGasFee = feeRate * 350 / __pow(10, 8);
3384
- const availableBalance = Math.max(0, balance - maxGasFee);
3472
+ const inputSize = ((utxos == null ? void 0 : utxos.length) || 0) * 66;
3473
+ const outputSize = 34;
3474
+ const overheadSize = 10;
3475
+ const estimatedTxSize = inputSize + outputSize + overheadSize;
3476
+ const estimatedFee = estimatedTxSize * feeRate / __pow(10, 8);
3477
+ console.log("estimated fee:", estimatedFee);
3478
+ const availableBalance = Math.max(0, balance - estimatedFee);
3385
3479
  return {
3386
3480
  rawBalance,
3387
3481
  balance,
@@ -3508,7 +3602,7 @@ function executeBTCDepositAndAction(_0) {
3508
3602
 
3509
3603
  // src/index.ts
3510
3604
  var getVersion = () => {
3511
- return "0.3.10";
3605
+ return "0.3.11";
3512
3606
  };
3513
3607
  if (typeof window !== "undefined") {
3514
3608
  window.__PARTICLE_BTC_CONNECT_VERSION = getVersion();