@multiplechain/bitcoin 0.1.11 → 0.1.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.
@@ -14,6 +14,10 @@
14
14
 
15
15
  /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
16
16
 
17
+ /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
18
+
19
+ /*! noble-secp256k1 - MIT License (c) 2019 Paul Miller (paulmillr.com) */
20
+
17
21
  /*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
18
22
 
19
23
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "namespace": "multiplechain",
3
3
  "name": "@multiplechain/bitcoin",
4
- "version": "0.1.11",
4
+ "version": "0.1.12",
5
5
  "description": "Bitcoin JS provider",
6
6
  "scripts": {
7
7
  "serve": "parcel test.html --no-cache --dist-dir test",
@@ -34,6 +34,7 @@
34
34
  "bignumber.js": "^9.1.1",
35
35
  "install": "^0.13.0",
36
36
  "npm": "^9.7.2",
37
+ "sats-connect": "^1.1.1",
37
38
  "web3-utils": "^1.8.1",
38
39
  "ws": "^8.13.0"
39
40
  },
@@ -0,0 +1,75 @@
1
+ module.exports = leather = (provider) => {
2
+
3
+ if (window.crypto && !window.crypto.randomUUID) {
4
+ window.crypto.randomUUID = () => {
5
+ let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
6
+ const r = (Math.random() * 16) | 0;
7
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
8
+ return v.toString(16);
9
+ });
10
+ return uuid;
11
+ };
12
+ }
13
+
14
+ const network = provider.testnet ? 'testnet' : 'mainnet';
15
+
16
+ let wallet = Object.assign({
17
+ sendBitcoin: (to, amount) => {
18
+ return new Promise(async (resolve, reject) => {
19
+ try {
20
+ await wallet.request('sendTransfer', {
21
+ address: to,
22
+ amount,
23
+ network
24
+ })
25
+ .then((response) => {
26
+ resolve(response.result.txid);
27
+ })
28
+ .catch(({error}) => {
29
+ reject(error);
30
+ });
31
+ } catch (error) {
32
+ reject(error)
33
+ }
34
+ });
35
+ },
36
+ on: (event, callback) => {
37
+ if (window.btc && btc.listen) {
38
+ btc.listen(event, callback);
39
+ }
40
+ }
41
+ }, window.LeatherProvider);
42
+
43
+ const connect = async () => {
44
+ return new Promise(async (resolve, reject) => {
45
+ try {
46
+ const addresses = (await wallet.request('getAddresses', {
47
+ network
48
+ })).result.addresses;
49
+ const bitcoin = addresses.find(address => address.type == 'p2wpkh');
50
+
51
+ // for ordinals & BRC-20 integrations
52
+ // const ordinals = addresses.find(address => address.type == 'p2tr');
53
+
54
+ wallet = Object.assign(wallet, window.LeatherProvider);
55
+
56
+ wallet.getAddress = async () => {
57
+ return bitcoin.address;
58
+ }
59
+
60
+ resolve(wallet);
61
+ } catch (error) {
62
+ reject(error);
63
+ }
64
+ });
65
+ }
66
+
67
+ return {
68
+ key: 'leather',
69
+ name: 'Leather',
70
+ supports: ['browser'],
71
+ connect,
72
+ download: 'https://leather.io/install-extension',
73
+ detected: Boolean(typeof window.LeatherProvider !== 'undefined')
74
+ }
75
+ }
@@ -1,15 +1,20 @@
1
1
  module.exports = unisat = (provider) => {
2
2
 
3
3
  const wallet = window.unisat;
4
+ const network = provider.testnet ? 'testnet' : 'livenet';
5
+
6
+ wallet.getAddress = async () => {
7
+ return (await wallet.getAccounts())[0];
8
+ }
4
9
 
5
10
  const connect = async () => {
6
11
  return new Promise(async (resolve, reject) => {
7
12
  try {
8
13
  wallet.requestAccounts()
9
14
  .then(async () => {
10
- wallet.switchNetwork(provider.network)
15
+ wallet.switchNetwork(network)
11
16
  .then(async () => {
12
- resolve((await wallet.getAccounts())[0]);
17
+ resolve(wallet);
13
18
  })
14
19
  .catch(error => {
15
20
  reject(error);
@@ -28,7 +33,6 @@ module.exports = unisat = (provider) => {
28
33
  key: 'unisat',
29
34
  name: 'UniSat',
30
35
  supports: ['browser'],
31
- wallet,
32
36
  connect,
33
37
  download: 'https://unisat.io/download',
34
38
  detected: Boolean(typeof window.unisat !== 'undefined' && window.unisat.requestAccounts)
@@ -0,0 +1,86 @@
1
+ const {getAddress, sendBtcTransaction, BitcoinNetworkType} = require('sats-connect');
2
+
3
+ module.exports = xverse = (provider) => {
4
+
5
+ const type = provider.testnet ?
6
+ BitcoinNetworkType.Testnet:
7
+ BitcoinNetworkType.Mainnet;
8
+
9
+ let wallet = {
10
+ sendBitcoin: (to, amount) => {
11
+ return new Promise(async (resolve, reject) => {
12
+ sendBtcTransaction({
13
+ payload: {
14
+ network: {
15
+ type,
16
+ },
17
+ recipients: [
18
+ {
19
+ address: to,
20
+ amountSats: BigInt(amount),
21
+ }
22
+ ],
23
+ senderAddress: provider.connectedWallet.connectedAccount,
24
+ },
25
+ onFinish: (txId) => {
26
+ resolve(txId);
27
+ },
28
+ onCancel: () => {
29
+ reject('request-rejected');
30
+ }
31
+ });
32
+ });
33
+ },
34
+ on: (event, callback) => {
35
+ // TODO: implement
36
+ }
37
+ }
38
+
39
+ const connect = async () => {
40
+ return new Promise(async (resolve, reject) => {
41
+ try {
42
+ getAddress({
43
+ payload: {
44
+ purposes: ['ordinals', 'payment'],
45
+ message: 'Address for receiving Ordinals and payments',
46
+ network: {
47
+ type
48
+ },
49
+ },
50
+ onFinish: (response) => {
51
+ const addresses = Object.values(response.addresses);
52
+ const bitcoin = addresses.find(address => address.purpose == 'payment');
53
+
54
+ // for ordinals & BRC-20 integrations
55
+ // const ordinals = addresses.find(address => address.purpose == 'ordinals');
56
+
57
+ wallet = Object.assign(wallet, window.XverseProviders.BitcoinProvider);
58
+
59
+ wallet.getAddress = async () => {
60
+ return bitcoin.address;
61
+ }
62
+
63
+ resolve(wallet);
64
+ },
65
+ onCancel: () => {
66
+ reject('request-rejected');
67
+ }
68
+ });
69
+ } catch (error) {
70
+ reject(error);
71
+ }
72
+ });
73
+ }
74
+
75
+ return {
76
+ key: 'xverse',
77
+ name: 'Xverse',
78
+ supports: [
79
+ 'browser',
80
+ 'mobile'
81
+ ],
82
+ connect,
83
+ download: 'https://www.xverse.app/download',
84
+ detected: Boolean(typeof window.XverseProviders !== 'undefined' && XverseProviders.BitcoinProvider)
85
+ }
86
+ }
@@ -43,40 +43,13 @@ class Coin {
43
43
  /**
44
44
  * @returns {Object}
45
45
  */
