btc-wallet 0.5.20-beta → 0.5.21-beta

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