btc-wallet 0.3.9 → 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,77 +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();
3108
- if (!useNearPayGas && transferGasTransaction) {
3109
- params.transactions.unshift(transferGasTransaction);
3110
- }
3111
- const newTransactions = params.transactions.map((transaction, index) => {
3112
- let nearNonceNumber = accessKey.nonce + BigInt(1);
3113
- if (nearNonceFromApi) {
3114
- nearNonceNumber = BigInt(nearNonceFromApi) > nearNonceNumber ? BigInt(nearNonceFromApi) : nearNonceNumber;
3115
- }
3116
- const newActions = transaction.actions.map((action) => {
3117
- switch (action.type) {
3118
- case "FunctionCall":
3119
- return functionCall(
3120
- action.params.methodName,
3121
- action.params.args,
3122
- BigInt(action.params.gas),
3123
- BigInt(action.params.deposit)
3124
- );
3125
- case "Transfer":
3126
- return transfer(BigInt(action.params.deposit));
3127
- }
3128
- }).filter(Boolean);
3129
- const _transaction = import_near_api_js2.transactions.createTransaction(
3130
- accountId,
3131
- publicKeyFormat,
3132
- transaction.receiverId,
3133
- BigInt(nearNonceNumber) + BigInt(index),
3134
- newActions,
3135
- (0, import_utils5.baseDecode)(header.hash)
3136
- );
3137
- const txBytes = (0, import_transaction.encodeTransaction)(_transaction);
3138
- const txHex = Array.from(
3139
- txBytes,
3140
- (byte) => ("0" + (byte & 255).toString(16)).slice(-2)
3141
- ).join("");
3142
- console.log("txHex:", txHex);
3143
- const hash = import_bs58.default.encode(new Uint8Array(import_js_sha256.sha256.array(txBytes)));
3144
- return { txBytes, txHex, hash };
3145
- });
3146
- const accountInfo = yield nearCall2(
3147
- currentConfig.accountContractId,
3148
- "get_account",
3149
- { account_id: accountId }
3098
+ const trans = [...params.transactions];
3099
+ console.log("raw trans:", trans);
3100
+ const { transferGasTransaction, useNearPayGas, gasLimit } = yield calculateGasStrategy(trans);
3101
+ console.log("transferGasTransaction:", transferGasTransaction);
3102
+ console.log("useNearPayGas:", useNearPayGas);
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))
3150
3110
  );
3151
3111
  const { result_data: nonceFromApi } = yield getNonceFromApi(
3152
3112
  currentConfig.base_url,
3153
3113
  accountId
3154
3114
  );
3115
+ const accountInfo = yield getAccountInfo();
3155
3116
  const nonce = Number(nonceFromApi) > Number(accountInfo.nonce) ? String(nonceFromApi) : String(accountInfo.nonce);
3156
3117
  const intention = {
3157
3118
  chain_id: "397",
3158
3119
  csna: accountId,
3159
- near_transactions: newTransactions.map((t) => t.txHex),
3120
+ near_transactions: newTrans.map((t) => t.txHex),
3160
3121
  gas_token: currentConfig.token,
3161
- gas_limit: currentConfig.gasTokenLimit,
3122
+ gas_limit: gasLimit,
3162
3123
  use_near_pay_gas: useNearPayGas,
3163
3124
  nonce
3164
3125
  };
@@ -3170,7 +3131,7 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3170
3131
  data: toHex(strIntention)
3171
3132
  });
3172
3133
  if (result.result_code === 0) {
3173
- const hash = newTransactions.map((t) => t.hash);
3134
+ const hash = newTrans.map((t) => t.hash);
3174
3135
  console.log("txHash:", hash);
3175
3136
  const result2 = yield pollTransactionStatuses(options.network.networkId, hash);
3176
3137
  return result2;
@@ -3179,8 +3140,71 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3179
3140
  }
3180
3141
  });
3181
3142
  }