46
- async getBalance() {
47
- let balance = await this.provider.connectedWallet.wallet.getBalance();
48
- return {
49
- confirmed: utils.toDec(balance.confirmed, this.getDecimals()),
50
- unconfirmed: utils.toDec(balance.unconfirmed, this.getDecimals()),
51
- total: utils.toDec(balance.total, this.getDecimals())
52
- }
46
+ async getBalance(address) {
47
+ let addressStatsApi = this.provider.api + 'address/' + address;
48
+ let addressStats = await fetch(addressStatsApi).then(res => res.json());
49
+ let balanceSat = addressStats.chain_stats.funded_txo_sum - addressStats.chain_stats.spent_txo_sum;
50
+ return utils.toBitcoin(balanceSat);
53
51
  }
54
52
 
55
- /**
56
- * @returns {Number}
57
- */
58
- async getConfirmedBalance() {
59
- let balance = await this.getBalance();
60
- return balance.confirmed;
61
- }
62
-
63
- /**
64
- * @returns {Number}
65
- */
66
- async getUnconfirmedBalance() {
67
- let balance = await this.getBalance();
68
- return balance.unconfirmed;
69
- }
70
-
71
- /**
72
- * @returns {Number}
73
- */
74
- async getTotalBalance() {
75
- let balance = await this.getBalance();
76
- return balance.total;
77
- }
78
-
79
-
80
53
  /**
81
54
  * @param {String} from
82
55
  * @param {String} to
@@ -86,18 +59,14 @@ class Coin {
86
59
  transfer(from, to, amount) {
87
60
  return new Promise(async (resolve, reject) => {
88
61
 
89
- if (parseFloat(amount) > await this.getConfirmedBalance(from)) {
62
+ if (parseFloat(amount) > await this.getBalance(from)) {
90
63
  return reject('insufficient-balance');
91
64
  }
92
65
 
93
66
  amount = utils.toSatoshi(amount);
94
- this.provider.connectedWallet.wallet.sendBitcoin(to, amount)
95
- .then((txid) => {
96
- resolve(txid);
97
- })
98
- .catch((error) => {
99
- reject(error);
100
- });
67
+
68
+ // develop for be side
69
+
101
70
  });
102
71
  }
103
72
  }
@@ -1,5 +1,7 @@
1
1
  const adapters = {
2
2
  unisat: require('./adapters/unisat'),
3
+ xverse: require('./adapters/xverse'),
4
+ leather: require('./adapters/leather'),
3
5
  }
4
6
 
5
7
  /**
package/src/provider.js CHANGED
@@ -48,22 +48,33 @@ class Provider {
48
48
  */
49
49
  connectedWallet;
50
50
 
51
+ /**
52
+ * @var {String}
53
+ */
54
+ blockcypherToken;
55
+
51
56
  /**
52
57
  * @param {Object} options
53
58
  */
54
59
  constructor(options = {}) {
55
60
 
56
61
  this.testnet = options.testnet;
57
- this.network = options.testnet ? 'testnet' : 'livenet';
62
+ this.network = options.testnet ? 'testnet' : 'mainnet';
63
+ this.blockcypherToken = options.blockcypherToken;
58
64
 
59
65
  if (this.testnet) {
60
66
  this.api = "https://blockstream.info/testnet/api/";
61
67
  this.explorer = "https://blockstream.info/testnet/";
62
- this.wsUrl = "wss://socket.blockcypher.com/v1/btc/test3?token=6d9cba333f234b9498473955497c40d9";
68
+ let token = this.blockcypherToken || "6d9cba333f234b9498473955497c40d9";
69
+ this.wsUrl = "wss://socket.blockcypher.com/v1/btc/test3?token=" + token;
63
70
  } else {
64
71
  this.api = "https://blockstream.info/api/";
65
72
  this.explorer = "https://blockstream.info/";
66
- this.wsUrl = "wss://ws.blockchain.info/inv";
73
+ if (this.blockcypherToken) {
74
+ this.wsUrl = "wss://socket.blockcypher.com/v1/btc/main?token=" + this.blockcypherToken;
75
+ } else {
76
+ this.wsUrl = "wss://ws.blockchain.info/inv";
77
+ }
67
78
  }
68
79
 
69
80
  this.detectWallets();
@@ -78,11 +89,11 @@ class Provider {
78
89
  let ws = new WebSocket(this.wsUrl);
79
90
 
80
91
  let message;
81
- if (this.testnet) {
92
+ if (this.testnet || this.blockcypherToken) {
82
93
  message = JSON.stringify({
83
94
  event: "unconfirmed-tx",
84
95
  address: receiver,
85
- token: "6d9cba333f234b9498473955497c40d9"
96
+ token: this.blockcypherToken || "6d9cba333f234b9498473955497c40d9"
86
97
  });
87
98
  } else {
88
99
  message = JSON.stringify({
@@ -92,7 +103,7 @@ class Provider {
92
103
 
93
104
  let subscription = {
94
105
  unsubscribe: () => {
95
- if (!this.testnet) {
106
+ if (!this.testnet && !this.blockcypherToken) {
96
107
  ws.send(JSON.stringify({
97
108
  "op": "unconfirmed_unsub"
98
109
  }));
@@ -121,7 +132,7 @@ class Provider {
121
132
  let result = true;
122
133
  let data = JSON.parse(res.data);
123
134
 
124
- if (!this.testnet) {
135
+ if (!this.testnet && !this.blockcypherToken) {
125
136
  result = data.x.out.find(o => {
126
137
  return String(o.addr).toLowerCase() == receiver.toLowerCase();
127
138
  });
@@ -155,7 +166,7 @@ class Provider {
155
166
  resolve(wallet);
156
167
  })
157
168
  .catch(error => {
158
-
169
+ reject(error);
159
170
  });
160
171
  } else {
161
172
  reject('wallet-not-found');
@@ -172,7 +183,9 @@ class Provider {
172
183
  const Wallet = require('./wallet');
173
184
 
174
185
  const wallets = {
175
- unisat: new Wallet('unisat', this)
186
+ unisat: new Wallet('unisat', this),
187
+ xverse: new Wallet('xverse', this),
188
+ leather: new Wallet('leather', this),
176
189
  };
177
190
 
178
191
  return Object.fromEntries(Object.entries(wallets).filter(([key]) => {
@@ -197,6 +210,14 @@ class Provider {
197
210
  if (typeof window.unisat !== 'undefined' && unisat.requestAccounts) {
198
211
  this.detectedWallets['unisat'] = new Wallet('unisat', this);
199
212
  }
213
+
214
+ if (typeof window.XverseProviders !== 'undefined' && XverseProviders.BitcoinProvider) {
215
+ this.detectedWallets['xverse'] = new Wallet('xverse', this);
216
+ }
217
+
218
+ if (typeof window.LeatherProvider !== 'undefined') {
219
+ this.detectedWallets['leather'] = new Wallet('leather', this);
220
+ }
200
221
  }
201
222
  }
202
223
 
package/src/utils.js CHANGED
@@ -8,11 +8,16 @@ module.exports = Object.assign(utils, {
8
8
  let value = new BigNumber(amount.toString(10), 10).times(length);
9
9
  return parseInt(value.toString(10));
10
10
  },
11
+ toBitcoin(amount) {
12
+ return parseFloat(amount.toString(10) / 100000000);
13
+ },
11
14
  rejectMessage(error, reject) {
12
15
 
13
16
  if (typeof error == 'object') {
14
17
  if (error.code == 4001 || error.message == 'User rejected the request.') {
15
18
  return reject('request-rejected');
19
+ } else if (String(error).includes('is not valid JSON')) {
20
+ return reject('not-accepted-chain');
16
21
  }
17
22
  }
18
23
 
package/src/wallet.js CHANGED
@@ -37,7 +37,6 @@ class Wallet {
37
37
  */
38
38
  setAdapter(adapter) {
39
39
  this.adapter = getAdapter(adapter, this.provider);
40
- this.wallet = this.adapter.wallet;
41
40
  }
42
41
 
43
42
  /**
@@ -88,14 +87,11 @@ class Wallet {
88
87
  connect() {
89
88
  return new Promise((resolve, reject) => {
90
89
  this.adapter.connect()
91
- .then(async (connectedAccount) => {
92
- let network = await this.wallet.getNetwork();
93
- if (this.provider.network == network) {
94
- this.provider.setConnectedWallet(this);
95
- resolve(this.connectedAccount = connectedAccount);
96
- } else {
97
- reject('not-accepted-chain');
98
- }
90
+ .then(async (wallet) => {
91
+ this.wallet = wallet;
92
+ this.connectedAccount = await wallet.getAddress();
93
+ this.provider.setConnectedWallet(this);
94
+ resolve(this.connectedAccount);
99
95
  })
100
96
  .catch((error) => {
101
97
  utils.rejectMessage(error, reject);
@@ -128,8 +124,13 @@ class Wallet {
128
124
  return new Promise(async (resolve, reject) => {
129
125
  try {
130
126
  let coin = this.provider.Coin();
131
-
132
- coin.transfer(this.connectedAccount, to, amount)
127
+ if (parseFloat(amount) > await coin.getBalance(this.connectedAccount)) {
128
+ return reject('insufficient-balance');
129
+ }
130
+
131
+ amount = utils.toSatoshi(amount);
132
+
133
+ this.wallet.sendBitcoin(to, amount)
133
134
  .then((transactionId) => {
134
135
  resolve(this.provider.Transaction(transactionId));
135
136
  })