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