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.
@@ -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<(providers.FinalExecutionOutcome | undefined)[]>;
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 = 3;
2824
- const pollStatus = (hash) => __async(this, null, function* () {
2825
- let attempt = 0;
2826
- while (attempt < maxAttempts) {
2827
- attempt++;
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
- return result;
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
- if (attempt === maxAttempts) {
2838
- throw new Error(`Transaction not found after max attempts: ${hash}`);
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
- const results = yield Promise.all(hashes.map((hash) => pollStatus(hash)));
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 publicKey = state.getPublicKey();
3052
- const { header } = yield provider.block({ finality: "final" });
3053
- const rawAccessKey = yield provider.query({
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
- if (!useNearPayGas && transferGasTransaction) {
3071
- params.transactions.unshift(transferGasTransaction);
3072
- }
3073
- console.log("raw transactions:", params.transactions);
3074
- const newTransactions = params.transactions.map((transaction, index) => {
3075
- let nearNonceNumber = accessKey.nonce + BigInt(1);
3076
- if (nearNonceFromApi) {
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: newTransactions.map((t) => t.txHex),
3080
+ near_transactions: newTrans.map((t) => t.txHex),
3123
3081
  gas_token: currentConfig.token,
3124
- gas_limit: currentConfig.gasTokenLimit,
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 = newTransactions.map((t) => t.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 getGasConfig() {
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
- return { useNearPayGas: true };
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
- const gasTokenBalance = yield nearCall2(currentConfig.token, "ft_balance_of", {
3158
- account_id: accountId
3159
- });
3160
- if (new Big(gasTokenBalance).gt(currentConfig.gasTokenLimit)) {
3161
- const transferGasTransaction = {
3162
- signerId: accountId,
3163
- receiverId: currentConfig.token,
3164
- actions: [
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
- throw new Error("No enough gas token balance");
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, (res2) => !!res2.account);
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 res = yield fetch(`${btcRpcUrl}/address/${account}/utxo`).then((res2) => res2.json());
3340
- const rawBalance = res == null ? void 0 : res.reduce((acc, cur) => acc + cur.value, 0);
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 maxGasFee = feeRate * 350 / __pow(10, 8);
3344
- const availableBalance = Math.max(0, balance - maxGasFee);
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.10";
3565
+ return "0.3.11";
3472
3566
  };
3473
3567
  if (typeof window !== "undefined") {
3474
3568
  window.__PARTICLE_BTC_CONNECT_VERSION = getVersion();