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.
@@ -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,77 +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();
3068
- if (!useNearPayGas && transferGasTransaction) {
3069
- params.transactions.unshift(transferGasTransaction);
3070
- }
3071
- const newTransactions = params.transactions.map((transaction, index) => {
3072
- let nearNonceNumber = accessKey.nonce + BigInt(1);
3073
- if (nearNonceFromApi) {
3074
- nearNonceNumber = BigInt(nearNonceFromApi) > nearNonceNumber ? BigInt(nearNonceFromApi) : nearNonceNumber;
3075
- }
3076
- const newActions = transaction.actions.map((action) => {
3077
- switch (action.type) {
3078
- case "FunctionCall":
3079
- return functionCall(
3080
- action.params.methodName,
3081
- action.params.args,
3082
- BigInt(action.params.gas),
3083
- BigInt(action.params.deposit)
3084
- );
3085
- case "Transfer":
3086
- return transfer(BigInt(action.params.deposit));
3087
- }
3088
- }).filter(Boolean);
3089
- const _transaction = transactions.createTransaction(
3090
- accountId,
3091
- publicKeyFormat,
3092
- transaction.receiverId,
3093
- BigInt(nearNonceNumber) + BigInt(index),
3094
- newActions,
3095
- baseDecode(header.hash)
3096
- );
3097
- const txBytes = encodeTransaction(_transaction);
3098
- const txHex = Array.from(
3099
- txBytes,
3100
- (byte) => ("0" + (byte & 255).toString(16)).slice(-2)
3101
- ).join("");
3102
- console.log("txHex:", txHex);
3103
- const hash = bs58.encode(new Uint8Array(sha256.array(txBytes)));
3104
- return { txBytes, txHex, hash };
3105
- });
3106
- const accountInfo = yield nearCall2(
3107
- currentConfig.accountContractId,
3108
- "get_account",
3109
- { account_id: accountId }
3058
+ const trans = [...params.transactions];
3059
+ console.log("raw trans:", trans);
3060
+ const { transferGasTransaction, useNearPayGas, gasLimit } = yield calculateGasStrategy(trans);
3061
+ console.log("transferGasTransaction:", transferGasTransaction);
3062
+ console.log("useNearPayGas:", useNearPayGas);
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))
3110
3070
  );
3111
3071
  const { result_data: nonceFromApi } = yield getNonceFromApi(
3112
3072
  currentConfig.base_url,
3113
3073
  accountId
3114
3074
  );
3075
+ const accountInfo = yield getAccountInfo();
3115
3076
  const nonce = Number(nonceFromApi) > Number(accountInfo.nonce) ? String(nonceFromApi) : String(accountInfo.nonce);
3116
3077
  const intention = {
3117
3078
  chain_id: "397",
3118
3079
  csna: accountId,
3119
- near_transactions: newTransactions.map((t) => t.txHex),
3080
+ near_transactions: newTrans.map((t) => t.txHex),
3120
3081
  gas_token: currentConfig.token,
3121
- gas_limit: currentConfig.gasTokenLimit,
3082
+ gas_limit: gasLimit,
3122
3083
  use_near_pay_gas: useNearPayGas,
3123
3084
  nonce
3124
3085
  };
@@ -3130,7 +3091,7 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3130
3091
  data: toHex(strIntention)
3131
3092
  });
3132
3093
  if (result.result_code === 0) {
3133
- const hash = newTransactions.map((t) => t.hash);
3094
+ const hash = newTrans.map((t) => t.hash);
3134
3095
  console.log("txHash:", hash);
3135
3096
  const result2 = yield pollTransactionStatuses(options.network.networkId, hash);
3136
3097
  return result2;
@@ -3139,8 +3100,71 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3139
3100
  }
3140
3101
  });
3141
3102
  }
