btc-wallet 0.5.20-beta → 0.5.21-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,6 +24,18 @@ var __spreadValues = (a, b) => {
24
24
  return a;
25
25
  };
26
26
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
27
+ var __objRest = (source, exclude) => {
28
+ var target = {};
29
+ for (var prop in source)
30
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
31
+ target[prop] = source[prop];
32
+ if (source != null && __getOwnPropSymbols)
33
+ for (var prop of __getOwnPropSymbols(source)) {
34
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
35
+ target[prop] = source[prop];
36
+ }
37
+ return target;
38
+ };
27
39
  var __export = (target, all) => {
28
40
  for (var name in all)
29
41
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -3013,7 +3025,6 @@ function request(url, options) {
3013
3025
  }
3014
3026
  return data;
3015
3027
  } catch (err) {
3016
- console.error(err);
3017
3028
  if (retryCount > 0) {
3018
3029
  console.log(`Retrying... attempts left: ${retryCount}`);
3019
3030
  return request(url, __spreadProps(__spreadValues({}, options), { retryCount: retryCount - 1 }));
@@ -3027,6 +3038,7 @@ function request(url, options) {
3027
3038
  }));
3028
3039
  }
3029
3040
  }
3041
+ console.error(err);
3030
3042
  return Promise.reject(err);
3031
3043
  }
3032
3044
  });
@@ -3199,6 +3211,7 @@ var state_default = {
3199
3211
  };
3200
3212
 
3201
3213
  // src/utils/satoshi.ts
