btc-wallet 0.3.10 → 0.3.12

Sign up to get free protection for your applications and to get access to all the features.
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();