btc-wallet 0.3.10 → 0.3.12

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.
package/dist/index.js CHANGED
@@ -2572,7 +2572,7 @@ var import_near_api_js2 = require("near-api-js");
2572
2572
  var import_transactions = require("@near-js/transactions");
2573
2573
  var import_key_pair = require("near-api-js/lib/utils/key_pair");
2574
2574
  var import_transaction = require("near-api-js/lib/transaction");
2575
- var import_utils5 = require("@near-js/utils");
2575
+ var import_utils6 = require("@near-js/utils");
2576
2576
  var import_bs58 = __toESM(require("bs58"), 1);
2577
2577
  var import_js_sha256 = require("js-sha256");
2578
2578
 
@@ -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 = {
@@ -2764,6 +2762,73 @@ var btcRpcUrls = {
2764
2762
  testnet: "https://mempool.space/testnet/api"
2765
2763
  };
2766
2764
 
2765
+ // src/utils/nearUtils.ts
2766
+ var import_near_api_js = require("near-api-js");
2767
+ function nearCallFunction(contractId, methodName, args, options) {
2768
+ return __async(this, null, function* () {
2769
+ const nearProvider = (options == null ? void 0 : options.provider) || new import_near_api_js.providers.FailoverRpcProvider(
2770
+ nearRpcUrls[options == null ? void 0 : options.network].map(
2771
+ (url) => new import_near_api_js.providers.JsonRpcProvider({ url })
2772
+ )
2773
+ );
2774
+ const res = yield nearProvider.query({
2775
+ request_type: "call_function",
2776
+ account_id: contractId,
2777
+ method_name: methodName,
2778
+ args_base64: Buffer.from(JSON.stringify(args)).toString("base64"),
2779
+ finality: "final"
2780
+ });
2781
+ return JSON.parse(Buffer.from(res.result).toString());
2782
+ });
2783
+ }
2784
+ function pollTransactionStatuses(network, hashes) {
2785
+ return __async(this, null, function* () {
2786
+ const provider = new import_near_api_js.providers.FailoverRpcProvider(
2787
+ Object.values(nearRpcUrls[network]).map(
2788
+ (url) => new import_near_api_js.providers.JsonRpcProvider({ url })
2789
+ )
2790
+ );
2791
+ const maxAttempts = 30;
2792
+ let currentAttempt = 0;
2793
+ const pendingHashes = new Set(hashes);
2794
+ const results = /* @__PURE__ */ new Map();
2795
+ while (pendingHashes.size > 0 && currentAttempt < maxAttempts) {
2796
+ currentAttempt++;
2797
+ const promises = Array.from(pendingHashes).map((hash) => __async(this, null, function* () {
2798
+ try {
2799
+ const result = yield provider.txStatus(hash, "unused", "FINAL");
2800
+ if (result && result.status) {
2801
+ console.log(`Transaction ${hash} result:`, result);
2802
+ results.set(hash, result);
2803
+ pendingHashes.delete(hash);
2804
+ }
2805
+ } catch (error) {
2806
+ console.error(`Failed to fetch transaction status for ${hash}: ${error.message}`);
2807
+ }
2808
+ }));
2809
+ yield Promise.all(promises);
2810
+ if (pendingHashes.size > 0) {
2811
+ if (currentAttempt === maxAttempts) {
2812
+ throw new Error(
2813
+ `Transactions not found after max attempts: ${Array.from(pendingHashes).join(", ")}`
2814
+ );
2815
+ }
2816
+ console.log(
2817
+ `Waiting for ${pendingHashes.size} transactions, retrying ${maxAttempts - currentAttempt} more times`
2818
+ );
2819
+ yield delay(1e4);
2820
+ }
2821
+ }
2822
+ return hashes.map((hash) => results.get(hash));
2823
+ });
2824
+ }
2825
+
2826
+ // src/core/setupBTCWallet.ts
2827
+ var import_big2 = __toESM(require("big.js"), 1);
2828
+
2829
+ // src/core/btcUtils.ts
2830
+ var import_big = __toESM(require("big.js"), 1);
2831
+
2767
2832
  // src/utils/request.ts
2768
2833
  var cache = /* @__PURE__ */ new Map();
2769
2834
  var defaultCacheTimeout = 3e3;
@@ -2804,18 +2869,20 @@ function request(url, options) {
2804
2869
  if (!res.ok)
2805
2870
  throw new Error(res.statusText);
2806
2871
  const data = yield res.json();
2872
+ if (options == null ? void 0 : options.shouldStopPolling) {
2873
+ if (options.shouldStopPolling(data)) {
2874
+ return data;
2875
+ }
2876
+ throw new Error("Polling should continue");
2877
+ }
2807
2878
  if (cacheKey) {
2808
2879
  cache.set(cacheKey, { timestamp: Date.now(), data });
2809
2880
  setTimeout(() => {
2810
2881
  cache.delete(cacheKey);
2811
2882
  }, cacheTimeout);
2812
2883
  }
2813
- if ((options == null ? void 0 : options.shouldStopPolling) && options.shouldStopPolling(data)) {
2814
- return data;
2815
- }
2816
2884
  return data;
2817
2885
  } catch (err) {
2818
- console.error(err);
2819
2886
  if (retryCount > 0) {
2820
2887
  console.log(`Retrying... attempts left: ${retryCount}`);
2821
2888
  return request(url, __spreadProps(__spreadValues({}, options), { retryCount: retryCount - 1 }));
@@ -2829,65 +2896,471 @@ function request(url, options) {
2829
2896
  }));
2830
2897
  }
2831
2898
  }
2832
- return Promise.reject(err);
2899
+ throw err;
2833
2900
  }
2834
2901
  });
2835
2902
  }
2836
2903
 