3182
- function getGasConfig() {
3143
+ function getAccountInfo() {
3183
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) {
3206
+ return __async(this, null, function* () {
3207
+ var _a;
3184
3208
  const accountId = state.getAccount();
3185
3209
  const nearAccount = yield provider.query({
3186
3210
  request_type: "view_account",
@@ -3188,39 +3212,107 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3188
3212
  finality: "final"
3189
3213
  });
3190
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
+ );
3191
3222
  if (availableBalance > 0.2) {
3192
- 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
+ }
3193
3244
  } else {
3194
- const gasTokenBalance = yield nearCall2(currentConfig.token, "ft_balance_of", {
3195
- account_id: accountId
3196
- });
3197
- if (new import_big.default(gasTokenBalance).gt(currentConfig.gasTokenLimit)) {
3198
- const transferGasTransaction = {
3199
- signerId: accountId,
3200
- receiverId: currentConfig.token,
3201
- actions: [
3202
- {
3203
- type: "FunctionCall",
3204
- params: {
3205
- methodName: "ft_transfer_call",
3206
- args: {
3207
- receiver_id: currentConfig.accountContractId,
3208
- amount: currentConfig.gasTokenLimit,
3209
- msg: "Deposit"
3210
- },
3211
- gas: new import_big.default(50).mul(__pow(10, 12)).toFixed(0),
3212
- deposit: "1"
3213
- }
3214
- }
3215
- ]
3216
- };
3217
- 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 };
3218
3254
  } else {
3219
- 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);
3220
3258
  }
3221
3259
  }
3222
3260
  });
3223
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
+ }
3224
3316
  function initWalletButton(network, wallet2) {
3225
3317
  return __async(this, null, function* () {
3226
3318
  const checkAndSetupWalletButton = () => {
@@ -3253,6 +3345,14 @@ function uploadBTCTx(url, data) {
3253
3345
  body: data
3254
3346
  });
3255
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
+ }
3256
3356
  function setupBTCWallet({
3257
3357
  iconUrl = "https://assets.deltatrade.ai/assets/chain/btc.svg",
3258
3358
  deprecated = false,
@@ -3280,14 +3380,6 @@ function setupBTCWallet({
3280
3380
  });
3281
3381
  return btcWallet;
3282
3382
  }
3283
- function toHex(originalString) {
3284
- const charArray = originalString.split("");
3285
- const asciiArray = charArray.map((char) => char.charCodeAt(0));
3286
- const hexArray = asciiArray.map((code) => code.toString(16));
3287
- let hexString = hexArray.join("");
3288
- hexString = hexString.replace(/(^0+)/g, "");
3289
- return hexString;
3290
- }
3291
3383
 
3292
3384
  // src/core/btcUtils.ts
3293
3385
  var import_big2 = __toESM(require("big.js"), 1);
@@ -3367,18 +3459,23 @@ function getBtcGasPrice() {
3367
3459
  }
3368
3460
  function getBtcBalance() {
3369
3461
  return __async(this, null, function* () {
3370
- const { account } = yield retryOperation(getBtcProvider, (res2) => !!res2.account);
3462
+ const { account } = yield retryOperation(getBtcProvider, (res) => !!res.account);
3371
3463
  if (!account) {
3372
3464
  console.error("BTC Account is not available.");
3373
3465
  return { rawBalance: 0, balance: 0, maxSpendableBalance: 0 };
3374
3466
  }
3375
3467
  const btcRpcUrl = yield getBtcRpcUrl();
3376
- const res = yield fetch(`${btcRpcUrl}/address/${account}/utxo`).then((res2) => res2.json());
3377
- 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;
3378
3470
  const balance = rawBalance / __pow(10, 8);
3379
3471
  const feeRate = yield getBtcGasPrice();
3380
- const maxGasFee = feeRate * 350 / __pow(10, 8);
3381
- 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);
3382
3479
  return {
3383
3480
  rawBalance,
3384
3481
  balance,
@@ -3491,7 +3588,7 @@ function executeBTCDepositAndAction(_0) {
3491
3588
  btcPublicKey,
3492
3589
  txHash,
3493
3590
  postActions: JSON.stringify(depositMsg.post_actions),
3494
- extraMsg: depositMsg.extra_msg || ""
3591
+ extraMsg: depositMsg.extra_msg
3495
3592
  });
3496
3593
  const checkTransactionStatusRes = yield checkTransactionStatus(config.base_url, txHash);
3497
3594
  console.log("checkTransactionStatus resp:", checkTransactionStatusRes);
@@ -3505,7 +3602,7 @@ function executeBTCDepositAndAction(_0) {
3505
3602
 
3506
3603
  // src/index.ts
3507
3604
  var getVersion = () => {
3508
- return "0.3.9";
3605
+ return "0.3.11";
3509
3606
  };
3510
3607
  if (typeof window !== "undefined") {
3511
3608
  window.__PARTICLE_BTC_CONNECT_VERSION = getVersion();