@multiplechain/bitcoin 0.1.11 → 0.1.13
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/bitcoin-provider.js +1 -1
- package/dist/bitcoin-provider.js.LICENSE.txt +4 -0
- package/package.json +2 -1
- package/src/adapters/leather.js +75 -0
- package/src/adapters/unisat.js +8 -4
- package/src/adapters/xverse.js +86 -0
- package/src/entity/coin.js +9 -40
- package/src/get-adapter.js +2 -0
- package/src/provider.js +38 -29
- package/src/utils.js +5 -0
- package/src/wallet.js +13 -12
|
@@ -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.
|
|
4
|
+
"version": "0.1.13",
|
|
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
|
+
isDetected: () => Boolean(typeof window.LeatherProvider !== 'undefined')
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/adapters/unisat.js
CHANGED
|
@@ -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(
|
|
15
|
+
wallet.switchNetwork(network)
|
|
11
16
|
.then(async () => {
|
|
12
|
-
resolve(
|
|
17
|
+
resolve(wallet);
|
|
13
18
|
})
|
|
14
19
|
.catch(error => {
|
|
15
20
|
reject(error);
|
|
@@ -28,9 +33,8 @@ 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
|
+
isDetected: () => Boolean(typeof window.unisat !== 'undefined' && window.unisat.requestAccounts)
|
|
35
39
|
}
|
|
36
40
|
}
|
|
@@ -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
|
+
isDetected: () => Boolean(typeof window.XverseProviders !== 'undefined' && XverseProviders.BitcoinProvider)
|
|
85
|
+
}
|
|
86
|
+
}
|
package/src/entity/coin.js
CHANGED
|
@@ -43,40 +43,13 @@ class Coin {
|
|
|
43
43
|
/**
|
|
44
44
|
* @returns {Object}
|
|
45
45
|
*/
|
|
46
|
-
async getBalance() {
|
|
47
|
-
let
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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.
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
})
|
|
98
|
-
.catch((error) => {
|
|
99
|
-
reject(error);
|
|
100
|
-
});
|
|
67
|
+
|
|
68
|
+
// develop for be side
|
|
69
|
+
|
|
101
70
|
});
|
|
102
71
|
}
|
|
103
72
|
}
|
package/src/get-adapter.js
CHANGED
package/src/provider.js
CHANGED
|
@@ -41,32 +41,43 @@ class Provider {
|
|
|
41
41
|
/**
|
|
42
42
|
* @var {Object}
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
supportedWallets = {};
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* @var {Object}
|
|
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' : '
|
|
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.
|
|
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.
|
|
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
|
-
this.
|
|
80
|
+
this.initSupportedWallets();
|
|
70
81
|
}
|
|
71
82
|
|
|
72
83
|
getWalletOpenLink(address, amount) {
|
|
@@ -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');
|
|
@@ -164,40 +175,38 @@ class Provider {
|
|
|
164
175
|
}
|
|
165
176
|
|
|
166
177
|
/**
|
|
167
|
-
* @
|
|
168
|
-
* @returns {Array}
|
|
178
|
+
* @returns {void}
|
|
169
179
|
*/
|
|
170
|
-
|
|
171
|
-
|
|
180
|
+
initSupportedWallets() {
|
|
172
181
|
const Wallet = require('./wallet');
|
|
173
182
|
|
|
174
|
-
|
|
175
|
-
unisat: new Wallet('unisat', this)
|
|
183
|
+
this.supportedWallets = {
|
|
184
|
+
unisat: new Wallet('unisat', this),
|
|
185
|
+
xverse: new Wallet('xverse', this),
|
|
186
|
+
leather: new Wallet('leather', this),
|
|
176
187
|
};
|
|
177
188
|
|
|
178
|
-
return Object.fromEntries(Object.entries(wallets).filter(([key]) => {
|
|
179
|
-
return !filter ? true : filter.includes(key);
|
|
180
|
-
}));
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
/**
|
|
184
192
|
* @param {Array|null} filter
|
|
185
193
|
* @returns {Array}
|
|
186
194
|
*/
|
|
187
|
-
|
|
188
|
-
return Object.fromEntries(Object.entries(this.
|
|
195
|
+
getSupportedWallets(filter) {
|
|
196
|
+
return Object.fromEntries(Object.entries(this.supportedWallets).filter(([key]) => {
|
|
189
197
|
return !filter ? true : filter.includes(key);
|
|
190
198
|
}));
|
|
191
199
|
}
|
|
192
200
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
+
/**
|
|
202
|
+
* @param {Array|null} filter
|
|
203
|
+
* @returns {Array}
|
|
204
|
+
*/
|
|
205
|
+
getDetectedWallets(filter) {
|
|
206
|
+
let detectedWallets = this.getSupportedWallets(filter);
|
|
207
|
+
return Object.fromEntries(Object.entries(detectedWallets).filter(([key, value]) => {
|
|
208
|
+
return value.isDetected() == undefined ? true : value.isDetected()
|
|
209
|
+
}));
|
|
201
210
|
}
|
|
202
211
|
|
|
203
212
|
Coin() {
|
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
|
/**
|
|
@@ -79,7 +78,7 @@ class Wallet {
|
|
|
79
78
|
* @returns {Boolean}
|
|
80
79
|
*/
|
|
81
80
|
isDetected() {
|
|
82
|
-
return this.adapter.
|
|
81
|
+
return this.adapter.isDetected();
|
|
83
82
|
}
|
|
84
83
|
|
|
85
84
|
/**
|
|
@@ -88,14 +87,11 @@ class Wallet {
|
|
|
88
87
|
connect() {
|
|
89
88
|
return new Promise((resolve, reject) => {
|
|
90
89
|
this.adapter.connect()
|
|
91
|
-
.then(async (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
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
|
})
|