2837
- // src/utils/nearUtils.ts
2838
- var import_near_api_js = require("near-api-js");
2839
- function nearCallFunction(contractId, methodName, args, options) {
2904
+ // src/utils/satoshi.ts
2905
+ function getNonce(url, accountId) {
2840
2906
  return __async(this, null, function* () {
2841
- const nearProvider = (options == null ? void 0 : options.provider) || new import_near_api_js.providers.FailoverRpcProvider(
2842
- nearRpcUrls[options == null ? void 0 : options.network].map(
2843
- (url) => new import_near_api_js.providers.JsonRpcProvider({ url })
2844
- )
2907
+ const { result_code, result_message, result_data } = yield request(
2908
+ `${url}/v1/nonce?csna=${accountId}`
2845
2909
  );
2846
- const res = yield nearProvider.query({
2847
- request_type: "call_function",
2848
- account_id: contractId,
2849
- method_name: methodName,
2850
- args_base64: Buffer.from(JSON.stringify(args)).toString("base64"),
2851
- finality: "final"
2910
+ if (result_code !== 0) {
2911
+ throw new Error(result_message);
2912
+ }
2913
+ return result_data;
2914
+ });
2915
+ }
2916
+ function getNearNonce(url, accountId) {
2917
+ return __async(this, null, function* () {
2918
+ const { result_code, result_message, result_data } = yield request(
2919
+ `${url}/v1/nonceNear?csna=${accountId}`
2920
+ );
2921
+ if (result_code !== 0) {
2922
+ throw new Error(result_message);
2923
+ }
2924
+ return result_data;
2925
+ });
2926
+ }
2927
+ function receiveTransaction(url, data) {
2928
+ return __async(this, null, function* () {
2929
+ const { result_code, result_message, result_data } = yield request(
2930
+ `${url}/v1/receiveTransaction`,
2931
+ {
2932
+ method: "POST",
2933
+ body: data
2934
+ }
2935
+ );
2936
+ if (result_code !== 0) {
2937
+ throw new Error(result_message);
2938
+ }
2939
+ return result_data;
2940
+ });
2941
+ }
2942
+ function receiveDepositMsg(_0, _1) {
2943
+ return __async(this, arguments, function* (url, {
2944
+ btcPublicKey,
2945
+ txHash,
2946
+ depositType = 1,
2947
+ postActions,
2948
+ extraMsg
2949
+ }) {
2950
+ const { result_code, result_message, result_data } = yield request(
2951
+ `${url}/v1/receiveDepositMsg`,
2952
+ {
2953
+ method: "POST",
2954
+ body: { btcPublicKey, txHash, depositType, postActions, extraMsg }
2955
+ }
2956
+ );
2957
+ console.log("receiveDepositMsg resp:", { result_code, result_message, result_data });
2958
+ if (result_code !== 0) {
2959
+ throw new Error(result_message);
2960
+ }
2961
+ return result_data;
2962
+ });
2963
+ }
2964
+ function checkBridgeTransactionStatus(url, txHash) {
2965
+ return __async(this, null, function* () {
2966
+ const { result_code, result_message, result_data } = yield request(`${url}/v1/bridgeFromTx?fromTxHash=${txHash}&fromChainId=1`, {
2967
+ timeout: 3e5,
2968
+ pollingInterval: 5e3,
2969
+ maxPollingAttempts: 30,
2970
+ shouldStopPolling: (res) => {
2971
+ var _a;
2972
+ return res.result_code === 0 && [4, 102].includes(((_a = res.result_data) == null ? void 0 : _a.status) || 0);
2973
+ }
2852
2974
  });
2853
- return JSON.parse(Buffer.from(res.result).toString());
2975
+ console.log("checkTransactionStatus resp:", { result_code, result_message, result_data });
2976
+ if ((result_data == null ? void 0 : result_data.status) !== 4) {
2977
+ throw new Error(result_message);
2978
+ }
2979
+ return result_data;
2854
2980
  });
2855
2981
  }
2856
- function pollTransactionStatuses(network, hashes) {
2982
+ function checkBtcTransactionStatus(url, sig) {
2857
2983
  return __async(this, null, function* () {
2858
- const provider = new import_near_api_js.providers.FailoverRpcProvider(
2859
- Object.values(nearRpcUrls[network]).map(
2860
- (url) => new import_near_api_js.providers.JsonRpcProvider({ url })
2861
- )
2984
+ const { result_code, result_message, result_data } = yield request(`${url}/v1/btcTx?sig=${sig}`, {
2985
+ timeout: 3e5,
2986
+ pollingInterval: 5e3,
2987
+ maxPollingAttempts: 30,
2988
+ shouldStopPolling: (res) => {
2989
+ var _a;
2990
+ return res.result_code === 0 && [3, 101, 102].includes(((_a = res.result_data) == null ? void 0 : _a.status) || 0);
2991
+ }
2992
+ });
2993
+ console.log("checkBtcTransactionStatus resp:", { result_code, result_message, result_data });
2994
+ if ((result_data == null ? void 0 : result_data.status) !== 3) {
2995
+ throw new Error(result_message);
2996
+ }
2997
+ return result_data;
2998
+ });
2999
+ }
3000
+
3001
+ // src/core/btcUtils.ts
3002
+ function getBtcProvider() {
3003
+ if (typeof window === "undefined" || !window.btcContext) {
3004
+ throw new Error("BTC Provider is not initialized.");
3005
+ }
3006
+ return window.btcContext;
3007
+ }
3008
+ function getNetwork() {
3009
+ return __async(this, null, function* () {
3010
+ const network = yield getBtcProvider().getNetwork();
3011
+ console.log("btc network:", network);
3012
+ return network === "livenet" ? "mainnet" : "testnet";
3013
+ });
3014
+ }
3015
+ function getBtcRpcUrl() {
3016
+ return __async(this, null, function* () {
3017
+ const network = yield getNetwork();
3018
+ return btcRpcUrls[network];
3019
+ });
3020
+ }
3021
+ function getConfig(isDev) {
3022
+ return __async(this, null, function* () {
3023
+ const network = yield getNetwork();
3024
+ return walletConfig[isDev ? "dev" : network];
3025
+ });
3026
+ }
3027
+ function nearCall(contractId, methodName, args) {
3028
+ return __async(this, null, function* () {
3029
+ const network = yield getNetwork();
3030
+ return nearCallFunction(contractId, methodName, args, { network });
3031
+ });
3032
+ }
3033
+ function getBtcGasPrice() {
3034
+ return __async(this, null, function* () {
3035
+ const defaultFeeRate = 100;
3036
+ try {
3037
+ const btcRpcUrl = yield getBtcRpcUrl();
3038
+ const res = yield fetch(`${btcRpcUrl}/v1/fees/recommended`).then((res2) => res2.json());
3039
+ const feeRate = res.fastestFee;
3040
+ return feeRate || defaultFeeRate;
3041
+ } catch (error) {
3042
+ return defaultFeeRate;
3043
+ }
3044
+ });
3045
+ }
3046
+ function getBtcBalance() {
3047
+ return __async(this, null, function* () {
3048
+ const { account } = yield retryOperation(getBtcProvider, (res) => !!res.account);
3049
+ if (!account) {
3050
+ console.error("BTC Account is not available.");
3051
+ return { rawBalance: 0, balance: 0, maxSpendableBalance: 0 };
3052
+ }
3053
+ const btcRpcUrl = yield getBtcRpcUrl();
3054
+ const utxos = yield fetch(`${btcRpcUrl}/address/${account}/utxo`).then((res) => res.json());
3055
+ const rawBalance = (utxos == null ? void 0 : utxos.reduce((acc, cur) => acc + cur.value, 0)) || 0;
3056
+ const balance = rawBalance / __pow(10, 8);
3057
+ const feeRate = yield getBtcGasPrice();
3058
+ const inputSize = ((utxos == null ? void 0 : utxos.length) || 0) * 66;
3059
+ const outputSize = 34;
3060
+ const overheadSize = 10;
3061
+ const estimatedTxSize = inputSize + outputSize + overheadSize;
3062
+ const estimatedFee = estimatedTxSize * feeRate / __pow(10, 8);
3063
+ console.log("estimated fee:", estimatedFee);
3064
+ const availableBalance = Math.max(0, balance - estimatedFee);
3065
+ return {
3066
+ rawBalance,
3067
+ balance,
3068
+ availableBalance
3069
+ };
3070
+ });
3071
+ }
3072
+ function sendBitcoin(address, amount, feeRate) {
3073
+ return __async(this, null, function* () {
3074
+ const { sendBitcoin: sendBitcoin2 } = getBtcProvider();
3075
+ const txHash = yield sendBitcoin2(address, amount, { feeRate });
3076
+ return txHash;
3077
+ });
3078
+ }
3079
+ function estimateDepositAmount(amount, option) {
3080
+ return __async(this, null, function* () {
3081
+ const config = yield getConfig((option == null ? void 0 : option.isDev) || false);
3082
+ const {
3083
+ deposit_bridge_fee: { fee_min, fee_rate }
3084
+ } = yield nearCall(
3085
+ config.bridgeContractId,
3086
+ "get_config",
3087
+ {}
2862
3088
  );
2863
- const maxAttempts = 3;
2864
- const pollStatus = (hash) => __async(this, null, function* () {
2865
- let attempt = 0;
2866
- while (attempt < maxAttempts) {
2867
- attempt++;
2868
- try {
2869
- const result = yield provider.txStatus(hash, "unused", "FINAL");
2870
- if (result && result.status) {
2871
- console.log(`Transaction ${hash} result:`, result);
2872
- return result;
2873
- }
2874
- } catch (error) {
2875
- console.error(`Failed to fetch transaction status for ${hash}: ${error.message}`);
3089
+ const fee = Math.max(Number(fee_min), Number(amount) * fee_rate);
3090
+ return new import_big.default(amount).minus(fee).toFixed(0);
3091
+ });
3092
+ }
3093
+ function executeBTCDepositAndAction(_0) {
3094
+ return __async(this, arguments, function* ({
3095
+ action,
3096
+ feeRate,
3097
+ isDev = false
3098
+ }) {
3099
+ try {
3100
+ const { getPublicKey } = getBtcProvider();
3101
+ const config = yield getConfig(isDev);
3102
+ const btcPublicKey = yield getPublicKey();
3103
+ if (!btcPublicKey) {
3104
+ throw new Error("BTC Public Key is not available.");
3105
+ }
3106
+ if (!action.receiver_id) {
3107
+ throw new Error("receiver_id is required");
3108
+ }
3109
+ if (!action.amount) {
3110
+ throw new Error("amount is required");
3111
+ }
3112
+ const csna = yield nearCall(
3113
+ config.accountContractId,
3114
+ "get_chain_signature_near_account_id",
3115
+ {
3116
+ btc_public_key: btcPublicKey
2876
3117
  }
2877
- if (attempt === maxAttempts) {
2878
- throw new Error(`Transaction not found after max attempts: ${hash}`);
3118
+ );
3119
+ const depositMsg = {
3120
+ recipient_id: csna,
3121
+ post_actions: [
3122
+ __spreadProps(__spreadValues({}, action), {
3123
+ gas: new import_big.default(100).mul(__pow(10, 12)).toFixed(0)
3124
+ })
3125
+ ]
3126
+ };
3127
+ const storageDepositMsg = {};
3128
+ const accountInfo = yield nearCall(
3129
+ config.accountContractId,
3130
+ "get_account",
3131
+ {
3132
+ account_id: csna
2879
3133
  }
2880
- yield delay(1e4);
2881
- console.log(`RPC request failed for ${hash}, retrying ${maxAttempts - attempt} more times`);
3134
+ );
3135
+ if (!(accountInfo == null ? void 0 : accountInfo.nonce)) {
3136
+ storageDepositMsg.btc_public_key = btcPublicKey;
2882
3137
  }
2883
- });
2884
- const results = yield Promise.all(hashes.map((hash) => pollStatus(hash)));
2885
- return results;
3138
+ const registerRes = yield nearCall(action.receiver_id, "storage_balance_of", {
3139
+ account_id: csna
3140
+ });
3141
+ if (!(registerRes == null ? void 0 : registerRes.available)) {
3142
+ storageDepositMsg.storage_deposit_msg = {
3143
+ contract_id: action.receiver_id,
3144
+ deposit: new import_big.default(0.25).mul(__pow(10, 24)).toFixed(0),
3145
+ registration_only: true
3146
+ };
3147
+ }
3148
+ if (Object.keys(storageDepositMsg).length > 0) {
3149
+ depositMsg.extra_msg = JSON.stringify(storageDepositMsg);
3150
+ }
3151
+ console.log("get_user_deposit_address params:", { deposit_msg: depositMsg });
3152
+ const userDepositAddress = yield nearCall(
3153
+ config.bridgeContractId,
3154
+ "get_user_deposit_address",
3155
+ { deposit_msg: depositMsg }
3156
+ );
3157
+ const _feeRate = feeRate || (yield getBtcGasPrice());
3158
+ const minDepositAmount = 5e3;
3159
+ const sendAmount = Math.max(minDepositAmount, new import_big.default(action.amount).toNumber());
3160
+ console.log("user deposit address:", userDepositAddress);
3161
+ console.log("send amount:", sendAmount);
3162
+ console.log("fee rate:", _feeRate);
3163
+ const txHash = yield sendBitcoin(userDepositAddress, sendAmount, _feeRate);
3164
+ yield receiveDepositMsg(config.base_url, {
3165
+ btcPublicKey,
3166
+ txHash,
3167
+ postActions: JSON.stringify(depositMsg.post_actions),
3168
+ extraMsg: depositMsg.extra_msg
3169
+ });
3170
+ const checkTransactionStatusRes = yield checkBridgeTransactionStatus(config.base_url, txHash);
3171
+ console.log("checkBridgeTransactionStatus resp:", checkTransactionStatusRes);
3172
+ const network = yield getNetwork();
3173
+ const result = yield pollTransactionStatuses(network, [checkTransactionStatusRes.ToTxHash]);
3174
+ return result;
3175
+ } catch (error) {
3176
+ console.error("executeBTCDepositAndAction error:", error);
3177
+ throw error;
3178
+ }
2886
3179
  });
2887
3180
  }
2888
3181
 
3182
+ // src/utils/Dialog.ts
3183
+ var Dialog = class {
3184
+ static injectStyles() {
3185
+ if (!document.querySelector("#dialog-styles")) {
3186
+ const styleSheet = document.createElement("style");
3187
+ styleSheet.id = "dialog-styles";
3188
+ styleSheet.textContent = this.style;
3189
+ document.head.appendChild(styleSheet);
3190
+ }
3191
+ }
3192
+ static confirm(options) {
3193
+ return new Promise((resolve) => {
3194
+ this.injectStyles();
3195
+ const container = document.createElement("div");
3196
+ container.innerHTML = this.template;
3197
+ document.body.appendChild(container);
3198
+ const titleEl = container.querySelector(".dialog-title");
3199
+ const messageEl = container.querySelector(".dialog-message");
3200
+ const confirmBtn = container.querySelector(".dialog-confirm-btn");
3201
+ const cancelBtn = container.querySelector(".dialog-cancel-btn");
3202
+ if (options.title) {
3203
+ titleEl.textContent = options.title;
3204
+ } else {
3205
+ titleEl.style.display = "none";
3206
+ }
3207
+ messageEl.textContent = options.message;
3208
+ const cleanup = () => {
3209
+ document.body.removeChild(container);
3210
+ };
3211
+ confirmBtn.addEventListener("click", () => {
3212
+ cleanup();
3213
+ resolve(true);
3214
+ });
3215
+ cancelBtn.addEventListener("click", () => {
3216
+ cleanup();
3217
+ resolve(false);
3218
+ });
3219
+ });
3220
+ }
3221
+ static alert(options) {
3222
+ return new Promise((resolve) => {
3223
+ this.injectStyles();
3224
+ const container = document.createElement("div");
3225
+ container.innerHTML = this.template;
3226
+ document.body.appendChild(container);
3227
+ const titleEl = container.querySelector(".dialog-title");
3228
+ const messageEl = container.querySelector(".dialog-message");
3229
+ const confirmBtn = container.querySelector(".dialog-confirm-btn");
3230
+ const cancelBtn = container.querySelector(".dialog-cancel-btn");
3231
+ if (options.title) {
3232
+ titleEl.textContent = options.title;
3233
+ } else {
3234
+ titleEl.style.display = "none";
3235
+ }
3236
+ messageEl.textContent = options.message;
3237
+ cancelBtn.style.display = "none";
3238
+ const cleanup = () => {
3239
+ document.body.removeChild(container);
3240
+ };
3241
+ confirmBtn.addEventListener("click", () => {
3242
+ cleanup();
3243
+ resolve();
3244
+ });
3245
+ });
3246
+ }
3247
+ };
3248
+ Dialog.template = `
3249
+ <div class="dialog-overlay">
3250
+ <div class="dialog-container">
3251
+ <div class="dialog-content">
3252
+ <div class="dialog-title"></div>
3253
+ <div class="dialog-message"></div>
3254
+ <div class="dialog-buttons">
3255
+ <button class="dialog-cancel-btn">Cancel</button>
3256
+ <button class="dialog-confirm-btn">Confirm</button>
3257
+ </div>
3258
+ </div>
3259
+ </div>
3260
+ </div>
3261
+ `;
3262
+ Dialog.style = `
3263
+ .dialog-overlay {
3264
+ position: fixed;
3265
+ top: 0;
3266
+ left: 0;
3267
+ right: 0;
3268
+ bottom: 0;
3269
+ background-color: rgba(0, 0, 0, 0.75);
3270
+ display: flex;
3271
+ align-items: center;
3272
+ justify-content: center;
3273
+ z-index: 999999;
3274
+ backdrop-filter: blur(4px);
3275
+ }
3276
+ .dialog-container {
3277
+ background: #21232f;
3278
+ border-radius: 12px;
3279
+ padding: 24px;
3280
+ width: 350px;
3281
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
3282
+ }
3283
+ .dialog-title {
3284
+ font-size: 18px;
3285
+ font-weight: 600;
3286
+ margin-bottom: 16px;
3287
+ color: #ffffff;
3288
+ }
3289
+ .dialog-message {
3290
+ margin-bottom: 24px;
3291
+ line-height: 1.6;
3292
+ color: rgba(255, 255, 255, 0.8);
3293
+ font-size: 14px;
3294
+ }
3295
+ .dialog-buttons {
3296
+ display: flex;
3297
+ justify-content: flex-end;
3298
+ gap: 12px;
3299
+ }
3300
+ .dialog-confirm-btn {
3301
+ padding: 8px 24px;
3302
+ background-color: #ff7a00;
3303
+ color: white;
3304
+ border: none;
3305
+ border-radius: 6px;
3306
+ cursor: pointer;
3307
+ font-size: 14px;
3308
+ font-weight: 500;
3309
+ transition: all 0.2s ease;
3310
+ }
3311
+ .dialog-confirm-btn:hover {
3312
+ background-color: #ff8f1f;
3313
+ transform: translateY(-1px);
3314
+ }
3315
+ .dialog-confirm-btn:active {
3316
+ transform: translateY(0);
3317
+ }
3318
+ .dialog-cancel-btn {
3319
+ padding: 8px 24px;
3320
+ background-color: rgba(255, 255, 255, 0.1);
3321
+ color: rgba(255, 255, 255, 0.8);
3322
+ border: none;
3323
+ border-radius: 6px;
3324
+ cursor: pointer;
3325
+ font-size: 14px;
3326
+ font-weight: 500;
3327
+ transition: all 0.2s ease;
3328
+ }
3329
+ .dialog-cancel-btn:hover {
3330
+ background-color: rgba(255, 255, 255, 0.15);
3331
+ transform: translateY(-1px);
3332
+ }
3333
+ .dialog-cancel-btn:active {
3334
+ transform: translateY(0);
3335
+ }
3336
+
3337
+ .dialog-overlay {
3338
+ animation: fadeIn 0.2s ease;
3339
+ }
3340
+ .dialog-container {
3341
+ animation: slideIn 0.2s ease;
3342
+ }
3343
+ @keyframes fadeIn {
3344
+ from {
3345
+ opacity: 0;
3346
+ }
3347
+ to {
3348
+ opacity: 1;
3349
+ }
3350
+ }
3351
+ @keyframes slideIn {
3352
+ from {
3353
+ transform: translateY(-20px);
3354
+ opacity: 0;
3355
+ }
3356
+ to {
3357
+ transform: translateY(0);
3358
+ opacity: 1;
3359
+ }
3360
+ }
3361
+ `;
3362
+
2889
3363
  // src/core/setupBTCWallet.ts
2890
- var import_big = __toESM(require("big.js"), 1);
2891
3364
  var { transfer, functionCall } = import_transactions.actionCreators;
2892
3365
  var state = {
2893
3366
  saveAccount(account) {
@@ -2937,6 +3410,7 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
2937
3410
  id,
2938
3411
  provider
2939
3412
  }) {
3413
+ var _a;
2940
3414
  const wallet = {
2941
3415
  signIn,
2942
3416
  signOut,
@@ -2946,8 +3420,9 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
2946
3420
  signAndSendTransaction,
2947
3421
  signAndSendTransactions
2948
3422
  };
2949
- const currentConfig = "isDev" in metadata && metadata.isDev ? walletConfig.dev : walletConfig[options.network.networkId];
2950
- const walletNetwork = "isDev" in metadata && metadata.isDev ? "dev" : options.network.networkId;
3423
+ const isDev = (_a = "isDev" in metadata && metadata.isDev) != null ? _a : false;
3424
+ const currentConfig = isDev ? walletConfig.dev : walletConfig[options.network.networkId];
3425
+ const walletNetwork = isDev ? "dev" : options.network.networkId;
2951
3426
  initWalletButton(walletNetwork, wallet);
2952
3427
  if (!inter) {
2953
3428
  inter = setInterval(() => __async(void 0, null, function* () {
@@ -3085,105 +3560,140 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3085
3560
  });
3086
3561
  }
3087
3562
  function signAndSendTransactions(params) {
3088
- return __async(this, null, function* () {
3089
- const btcContext = window.btcContext;
3090
- 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();
3108
- console.log("transferGasTransaction:", transferGasTransaction);
3109
- 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 }
3563
+ return __async(this, null, function* () {
3564
+ const btcContext = window.btcContext;
3565
+ const accountId = state.getAccount();
3566
+ const accountInfo = yield getAccountInfo();
3567
+ yield checkGasTokenArrears(accountInfo.debt_info);
3568
+ const trans = [...params.transactions];
3569
+ console.log("raw trans:", trans);
3570
+ const gasTokenBalance = accountInfo.gas_token[currentConfig.token] || "0";
3571
+ const { transferGasTransaction, useNearPayGas, gasLimit } = yield calculateGasStrategy(
3572
+ gasTokenBalance,
3573
+ trans
3153
3574
  );
3154
- const { result_data: nonceFromApi } = yield getNonceFromApi(
3155
- currentConfig.base_url,
3156
- accountId
3575
+ console.log("transferGasTransaction:", transferGasTransaction);
3576
+ console.log("useNearPayGas:", useNearPayGas);
3577
+ console.log("gasLimit:", gasLimit);
3578
+ if (transferGasTransaction) {
3579
+ trans.unshift(transferGasTransaction);
3580
+ }
3581
+ console.log("calculateGasStrategy trans:", trans);
3582
+ const newTrans = yield Promise.all(
3583
+ trans.map((transaction, index) => convertTransactionToTxHex(transaction, index))
3157
3584
  );
3585
+ const nonceFromApi = yield getNonce(currentConfig.base_url, accountId);
3158
3586
  const nonce = Number(nonceFromApi) > Number(accountInfo.nonce) ? String(nonceFromApi) : String(accountInfo.nonce);
3159
3587
  const intention = {
3160
3588
  chain_id: "397",
3161
3589
  csna: accountId,
3162
- near_transactions: newTransactions.map((t) => t.txHex),
3590
+ near_transactions: newTrans.map((t) => t.txHex),
3163
3591
  gas_token: currentConfig.token,
3164
- gas_limit: currentConfig.gasTokenLimit,
3592
+ gas_limit: gasLimit,
3165
3593
  use_near_pay_gas: useNearPayGas,
3166
3594
  nonce
3167
3595
  };
3168
3596
  const strIntention = JSON.stringify(intention);
3169
3597
  const signature = yield btcContext.signMessage(strIntention);
3170
- const result = yield uploadBTCTx(currentConfig.base_url, {
3598
+ yield receiveTransaction(currentConfig.base_url, {
3171
3599
  sig: signature,
3172
3600
  btcPubKey: state.getBtcPublicKey(),
3173
3601
  data: toHex(strIntention)
3174
3602
  });
3175
- if (result.result_code === 0) {
3176
- const hash = newTransactions.map((t) => t.hash);
3177
- console.log("txHash:", hash);
3178
- const result2 = yield pollTransactionStatuses(options.network.networkId, hash);
3179
- return result2;
3603
+ yield checkBtcTransactionStatus(currentConfig.base_url, signature);
3604
+ const hash = newTrans.map((t) => t.hash);
3605
+ console.log("txHash:", hash);
3606
+ const result = yield pollTransactionStatuses(options.network.networkId, hash);
3607
+ return result;
3608
+ });
3609
+ }
3610
+ function checkGasTokenArrears(debtInfo) {
3611
+ return __async(this, null, function* () {
3612
+ const transferAmount = (debtInfo == null ? void 0 : debtInfo.transfer_amount) || "0";
3613
+ console.log("get_account debtInfo:", debtInfo);
3614
+ if (transferAmount === "0")
3615
+ return;
3616
+ const confirmed = yield Dialog.confirm({
3617
+ title: "Has gas token arrears",
3618
+ message: "You have gas token arrears, please deposit gas token to continue."
3619
+ });
3620
+ if (confirmed) {
3621
+ const action = {
3622
+ receiver_id: currentConfig.token,
3623
+ amount: transferAmount,
3624
+ msg: JSON.stringify("Deposit")
3625
+ };
3626
+ yield executeBTCDepositAndAction({ action, isDev });
3627
+ yield Dialog.alert({
3628
+ title: "Deposit success",
3629
+ message: "Deposit success, will continue to execute transaction."
3630
+ });
3631
+ } else {
3632
+ throw new Error("Deposit failed, please deposit gas token first.");
3633
+ }
3634
+ });
3635
+ }
3636
+ function getAccountInfo() {
3637
+ return __async(this, null, function* () {
3638
+ const accountId = state.getAccount();
3639
+ const accountInfo = yield nearCall2(currentConfig.accountContractId, "get_account", { account_id: accountId });
3640
+ return accountInfo;
3641
+ });
3642
+ }
3643
+ function createGasTokenTransfer(accountId, amount) {
3644
+ return __async(this, null, function* () {
3645
+ return {
3646
+ signerId: accountId,
3647
+ receiverId: currentConfig.token,
3648
+ actions: [
3649
+ {
3650
+ type: "FunctionCall",
3651
+ params: {
3652
+ methodName: "ft_transfer_call",
3653
+ args: {
3654
+ receiver_id: currentConfig.accountContractId,
3655
+ amount,
3656
+ msg: JSON.stringify("Deposit")
3657
+ },
3658
+ gas: new import_big2.default(50).mul(__pow(10, 12)).toFixed(0),
3659
+ deposit: "1"
3660
+ }
3661
+ }
3662
+ ]
3663
+ };
3664
+ });
3665
+ }
3666
+ function recalculateGasWithTransfer(transferTx, transactions2, useNearPayGas, perTxFee) {
3667
+ return __async(this, null, function* () {
3668
+ const { txHex: transferTxHex } = yield convertTransactionToTxHex(transferTx);
3669
+ let newGasLimit;
3670
+ if (useNearPayGas && perTxFee) {
3671
+ newGasLimit = new import_big2.default(perTxFee).mul(transactions2.length + 1).toFixed(0);
3180
3672
  } else {
3181
- return null;
3673
+ newGasLimit = yield getPredictedGasAmount(
3674
+ currentConfig.accountContractId,
3675
+ currentConfig.token,
3676
+ [transferTxHex, ...transactions2.map((t) => t.txHex)]
3677
+ );
3182
3678
  }
3679
+ transferTx.actions[0].params.args.amount = newGasLimit;
3680
+ return { transferGasTransaction: transferTx, useNearPayGas, gasLimit: newGasLimit };
3681
+ });
3682
+ }
3683
+ function getPredictedGasAmount(accountContractId, tokenId, transactions2) {
3684
+ return __async(this, null, function* () {
3685
+ const predictedGas = yield nearCall2(accountContractId, "predict_txs_gas_token_amount", {
3686
+ gas_token_id: tokenId,
3687
+ near_transactions: transactions2
3688
+ });
3689
+ const predictedGasAmount = new import_big2.default(predictedGas).mul(1.2).toFixed(0);
3690
+ console.log("predictedGas:", predictedGasAmount);
3691
+ return predictedGasAmount;
3183
3692
  });
3184
3693
  }
3185
- function getGasConfig() {
3694
+ function calculateGasStrategy(gasTokenBalance, transactions2) {
3186
3695
  return __async(this, null, function* () {
3696
+ var _a2;
3187
3697
  const accountId = state.getAccount();
3188
3698
  const nearAccount = yield provider.query({
3189
3699
  request_type: "view_account",
@@ -3191,39 +3701,102 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3191
3701
  finality: "final"
3192
3702
  });
3193
3703
  const availableBalance = parseFloat(nearAccount.amount) / __pow(10, 24);
3704
+ console.log("available near balance:", availableBalance);
3705
+ console.log("available gas token balance:", gasTokenBalance);
3706
+ const convertTx = yield Promise.all(
3707
+ transactions2.map((transaction, index) => convertTransactionToTxHex(transaction, index))
3708
+ );
3194
3709
  if (availableBalance > 0.2) {
3195
- return { useNearPayGas: true };
3710
+ const gasTokens = yield nearCall2(
3711
+ currentConfig.accountContractId,
3712
+ "list_gas_token",
3713
+ { token_ids: [currentConfig.token] }
3714
+ );
3715
+ console.log("list_gas_token gas tokens:", gasTokens);
3716
+ const perTxFee = Math.max(
3717
+ Number(((_a2 = gasTokens[currentConfig.token]) == null ? void 0 : _a2.per_tx_protocol_fee) || 0),
3718
+ 100
3719
+ );
3720
+ console.log("perTxFee:", perTxFee);
3721
+ const protocolFee = new import_big2.default(perTxFee || "0").mul(convertTx.length).toFixed(0);
3722
+ console.log("protocolFee:", protocolFee);
3723
+ if (new import_big2.default(gasTokenBalance).gte(protocolFee)) {
3724
+ console.log("use near pay gas and enough gas token balance");
3725
+ return { useNearPayGas: true, gasLimit: protocolFee };
3726
+ } else {
3727
+ console.log("use near pay gas and not enough gas token balance");
3728
+ const transferTx = yield createGasTokenTransfer(accountId, protocolFee);
3729
+ return recalculateGasWithTransfer(transferTx, convertTx, true, perTxFee.toString());
3730
+ }
3196
3731
  } 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 };
3732
+ console.log("near balance is not enough, predict the gas token amount required");
3733
+ const adjustedGas = yield getPredictedGasAmount(
3734
+ currentConfig.accountContractId,
3735
+ currentConfig.token,
3736
+ convertTx.map((t) => t.txHex)
3737
+ );
3738
+ if (new import_big2.default(gasTokenBalance).gte(adjustedGas)) {
3739
+ console.log("use gas token and gas token balance is enough");
3740
+ return { useNearPayGas: false, gasLimit: adjustedGas };
3221
3741
  } else {
3222
- throw new Error("No enough gas token balance");
3742
+ console.log("use gas token and gas token balance is not enough, need to transfer");
3743
+ const transferTx = yield createGasTokenTransfer(accountId, adjustedGas);
3744
+ return recalculateGasWithTransfer(transferTx, convertTx, false);
3223
3745
  }
3224
3746
  }
3225
3747
  });
3226
3748
  }
3749
+ function convertTransactionToTxHex(transaction, index = 0) {
3750
+ return __async(this, null, function* () {
3751
+ const accountId = state.getAccount();
3752
+ const publicKey = state.getPublicKey();
3753
+ const publicKeyFormat = import_key_pair.PublicKey.from(publicKey);
3754
+ const { header } = yield provider.block({
3755
+ finality: "final"
3756
+ });
3757
+ const rawAccessKey = yield provider.query({
3758
+ request_type: "view_access_key",
3759
+ account_id: accountId,
3760
+ public_key: publicKey,
3761
+ finality: "final"
3762
+ });
3763
+ const accessKey = __spreadProps(__spreadValues({}, rawAccessKey), {
3764
+ nonce: BigInt(rawAccessKey.nonce || 0)
3765
+ });
3766
+ const nearNonceFromApi = yield getNearNonce(currentConfig.base_url, accountId);
3767
+ let nearNonceNumber = accessKey.nonce + BigInt(1);
3768
+ if (nearNonceFromApi) {
3769
+ nearNonceNumber = BigInt(nearNonceFromApi) > nearNonceNumber ? BigInt(nearNonceFromApi) : nearNonceNumber;
3770
+ }
3771
+ const newActions = transaction.actions.map((action) => {
3772
+ switch (action.type) {
3773
+ case "FunctionCall":
3774
+ return functionCall(
3775
+ action.params.methodName,
3776
+ action.params.args,
3777
+ BigInt(action.params.gas),
3778
+ BigInt(action.params.deposit)
3779
+ );
3780
+ case "Transfer":
3781
+ return transfer(BigInt(action.params.deposit));
3782
+ }
3783
+ }).filter(Boolean);
3784
+ const _transaction = import_near_api_js2.transactions.createTransaction(
3785
+ accountId,
3786
+ publicKeyFormat,
3787
+ transaction.receiverId,
3788
+ BigInt(nearNonceNumber) + BigInt(index),
3789
+ newActions,
3790
+ (0, import_utils6.baseDecode)(header.hash)
3791
+ );
3792
+ const txBytes = (0, import_transaction.encodeTransaction)(_transaction);
3793
+ const txHex = Array.from(txBytes, (byte) => ("0" + (byte & 255).toString(16)).slice(-2)).join(
3794
+ ""
3795
+ );
3796
+ const hash = import_bs58.default.encode(new Uint8Array(import_js_sha256.sha256.array(txBytes)));
3797
+ return { txBytes, txHex, hash };
3798
+ });
3799
+ }
3227
3800
  function initWalletButton(network, wallet2) {
3228
3801
  return __async(this, null, function* () {
3229
3802
  const checkAndSetupWalletButton = () => {
@@ -3244,17 +3817,13 @@ var BTCWallet = (_0) => __async(void 0, [_0], function* ({
3244
3817
  }
3245
3818
  return wallet;
3246
3819
  });
3247
- function getNonceFromApi(url, accountId) {
3248
- return request(`${url}/v1/nonce?csna=${accountId}`);
3249
- }
3250
- function getNearNonceFromApi(url, accountId) {
3251
- return request(`${url}/v1/nonceNear?csna=${accountId}`);
3252
- }
3253
- function uploadBTCTx(url, data) {
3254
- return request(`${url}/v1/receiveTransaction`, {
3255
- method: "POST",
3256
- body: data
3257
- });
3820
+ function toHex(originalString) {
3821
+ const charArray = originalString.split("");
3822
+ const asciiArray = charArray.map((char) => char.charCodeAt(0));
3823
+ const hexArray = asciiArray.map((code) => code.toString(16));
3824
+ let hexString = hexArray.join("");
3825
+ hexString = hexString.replace(/(^0+)/g, "");
3826
+ return hexString;
3258
3827
  }
3259
3828
  function setupBTCWallet({
3260
3829
  iconUrl = "https://assets.deltatrade.ai/assets/chain/btc.svg",
@@ -3283,232 +3852,10 @@ function setupBTCWallet({
3283
3852
  });
3284
3853
  return btcWallet;
3285
3854
  }
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
-
3295
- // src/core/btcUtils.ts
3296
- var import_big2 = __toESM(require("big.js"), 1);
3297
- function getBtcProvider() {
3298
- if (typeof window === "undefined" || !window.btcContext) {
3299
- throw new Error("BTC Provider is not initialized.");
3300
- }
3301
- return window.btcContext;
3302
- }
3303
- function getNetwork() {
3304
- return __async(this, null, function* () {
3305
- const network = yield getBtcProvider().getNetwork();
3306
- console.log("btc network:", network);
3307
- return network === "livenet" ? "mainnet" : "testnet";
3308
- });
3309
- }
3310
- function getBtcRpcUrl() {
3311
- return __async(this, null, function* () {
3312
- const network = yield getNetwork();
3313
- return btcRpcUrls[network];
3314
- });
3315
- }
3316
- function getConfig(isDev) {
3317
- return __async(this, null, function* () {
3318
- const network = yield getNetwork();
3319
- return walletConfig[isDev ? "dev" : network];
3320
- });
3321
- }
3322
- function nearCall(contractId, methodName, args) {
3323
- return __async(this, null, function* () {
3324
- const network = yield getNetwork();
3325
- return nearCallFunction(contractId, methodName, args, { network });
3326
- });
3327
- }
3328
- function receiveDepositMsg(_0, _1) {
3329
- return __async(this, arguments, function* (baseUrl, {
3330
- btcPublicKey,
3331
- txHash,
3332
- depositType = 1,
3333
- postActions,
3334
- extraMsg
3335
- }) {
3336
- const res = yield request(`${baseUrl}/v1/receiveDepositMsg`, {
3337
- method: "POST",
3338
- body: { btcPublicKey, txHash, depositType, postActions, extraMsg }
3339
- });
3340
- console.log("receiveDepositMsg resp:", res);
3341
- return res;
3342
- });
3343
- }
3344
- function checkTransactionStatus(baseUrl, txHash) {
3345
- return __async(this, null, function* () {
3346
- const res = yield request(
3347
- `${baseUrl}/v1/bridgeFromTx?fromTxHash=${txHash}&fromChainId=1`,
3348
- {
3349
- timeout: 6e4,
3350
- pollingInterval: 5e3,
3351
- maxPollingAttempts: 10,
3352
- shouldStopPolling: (res2) => res2.result_code === 0
3353
- }
3354
- );
3355
- return res;
3356
- });
3357
- }
3358
- function getBtcGasPrice() {
3359
- return __async(this, null, function* () {
3360
- const defaultFeeRate = 100;
3361
- try {
3362
- const btcRpcUrl = yield getBtcRpcUrl();
3363
- const res = yield fetch(`${btcRpcUrl}/v1/fees/recommended`).then((res2) => res2.json());
3364
- const feeRate = res.fastestFee;
3365
- return feeRate || defaultFeeRate;
3366
- } catch (error) {
3367
- return defaultFeeRate;
3368
- }
3369
- });
3370
- }
3371
- function getBtcBalance() {
3372
- return __async(this, null, function* () {
3373
- const { account } = yield retryOperation(getBtcProvider, (res2) => !!res2.account);
3374
- if (!account) {
3375
- console.error("BTC Account is not available.");
3376
- return { rawBalance: 0, balance: 0, maxSpendableBalance: 0 };
3377
- }
3378
- 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);
3381
- const balance = rawBalance / __pow(10, 8);
3382
- const feeRate = yield getBtcGasPrice();
3383
- const maxGasFee = feeRate * 350 / __pow(10, 8);
3384
- const availableBalance = Math.max(0, balance - maxGasFee);
3385
- return {
3386
- rawBalance,
3387
- balance,
3388
- availableBalance
3389
- };
3390
- });
3391
- }
3392
- function sendBitcoin(address, amount, feeRate) {
3393
- return __async(this, null, function* () {
3394
- const { sendBitcoin: sendBitcoin2 } = getBtcProvider();
3395
- const txHash = yield sendBitcoin2(address, amount, { feeRate });
3396
- return txHash;
3397
- });
3398
- }
3399
- function estimateDepositAmount(amount, option) {
3400
- return __async(this, null, function* () {
3401
- const config = yield getConfig((option == null ? void 0 : option.isDev) || false);
3402
- const {
3403
- deposit_bridge_fee: { fee_min, fee_rate }
3404
- } = yield nearCall(
3405
- config.bridgeContractId,
3406
- "get_config",
3407
- {}
3408
- );
3409
- const fee = Math.max(Number(fee_min), Number(amount) * fee_rate);
3410
- return new import_big2.default(amount).minus(fee).toFixed(0);
3411
- });
3412
- }
3413
- function executeBTCDepositAndAction(_0) {
3414
- return __async(this, arguments, function* ({
3415
- action,
3416
- feeRate,
3417
- isDev = false
3418
- }) {
3419
- try {
3420
- const { getPublicKey } = getBtcProvider();
3421
- const config = yield getConfig(isDev);
3422
- const btcPublicKey = yield getPublicKey();
3423
- const _action = Object.assign(
3424
- {},
3425
- __spreadProps(__spreadValues({}, action), {
3426
- gas: new import_big2.default(100).mul(__pow(10, 12)).toFixed(0)
3427
- })
3428
- );
3429
- if (!btcPublicKey) {
3430
- throw new Error("BTC Public Key is not available.");
3431
- }
3432
- if (!_action.receiver_id) {
3433
- throw new Error("action.receiver_id is required");
3434
- }
3435
- const amountWithFee = yield estimateDepositAmount(_action.amount, {
3436
- isDev
3437
- });
3438
- _action.amount = amountWithFee;
3439
- if (!_action.amount || !new import_big2.default(_action.amount || 0).gt(0)) {
3440
- throw new Error("action.amount is required or deposit amount is not enough");
3441
- }
3442
- const csna = yield nearCall(
3443
- config.accountContractId,
3444
- "get_chain_signature_near_account_id",
3445
- {
3446
- btc_public_key: btcPublicKey
3447
- }
3448
- );
3449
- const depositMsg = {
3450
- recipient_id: csna,
3451
- post_actions: [_action]
3452
- };
3453
- const storageDepositMsg = {};
3454
- const accountInfo = yield nearCall(
3455
- config.accountContractId,
3456
- "get_account",
3457
- {
3458
- account_id: csna
3459
- }
3460
- );
3461
- if (!(accountInfo == null ? void 0 : accountInfo.nonce)) {
3462
- storageDepositMsg.btc_public_key = btcPublicKey;
3463
- }
3464
- const registerRes = yield nearCall(action.receiver_id, "storage_balance_of", {
3465
- account_id: csna
3466
- });
3467
- if (!(registerRes == null ? void 0 : registerRes.available)) {
3468
- storageDepositMsg.storage_deposit_msg = {
3469
- contract_id: action.receiver_id,
3470
- deposit: new import_big2.default(0.25).mul(__pow(10, 24)).toFixed(0),
3471
- registration_only: true
3472
- };
3473
- }
3474
- if (Object.keys(storageDepositMsg).length > 0) {
3475
- depositMsg.extra_msg = JSON.stringify(storageDepositMsg);
3476
- }
3477
- console.log("get_user_deposit_address params:", { deposit_msg: depositMsg });
3478
- const userDepositAddress = yield nearCall(
3479
- config.bridgeContractId,
3480
- "get_user_deposit_address",
3481
- { deposit_msg: depositMsg }
3482
- );
3483
- const _feeRate = feeRate || (yield getBtcGasPrice());
3484
- console.log("user deposit address:", userDepositAddress);
3485
- console.log("deposit amount:", new import_big2.default(action.amount).toNumber());
3486
- console.log("receive amount:", new import_big2.default(_action.amount).toNumber());
3487
- console.log("fee rate:", _feeRate);
3488
- const txHash = yield sendBitcoin(
3489
- userDepositAddress,
3490
- new import_big2.default(action.amount).toNumber(),
3491
- _feeRate
3492
- );
3493
- yield receiveDepositMsg(config.base_url, {
3494
- btcPublicKey,
3495
- txHash,
3496
- postActions: JSON.stringify(depositMsg.post_actions),
3497
- extraMsg: depositMsg.extra_msg
3498
- });
3499
- const checkTransactionStatusRes = yield checkTransactionStatus(config.base_url, txHash);
3500
- console.log("checkTransactionStatus resp:", checkTransactionStatusRes);
3501
- return checkTransactionStatusRes.result_code === 0 ? { result: "success" } : { result: "failed", error: checkTransactionStatusRes.result_message };
3502
- } catch (error) {
3503
- console.error("Error executing Bridge+BurrowSupply:", error);
3504
- return { result: "failed", error: error.message };
3505
- }
3506
- });
3507
- }
3508
3855
 
3509
3856
  // src/index.ts
3510
3857
  var getVersion = () => {
3511
- return "0.3.10";
3858
+ return "0.3.12";
3512
3859
  };
3513
3860
  if (typeof window !== "undefined") {
3514
3861
  window.__PARTICLE_BTC_CONNECT_VERSION = getVersion();