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.
@@ -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();