btc-wallet 0.3.10 → 0.3.11

Sign up to get free protection for your applications and to get access to all the features.
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();