btc-wallet 0.3.9 → 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,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();