3142
- function getGasConfig() {
3103
+ function getAccountInfo() {
3143
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) {
3166
+ return __async(this, null, function* () {
3167
+ var _a;
3144
3168
  const accountId = state.getAccount();
3145
3169
  const nearAccount = yield provider.query({
3146
3170
  request_type: "view_account",
@@ -3148,39 +3172,107 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3148
3172
  finality: "final"
3149
3173
  });
3150
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
+ );
3151
3182
  if (availableBalance > 0.2) {
3152
- 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
+ }
3153
3204
  } else {
3154
- const gasTokenBalance = yield nearCall2(currentConfig.token, "ft_balance_of", {
3155
- account_id: accountId
3156
- });
3157
- if (new Big(gasTokenBalance).gt(currentConfig.gasTokenLimit)) {
3158
- const transferGasTransaction = {
3159
- signerId: accountId,
3160
- receiverId: currentConfig.token,
3161
- actions: [
3162
- {
3163
- type: "FunctionCall",
3164
- params: {
3165
- methodName: "ft_transfer_call",
3166
- args: {
3167
- receiver_id: currentConfig.accountContractId,
3168
- amount: currentConfig.gasTokenLimit,
3169
- msg: "Deposit"
3170
- },
3171
- gas: new Big(50).mul(__pow(10, 12)).toFixed(0),
3172
- deposit: "1"
3173
- }
3174
- }
3175
- ]
3176
- };
3177
- 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 };
3178
3214
  } else {
3179
- 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);
3180
3218
  }
3181
3219
  }
3182
3220
  });
3183
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
+ }
3184
3276
  function initWalletButton(network, wallet2) {
3185
3277
  return __async(this, null, function* () {
3186
3278
  const checkAndSetupWalletButton = () => {
@@ -3213,6 +3305,14 @@ function uploadBTCTx(url, data) {
3213
3305
  body: data
3214
3306
  });
3215
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
+ }
3216
3316
  function setupBTCWallet({
3217
3317
  iconUrl = "https://assets.deltatrade.ai/assets/chain/btc.svg",
3218
3318
  deprecated = false,
@@ -3240,14 +3340,6 @@ function setupBTCWallet({
3240
3340
  });
3241
3341
  return btcWallet;
3242
3342
  }
3243
- function toHex(originalString) {
3244
- const charArray = originalString.split("");
3245
- const asciiArray = charArray.map((char) => char.charCodeAt(0));
3246
- const hexArray = asciiArray.map((code) => code.toString(16));
3247
- let hexString = hexArray.join("");
3248
- hexString = hexString.replace(/(^0+)/g, "");
3249
- return hexString;
3250
- }
3251
3343
 
3252
3344
  // src/core/btcUtils.ts
3253
3345
  import Big2 from "big.js";
@@ -3327,18 +3419,23 @@ function getBtcGasPrice() {
3327
3419
  }
3328
3420
  function getBtcBalance() {
3329
3421
  return __async(this, null, function* () {
3330
- const { account } = yield retryOperation(getBtcProvider, (res2) => !!res2.account);
3422
+ const { account } = yield retryOperation(getBtcProvider, (res) => !!res.account);
3331
3423
  if (!account) {
3332
3424
  console.error("BTC Account is not available.");
3333
3425
  return { rawBalance: 0, balance: 0, maxSpendableBalance: 0 };
3334
3426
  }
3335
3427
  const btcRpcUrl = yield getBtcRpcUrl();
3336
- const res = yield fetch(`${btcRpcUrl}/address/${account}/utxo`).then((res2) => res2.json());
3337
- 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;
3338
3430
  const balance = rawBalance / __pow(10, 8);
3339
3431
  const feeRate = yield getBtcGasPrice();
3340
- const maxGasFee = feeRate * 350 / __pow(10, 8);
3341
- 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);
3342
3439
  return {
3343
3440
  rawBalance,
3344
3441
  balance,
@@ -3451,7 +3548,7 @@ function executeBTCDepositAndAction(_0) {
3451
3548
  btcPublicKey,
3452
3549
  txHash,
3453
3550
  postActions: JSON.stringify(depositMsg.post_actions),
3454
- extraMsg: depositMsg.extra_msg || ""
3551
+ extraMsg: depositMsg.extra_msg
3455
3552
  });
3456
3553
  const checkTransactionStatusRes = yield checkTransactionStatus(config.base_url, txHash);
3457
3554
  console.log("checkTransactionStatus resp:", checkTransactionStatusRes);
@@ -3465,7 +3562,7 @@ function executeBTCDepositAndAction(_0) {
3465
3562
 
3466
3563
  // src/index.ts
3467
3564
  var getVersion = () => {
3468
- return "0.3.9";
3565
+ return "0.3.11";
3469
3566
  };
3470
3567
  if (typeof window !== "undefined") {
3471
3568
  window.__PARTICLE_BTC_CONNECT_VERSION = getVersion();