3214
+ var import_coinselect = __toESM(require("coinselect"), 1);
3202
3215
  function getNonce(url, accountId) {
3203
3216
  return __async(this, null, function* () {
3204
3217
  const { result_code, result_message, result_data } = yield request(
@@ -3328,10 +3341,16 @@ function getAccountInfo(_0) {
3328
3341
  ).catch((error) => {
3329
3342
  return void 0;
3330
3343
  });
3331
- console.log("get_account accountInfo:", accountInfo);
3332
3344
  return accountInfo;
3333
3345
  });
3334
3346
  }
3347
+ function getBridgeConfig(_0) {
3348
+ return __async(this, arguments, function* ({ env }) {
3349
+ const config = getWalletConfig(env);
3350
+ const bridgeConfig = yield nearCallFunction(config.bridgeContractId, "get_config", {}, { network: config.network });
3351
+ return bridgeConfig;
3352
+ });
3353
+ }
3335
3354
  function getTokenBalance(_0) {
3336
3355
  return __async(this, arguments, function* ({
3337
3356
  csna,
@@ -3630,11 +3649,196 @@ function getPredictedGasAmount(_0) {
3630
3649
  return gasAmount.toString();
3631
3650
  });
3632
3651
  }
3652
+ function calculateWithdraw(_0) {
3653
+ return __async(this, arguments, function* ({
3654
+ amount,
3655
+ feeRate,
3656
+ csna,
3657
+ btcAddress,
3658
+ env
3659
+ }) {
3660
+ console.log("calculateWithdraw feeRate:", feeRate);
3661
+ try {
3662
+ const config = getWalletConfig(env);
3663
+ const gasLimit = yield calculateGasLimit({
3664
+ csna,
3665
+ transactions: [
3666
+ {
3667
+ signerId: "",
3668
+ receiverId: config.btcToken,
3669
+ actions: [
3670
+ {
3671
+ type: "FunctionCall",
3672
+ params: {
3673
+ methodName: "ft_transfer_call",
3674
+ args: {
3675
+ receiver_id: config.btcToken,
3676
+ amount: "100",
3677
+ msg: ""
3678
+ },
3679
+ gas: "300000000000000",
3680
+ deposit: "1"
3681
+ }
3682
+ }
3683
+ ]
3684
+ }
3685
+ ],
3686
+ env
3687
+ });
3688
+ let satoshis = Number(amount);
3689
+ if (Number(gasLimit) > 0) {
3690
+ satoshis = new import_big.default(amount).minus(gasLimit).toNumber();
3691
+ }
3692
+ const brgConfig = yield getBridgeConfig({ env });
3693
+ const allUTXO = yield nearCallFunction(config.bridgeContractId, "get_utxos_paged", {}, { network: config.network });
3694
+ if (brgConfig.min_withdraw_amount) {
3695
+ if (Number(satoshis) < Number(brgConfig.min_withdraw_amount)) {
3696
+ return {
3697
+ withdrawFee: 0,
3698
+ isError: true,
3699
+ errorMsg: "Mini withdraw amount is " + (Number(brgConfig.min_withdraw_amount) + Number(gasLimit))
3700
+ };
3701
+ }
3702
+ }
3703
+ const feePercent = Number(brgConfig.withdraw_bridge_fee.fee_rate) * Number(satoshis);
3704
+ const withdrawFee = feePercent > Number(brgConfig.withdraw_bridge_fee.fee_min) ? feePercent : Number(brgConfig.withdraw_bridge_fee.fee_min);
3705
+ const withdrawChangeAddress = brgConfig.change_address;
3706
+ const utxos = Object.keys(allUTXO).map((key) => {
3707
+ const txid = key.split("@");
3708
+ return {
3709
+ txid: txid[0],
3710
+ vout: allUTXO[key].vout,
3711
+ value: Number(allUTXO[key].balance),
3712
+ script: allUTXO[key].script
3713
+ };
3714
+ }).filter((utxo) => utxo.value > Number(brgConfig.min_change_amount));
3715
+ if (!utxos || utxos.length === 0) {
3716
+ return {
3717
+ withdrawFee,
3718
+ isError: true,
3719
+ errorMsg: "The network is busy, please try again later."
3720
+ };
3721
+ }
3722
+ const userSatoshis = Number(satoshis);
3723
+ const maxBtcFee = Number(brgConfig.max_btc_gas_fee);
3724
+ const { inputs, outputs, fee } = (0, import_coinselect.default)(
3725
+ utxos,
3726
+ [{ address: btcAddress, value: userSatoshis }],
3727
+ Math.ceil(feeRate || 0)
3728
+ );
3729
+ const newInputs = inputs;
3730
+ let newOutputs = outputs;
3731
+ let newFee = fee;
3732
+ if (!newOutputs || newOutputs.length === 0) {
3733
+ return {
3734
+ withdrawFee,
3735
+ isError: true,
3736
+ errorMsg: "The network is busy, please try again later."
3737
+ };
3738
+ }
3739
+ let userOutput, noUserOutput;
3740
+ for (let i = 0; i < newOutputs.length; i++) {
3741
+ const output = newOutputs[i];
3742
+ if (output.value.toString() === userSatoshis.toString()) {
3743
+ userOutput = output;
3744
+ } else {
3745
+ noUserOutput = output;
3746
+ }
3747
+ if (!output.address) {
3748
+ output.address = withdrawChangeAddress;
3749
+ }
3750
+ }
3751
+ let dis = 0;
3752
+ if (newFee > maxBtcFee) {
3753
+ dis = newFee - maxBtcFee;
3754
+ newFee = maxBtcFee;
3755
+ return {
3756
+ gasFee: newFee,
3757
+ withdrawFee,
3758
+ isError: true,
3759
+ errorMsg: "Gas exceeds maximum value"
3760
+ };
3761
+ }
3762
+ userOutput.value = new import_big.default(userOutput.value).minus(newFee).minus(withdrawFee).toNumber();
3763
+ if (userOutput.value < 0) {
3764
+ return {
3765
+ gasFee: newFee,
3766
+ withdrawFee,
3767
+ isError: true,
3768
+ errorMsg: "Not enough gas"
3769
+ };
3770
+ }
3771
+ if (noUserOutput) {
3772
+ if (!noUserOutput.address) {
3773
+ noUserOutput.address = withdrawChangeAddress;
3774
+ }
3775
+ noUserOutput.value = new import_big.default(noUserOutput.value).plus(newFee).plus(withdrawFee).plus(dis).toNumber();
3776
+ } else {
3777
+ noUserOutput = {
3778
+ address: withdrawChangeAddress,
3779
+ value: new import_big.default(newFee).plus(withdrawFee).plus(dis).toNumber()
3780
+ };
3781
+ newOutputs.push(noUserOutput);
3782
+ }
3783
+ let minValue = Math.min(...newInputs.map((input) => input.value));
3784
+ let totalNoUserOutputValue = noUserOutput.value;
3785
+ while (totalNoUserOutputValue >= minValue && minValue > 0 && newInputs.length > 0) {
3786
+ totalNoUserOutputValue -= minValue;
3787
+ noUserOutput.value = totalNoUserOutputValue;
3788
+ const minValueIndex = newInputs.findIndex((input) => input.value === minValue);
3789
+ if (minValueIndex > -1) {
3790
+ newInputs.splice(minValueIndex, 1);
3791
+ }
3792
+ minValue = Math.min(...newInputs.map((input) => input.value));
3793
+ }
3794
+ let gasMore = 0;
3795
+ if (noUserOutput.value === 0) {
3796
+ newOutputs = newOutputs.filter((item) => item.value !== 0);
3797
+ } else if (noUserOutput.value < Number(brgConfig.min_change_amount)) {
3798
+ gasMore = Number(brgConfig.min_change_amount) - noUserOutput.value;
3799
+ userOutput.value -= gasMore;
3800
+ noUserOutput.value = Number(brgConfig.min_change_amount);
3801
+ }
3802
+ const insufficientOutput = newOutputs.some((item) => item.value < 0);
3803
+ if (insufficientOutput) {
3804
+ return {
3805
+ gasFee: newFee,
3806
+ withdrawFee,
3807
+ isError: true,
3808
+ errorMsg: "Not enough gas"
3809
+ };
3810
+ }
3811
+ const inputSum = newInputs.reduce((sum, cur) => sum + Number(cur.value), 0);
3812
+ const outputSum = newOutputs.reduce((sum, cur) => sum + Number(cur.value), 0);
3813
+ if (newFee + outputSum !== inputSum) {
3814
+ return {
3815
+ withdrawFee,
3816
+ isError: true,
3817
+ errorMsg: "Service busy, please try again later"
3818
+ };
3819
+ }
3820
+ return {
3821
+ withdrawFee: new import_big.default(withdrawFee).plus(gasLimit).plus(gasMore).toNumber(),
3822
+ gasFee: new import_big.default(newFee).toNumber(),
3823
+ inputs: newInputs,
3824
+ outputs: newOutputs,
3825
+ fromAmount: satoshis,
3826
+ receiveAmount: userOutput.value,
3827
+ isError: false
3828
+ };
3829
+ } catch (error) {
3830
+ return {
3831
+ withdrawFee: 0,
3832
+ isError: true,
3833
+ errorMsg: error.message
3834
+ };
3835
+ }
3836
+ });
3837
+ }
3633
3838
 
3634
3839
  // src/core/btcUtils.ts
3635
3840
  var import_bitcoinjs_lib = __toESM(require("bitcoinjs-lib"), 1);
3636
3841
  var ecc = __toESM(require("@bitcoinerlab/secp256k1"), 1);
3637
- var import_coinselect = __toESM(require("coinselect"), 1);
3638
3842
  import_bitcoinjs_lib.default.initEccLib(ecc);
3639
3843
  var NEAR_STORAGE_DEPOSIT_AMOUNT = "1250000000000000000000";
3640
3844
  var NBTC_STORAGE_DEPOSIT_AMOUNT = "3000";
@@ -3758,7 +3962,6 @@ function getDepositAmount(amount, option) {
3758
3962
  var _a;
3759
3963
  const env = (option == null ? void 0 : option.env) || "mainnet";
3760
3964
  const _newAccountMinDepositAmount = (_a = option == null ? void 0 : option.newAccountMinDepositAmount) != null ? _a : true;
3761
- const config = getWalletConfig(env);
3762
3965
  const csna = yield getCsnaAccountId(env);
3763
3966
  const accountInfo = yield getAccountInfo({ csna, env });
3764
3967
  const debtAction = yield checkGasTokenDebt(csna, env, false);
@@ -3766,7 +3969,7 @@ function getDepositAmount(amount, option) {
3766
3969
  const {
3767
3970
  deposit_bridge_fee: { fee_min, fee_rate },
3768
3971
  min_deposit_amount
3769
- } = yield nearCall(config.bridgeContractId, "get_config", {});
3972
+ } = yield getBridgeConfig({ env });
3770
3973
  const depositAmount = Math.max(Number(min_deposit_amount), Number(amount));
3771
3974
  const protocolFee = Math.max(Number(fee_min), Number(depositAmount) * fee_rate);
3772
3975
  const newAccountMinDepositAmount = !(accountInfo == null ? void 0 : accountInfo.nonce) && _newAccountMinDepositAmount ? NEW_ACCOUNT_MIN_DEPOSIT_AMOUNT : 0;
@@ -3958,190 +4161,52 @@ function getWithdrawTransaction(_0) {
3958
4161
  feeRate,
3959
4162
  env = "mainnet"
3960
4163
  }) {
3961
- console.log("=== Start getWithdrawTransaction ===");
4164
+ const config = getWalletConfig(env);
3962
4165
  const provider = getBtcProvider();
3963
4166
  const btcAddress = provider.account;
3964
- const config = getWalletConfig(env);
3965
4167
  const csna = yield getCsnaAccountId(env);
3966
- const brgConfig = yield nearCall(config.bridgeContractId, "get_config", {});
3967
- if (brgConfig.min_withdraw_amount) {
3968
- if (Number(amount) < Number(brgConfig.min_withdraw_amount)) {
3969
- throw new Error("Mini withdraw amount is " + brgConfig.min_withdraw_amount);
3970
- }
3971
- }
3972
- const feePercent = Number(brgConfig.withdraw_bridge_fee.fee_rate) * Number(amount);
3973
- const withdrawFee = feePercent > Number(brgConfig.withdraw_bridge_fee.fee_min) ? feePercent : Number(brgConfig.withdraw_bridge_fee.fee_min);
3974
- console.log("Withdrawal Fee:", {
3975
- feePercent,
3976
- withdrawFee,
3977
- minFee: brgConfig.withdraw_bridge_fee.fee_min
3978
- });
3979
- const gasLimit = yield calculateGasLimit({
4168
+ const _feeRate = feeRate || (yield getBtcGasPrice());
4169
+ const _a = yield calculateWithdraw({
4170
+ amount,
4171
+ feeRate: _feeRate,
3980
4172
  csna,
3981
- transactions: [
3982
- {
3983
- signerId: "",
3984
- receiverId: config.btcToken,
3985
- actions: [
3986
- {
3987
- type: "FunctionCall",
3988
- params: {
3989
- methodName: "ft_transfer_call",
3990
- args: {
3991
- receiver_id: config.btcToken,
3992
- amount: "100",
3993
- msg: ""
3994
- },
3995
- gas: "300000000000000",
3996
- deposit: "1"
3997
- }
3998
- }
3999
- ]
4000
- }
4001
- ],
4173
+ btcAddress,
4002
4174
  env
4003
- });
4004
- const finalAmount = Number(gasLimit) > 0 ? Number(amount) - Number(gasLimit) : Number(amount);
4005
- const allUTXO = yield nearCall(config.bridgeContractId, "get_utxos_paged", {});
4006
- console.log("All UTXOs:", allUTXO);
4007
- if (!allUTXO || Object.keys(allUTXO).length === 0) {
4008
- throw new Error("The network is busy, please try again later.");
4175
+ }), { inputs, outputs, isError, errorMsg } = _a, rest = __objRest(_a, ["inputs", "outputs", "isError", "errorMsg"]);
4176
+ if (isError || !inputs || !outputs) {
4177
+ throw new Error(errorMsg);
4009
4178
  }
4010
- const utxos = Object.keys(allUTXO).map((key) => {
4011
- const txid = key.split("@");
4012
- return {
4013
- txid: txid[0],
4014
- vout: allUTXO[key].vout,
4015
- value: Number(allUTXO[key].balance),
4016
- script: allUTXO[key].script
4017
- };
4018
- });
4019
- console.log("Formatted UTXOs:", utxos);
4020
- const _feeRate = feeRate || (yield getBtcGasPrice());
4021
- console.log("Fee Rate:", _feeRate);
4022
- const coinSelectResult = (0, import_coinselect.default)(
4023
- utxos,
4024
- [{ address: btcAddress, value: Number(finalAmount) }],
4025
- Math.ceil(_feeRate)
4179
+ console.log("inputs:", JSON.stringify(inputs));
4180
+ console.log("outputs:", JSON.stringify(outputs));
4181
+ console.log("inputs - outputs = gas");
4182
+ console.log(
4183
+ `(${inputs.map((item) => item.value).join(" + ")}) - (${outputs.map((item) => item.value).join(" + ")}) = ${rest.gasFee}`
4026
4184
  );
4027
- console.log("Coinselect Result:", coinSelectResult);
4028
- const { inputs, outputs, fee } = coinSelectResult;
4029
- if (!outputs || !inputs) {
4030
- throw new Error("The network is busy, please try again later.");
4031
- }
4032
- const maxBtcFee = Number(brgConfig.max_btc_gas_fee);
4033
- const transactionFee = fee;
4034
- console.log("Transaction Fee:", { transactionFee, maxBtcFee });
4035
- if (transactionFee > maxBtcFee) {
4036
- throw new Error("Gas exceeds maximum value");
4037
- }
4038
- let recipientOutput, changeOutput;
4039
- for (let i = 0; i < outputs.length; i++) {
4040
- const output = outputs[i];
4041
- if (output.value.toString() === finalAmount.toString()) {
4042
- recipientOutput = output;
4043
- } else {
4044
- changeOutput = output;
4045
- }
4046
- if (!output.address) {
4047
- output.address = brgConfig.change_address;
4048
- }
4049
- }
4050
- console.log("Initial Outputs:", { recipientOutput, changeOutput });
4051
- recipientOutput.value = new import_big2.default(recipientOutput.value).minus(transactionFee).minus(withdrawFee).toNumber();
4052
- if (changeOutput) {
4053
- changeOutput.value = new import_big2.default(changeOutput.value).plus(transactionFee).plus(withdrawFee).toNumber();
4054
- const remainingInputs = [...inputs];
4055
- let smallestInput = Math.min.apply(
4056
- null,
4057
- remainingInputs.map((input) => input.value)
4058
- );
4059
- let remainingChangeAmount = changeOutput.value;
4060
- console.log("Initial Change Processing:", { smallestInput, remainingChangeAmount });
4061
- while (remainingChangeAmount >= smallestInput && smallestInput > 0 && remainingInputs.length > 0) {
4062
- remainingChangeAmount -= smallestInput;
4063
- changeOutput.value = remainingChangeAmount;
4064
- const smallestInputIndex = remainingInputs.findIndex(
4065
- (input) => input.value === smallestInput
4066
- );
4067
- if (smallestInputIndex > -1) {
4068
- remainingInputs.splice(smallestInputIndex, 1);
4069
- }
4070
- smallestInput = Math.min.apply(
4071
- null,
4072
- remainingInputs.map((input) => input.value)
4073
- );
4074
- console.log("Change Processing Loop:", {
4075
- remainingChangeAmount,
4076
- smallestInput,
4077
- remainingInputsCount: remainingInputs.length
4078
- });
4079
- }
4080
- const minChangeAmount = Number(brgConfig.min_change_amount);
4081
- let additionalFee = 0;
4082
- console.log("Checking minimum change amount:", {
4083
- changeValue: changeOutput.value,
4084
- minChangeAmount
4085
- });
4086
- let finalOutputs = [...outputs];
4087
- if (changeOutput.value === 0) {
4088
- finalOutputs = finalOutputs.filter((output) => output.value !== 0);
4089
- console.log("Removed zero-value change output", finalOutputs);
4090
- } else if (changeOutput.value < minChangeAmount) {
4091
- additionalFee = minChangeAmount - changeOutput.value;
4092
- recipientOutput.value -= additionalFee;
4093
- changeOutput.value = minChangeAmount;
4094
- console.log("Adjusted for minimum change amount:", {
4095
- additionalFee,
4096
- newRecipientValue: recipientOutput.value,
4097
- newChangeValue: changeOutput.value
4098
- });
4099
- }
4100
- } else {
4101
- changeOutput = {
4102
- address: brgConfig.change_address,
4103
- value: new import_big2.default(transactionFee).plus(withdrawFee).toNumber()
4104
- };
4105
- outputs.push(changeOutput);
4106
- console.log("Created new change output:", changeOutput);
4107
- }
4108
- const insufficientOutput = outputs.some((item) => item.value < 0);
4109
- if (insufficientOutput) {
4110
- console.error("Negative output value detected");
4111
- throw new Error("Not enough gas");
4112
- }
4113
- const inputSum = inputs.reduce((sum, cur) => sum + Number(cur.value), 0);
4114
- const outputSum = outputs.reduce((sum, cur) => sum + Number(cur.value), 0);
4115
- console.log("Balance verification:", { inputSum, outputSum, transactionFee });
4116
- if (transactionFee + outputSum !== inputSum) {
4117
- console.error("Balance mismatch:", { inputSum, outputSum, transactionFee });
4118
- throw new Error("compute error");
4119
- }
4120
4185
  const network = yield getNetwork();
4121
4186
  const btcNetwork = network === "mainnet" ? import_bitcoinjs_lib.default.networks.bitcoin : import_bitcoinjs_lib.default.networks.testnet;
4122
4187
  const psbt = new import_bitcoinjs_lib.default.Psbt({ network: btcNetwork });
4123
4188
  const btcRpcUrl = yield getBtcRpcUrl();
4124
- for (let i = 0; i < inputs.length; i++) {
4125
- const input = inputs[i];
4126
- const txData = yield fetch(`${btcRpcUrl}/tx/${input.txid}`).then((res) => res.json());
4127
- const inputOptions = {
4128
- hash: input.txid,
4129
- index: input.vout,
4130
- sequence: 4294967293,
4131
- witnessUtxo: {
4132
- script: Buffer.from(txData.vout[input.vout].scriptpubkey, "hex"),
4133
- value: input.value
4134
- }
4135
- };
4136
- psbt.addInput(inputOptions);
4137
- }
4189
+ Promise.all(
4190
+ inputs.map((input) => __async(this, null, function* () {
4191
+ const txData = yield fetch(`${btcRpcUrl}/tx/${input.txid}`).then((res) => res.json());
4192
+ const inputOptions = {
4193
+ hash: input.txid,
4194
+ index: input.vout,
4195
+ sequence: 4294967293,
4196
+ witnessUtxo: {
4197
+ script: Buffer.from(txData.vout[input.vout].scriptpubkey, "hex"),
4198
+ value: input.value
4199
+ }
4200
+ };
4201
+ psbt.addInput(inputOptions);
4202
+ }))
4203
+ );
4138
4204
  outputs.forEach((output) => {
4139
4205
  psbt.addOutput({
4140
4206
  address: output.address,
4141
4207
  value: output.value
4142
4208
  });
4143
4209
  });
4144
- console.log("outputs:", JSON.stringify(outputs));
4145
4210
  const _inputs = inputs.map((item) => {
4146
4211
  return `${item.txid}:${item.vout}`;
4147
4212
  });
@@ -4726,7 +4791,7 @@ function setupBTCWallet({
4726
4791
 
4727
4792
  // src/index.ts
4728
4793
  var getVersion = () => {
4729
- return "0.5.20-beta";
4794
+ return "0.5.21-beta";
4730
4795
  };
4731
4796
  if (typeof window !== "undefined") {
4732
4797
  window.__BTC_WALLET_VERSION = getVersion();