@multiplechain/bitcoin 0.1.0 → 0.1.2
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/package.json +45 -45
- package/src/adapters/unisat.js +35 -0
- package/src/entity/coin.js +105 -0
- package/src/entity/token.js +5 -0
- package/src/{transaction.js → entity/transaction.js} +18 -66
- package/src/get-adapter.js +11 -0
- package/src/provider.js +139 -31
- package/src/utils.js +21 -0
- package/src/wallet.js +185 -0
package/package.json
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
{
|
|
2
|
-
"namespace": "multiplechain",
|
|
3
|
-
"name": "@multiplechain/bitcoin",
|
|
4
|
-
"version": "0.1.
|
|
5
|
-
"description": "Bitcoin JS provider",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"serve": "parcel test.html --no-cache --dist-dir test",
|
|
8
|
-
"build": "webpack"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"src"
|
|
12
|
-
],
|
|
13
|
-
"main": "src/provider.js",
|
|
14
|
-
"types": "index.d.ts",
|
|
15
|
-
"typings": "index.d.ts",
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "git+https://github.com/MultipleChain/bitcoin.git"
|
|
19
|
-
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
"Blockchain",
|
|
22
|
-
"Bitcoin",
|
|
23
|
-
"Cryptocurrency"
|
|
24
|
-
],
|
|
25
|
-
"author": "MultipleChain",
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"bugs": {
|
|
28
|
-
"url": "https://github.com/MultipleChain/bitcoin/issues"
|
|
29
|
-
},
|
|
30
|
-
"homepage": "https://github.com/MultipleChain/bitcoin",
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"@multiplechain/utils": "^0.1.1",
|
|
33
|
-
"bignumber.js": "^9.1.1",
|
|
34
|
-
"web3-utils": "^1.8.1"
|
|
35
|
-
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"assert": "^2.0.0",
|
|
38
|
-
"buffer": "^5.7.1",
|
|
39
|
-
"events": "^3.3.0",
|
|
40
|
-
"process": "^0.11.10",
|
|
41
|
-
"stream-browserify": "^3.0.0",
|
|
42
|
-
"webpack": "^5.76.0",
|
|
43
|
-
"webpack-cli": "^5.0.1"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"namespace": "multiplechain",
|
|
3
|
+
"name": "@multiplechain/bitcoin",
|
|
4
|
+
"version": "0.1.2",
|
|
5
|
+
"description": "Bitcoin JS provider",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"serve": "parcel test.html --no-cache --dist-dir test",
|
|
8
|
+
"build": "webpack"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"main": "src/bitcoin-provider.js",
|
|
14
|
+
"types": "index.d.ts",
|
|
15
|
+
"typings": "index.d.ts",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/MultipleChain/bitcoin.git"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"Blockchain",
|
|
22
|
+
"Bitcoin",
|
|
23
|
+
"Cryptocurrency"
|
|
24
|
+
],
|
|
25
|
+
"author": "MultipleChain",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/MultipleChain/bitcoin/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/MultipleChain/bitcoin",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@multiplechain/utils": "^0.1.1",
|
|
33
|
+
"bignumber.js": "^9.1.1",
|
|
34
|
+
"web3-utils": "^1.8.1"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"assert": "^2.0.0",
|
|
38
|
+
"buffer": "^5.7.1",
|
|
39
|
+
"events": "^3.3.0",
|
|
40
|
+
"process": "^0.11.10",
|
|
41
|
+
"stream-browserify": "^3.0.0",
|
|
42
|
+
"webpack": "^5.76.0",
|
|
43
|
+
"webpack-cli": "^5.0.1"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module.exports = unisat = (provider) => {
|
|
2
|
+
|
|
3
|
+
const wallet = window.unisat;
|
|
4
|
+
|
|
5
|
+
const connect = async () => {
|
|
6
|
+
return new Promise(async (resolve, reject) => {
|
|
7
|
+
try {
|
|
8
|
+
wallet.requestAccounts()
|
|
9
|
+
.then(async () => {
|
|
10
|
+
wallet.switchNetwork(provider.network)
|
|
11
|
+
.then(async () => {
|
|
12
|
+
resolve((await wallet.getAccounts())[0]);
|
|
13
|
+
})
|
|
14
|
+
.catch(error => {
|
|
15
|
+
reject(error);
|
|
16
|
+
});
|
|
17
|
+
})
|
|
18
|
+
.catch(error => {
|
|
19
|
+
reject(error);
|
|
20
|
+
});
|
|
21
|
+
} catch (error) {
|
|
22
|
+
reject(error);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
key: 'unisat',
|
|
29
|
+
name: 'UniSat',
|
|
30
|
+
type: 'browser',
|
|
31
|
+
wallet,
|
|
32
|
+
connect,
|
|
33
|
+
download: 'https://unisat.io/download'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const utils = require('../utils');
|
|
2
|
+
|
|
3
|
+
class Coin {
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @var {String}
|
|
7
|
+
*/
|
|
8
|
+
symbol;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @var {String}
|
|
12
|
+
*/
|
|
13
|
+
decimals;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @var {Provider}
|
|
17
|
+
*/
|
|
18
|
+
provider;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {Provider} provider
|
|
22
|
+
*/
|
|
23
|
+
constructor(provider) {
|
|
24
|
+
this.provider = provider;
|
|
25
|
+
this.decimals = 8;
|
|
26
|
+
this.symbol = 'BTC';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @returns {String}
|
|
31
|
+
*/
|
|
32
|
+
getSymbol() {
|
|
33
|
+
return this.symbol;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @returns {Integer}
|
|
38
|
+
*/
|
|
39
|
+
getDecimals() {
|
|
40
|
+
return this.decimals;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @returns {Object}
|
|
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
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
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
|
+
/**
|
|
81
|
+
* @param {String} from
|
|
82
|
+
* @param {String} to
|
|
83
|
+
* @param {Number} amount
|
|
84
|
+
* @returns {String|Object}
|
|
85
|
+
*/
|
|
86
|
+
transfer(from, to, amount) {
|
|
87
|
+
return new Promise(async (resolve, reject) => {
|
|
88
|
+
|
|
89
|
+
if (parseFloat(amount) > await this.getConfirmedBalance(from)) {
|
|
90
|
+
return reject('insufficient-balance');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
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
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = Coin;
|
|
@@ -20,7 +20,7 @@ class Transaction {
|
|
|
20
20
|
/**
|
|
21
21
|
* @var {Number}
|
|
22
22
|
*/
|
|
23
|
-
timer;
|
|
23
|
+
timer = 30;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* @param {String} hash
|
|
@@ -49,15 +49,7 @@ class Transaction {
|
|
|
49
49
|
*/
|
|
50
50
|
async getData() {
|
|
51
51
|
try {
|
|
52
|
-
|
|
53
|
-
let txApi;
|
|
54
|
-
|
|
55
|
-
if (this.provider.testnet) {
|
|
56
|
-
txApi = this.provider.api + 'tx/' + this.hash;
|
|
57
|
-
} else {
|
|
58
|
-
txApi = this.provider.api + 'rawtx/' + this.hash;
|
|
59
|
-
}
|
|
60
|
-
|
|
52
|
+
let txApi = this.provider.api + 'tx/' + this.hash;
|
|
61
53
|
this.data = await fetch(txApi).then(res => res.json());
|
|
62
54
|
} catch (error) {
|
|
63
55
|
throw new Error('There was a problem retrieving transaction data!');
|
|
@@ -72,13 +64,7 @@ class Transaction {
|
|
|
72
64
|
async getConfirmations() {
|
|
73
65
|
try {
|
|
74
66
|
|
|
75
|
-
let blockApi;
|
|
76
|
-
if (this.provider.testnet) {
|
|
77
|
-
blockApi = this.provider.api + 'blocks/tip/height';
|
|
78
|
-
} else {
|
|
79
|
-
blockApi = this.provider.api + 'latestblock';
|
|
80
|
-
}
|
|
81
|
-
|
|
67
|
+
let blockApi = this.provider.api + 'blocks/tip/height';
|
|
82
68
|
if (!this.data) await this.getData();
|
|
83
69
|
let latestBlock = await fetch(blockApi).then(res => res.json());
|
|
84
70
|
|
|
@@ -86,14 +72,7 @@ class Transaction {
|
|
|
86
72
|
latestBlock = latestBlock.height;
|
|
87
73
|
}
|
|
88
74
|
|
|
89
|
-
|
|
90
|
-
if (this.provider.testnet) {
|
|
91
|
-
blockHeight = this.data.status.block_height;
|
|
92
|
-
} else {
|
|
93
|
-
blockHeight = this.data.block_height;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return ((latestBlock - blockHeight) + 1);
|
|
75
|
+
return ((latestBlock - (this.data.status.block_height || 0)) + 1);
|
|
97
76
|
} catch (error) {}
|
|
98
77
|
}
|
|
99
78
|
|
|
@@ -133,14 +112,8 @@ class Transaction {
|
|
|
133
112
|
if (this.data == null) {
|
|
134
113
|
result = false;
|
|
135
114
|
} else {
|
|
136
|
-
if (this.
|
|
137
|
-
|
|
138
|
-
result = true;
|
|
139
|
-
}
|
|
140
|
-
} else {
|
|
141
|
-
if (this.data.block_height) {
|
|
142
|
-
result = true;
|
|
143
|
-
}
|
|
115
|
+
if (this.data.status.block_height) {
|
|
116
|
+
result = true;
|
|
144
117
|
}
|
|
145
118
|
}
|
|
146
119
|
|
|
@@ -166,42 +139,25 @@ class Transaction {
|
|
|
166
139
|
}
|
|
167
140
|
|
|
168
141
|
/**
|
|
169
|
-
* @param {
|
|
170
|
-
* @param {Number} amount
|
|
142
|
+
* @param {Object} config
|
|
171
143
|
* @returns {Boolean}
|
|
172
144
|
*/
|
|
173
|
-
async verifyTransferWithData(
|
|
145
|
+
async verifyTransferWithData(config) {
|
|
174
146
|
|
|
175
147
|
if (await this.validateTransaction()) {
|
|
176
148
|
|
|
177
|
-
let data
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
let index = this.data.vout.findIndex(object => {
|
|
181
|
-
return object.scriptpubkey_address == receiver;
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
data = this.data.vout[index];
|
|
185
|
-
|
|
186
|
-
data = {
|
|
187
|
-
receiver: data.scriptpubkey_address,
|
|
188
|
-
amount: utils.toDec(data.value, 8)
|
|
189
|
-
};
|
|
190
|
-
} else {
|
|
191
|
-
|
|
192
|
-
let index = this.data.out.findIndex(object => {
|
|
193
|
-
return object.addr == receiver;
|
|
194
|
-
});
|
|
149
|
+
let index = this.data.vout.findIndex(object => {
|
|
150
|
+
return object.scriptpubkey_address == config.receiver;
|
|
151
|
+
});
|
|
195
152
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
};
|
|
153
|
+
let data = this.data.vout[index];
|
|
154
|
+
|
|
155
|
+
data = {
|
|
156
|
+
receiver: data.scriptpubkey_address,
|
|
157
|
+
amount: utils.toDec(data.value, 8)
|
|
202
158
|
}
|
|
203
159
|
|
|
204
|
-
if (data.receiver == receiver && data.amount == amount) {
|
|
160
|
+
if (data.receiver == config.receiver && data.amount == config.amount) {
|
|
205
161
|
return true;
|
|
206
162
|
} else {
|
|
207
163
|
return false;
|
|
@@ -215,11 +171,7 @@ class Transaction {
|
|
|
215
171
|
* @returns {String}
|
|
216
172
|
*/
|
|
217
173
|
getUrl() {
|
|
218
|
-
|
|
219
|
-
return this.provider.explorer + 'tx/' + this.hash;
|
|
220
|
-
} else {
|
|
221
|
-
return this.provider.explorer + 'transactions/btc/' + this.hash;
|
|
222
|
-
}
|
|
174
|
+
return this.provider.explorer + 'tx/' + this.hash;
|
|
223
175
|
}
|
|
224
176
|
}
|
|
225
177
|
|
package/src/provider.js
CHANGED
|
@@ -1,72 +1,180 @@
|
|
|
1
|
-
const Transaction = require("./transaction");
|
|
2
1
|
const utils = require("@multiplechain/utils");
|
|
2
|
+
const Coin = require("./entity/coin");
|
|
3
|
+
const Token = require("./entity/token");
|
|
4
|
+
const Transaction = require("./entity/transaction");
|
|
3
5
|
|
|
4
6
|
class Provider {
|
|
5
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @var {String}
|
|
10
|
+
*/
|
|
6
11
|
api;
|
|
7
12
|
|
|
13
|
+
/**
|
|
14
|
+
* @var {String}
|
|
15
|
+
*/
|
|
8
16
|
explorer;
|
|
9
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @var {Boolean}
|
|
20
|
+
*/
|
|
10
21
|
testnet;
|
|
11
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @var {String}
|
|
25
|
+
*/
|
|
26
|
+
network;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @var {Object}
|
|
30
|
+
*/
|
|
31
|
+
detectedWallets = [];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @var {Object}
|
|
35
|
+
*/
|
|
36
|
+
connectedWallet;
|
|
37
|
+
|
|
12
38
|
constructor(testnet = false) {
|
|
13
39
|
this.testnet = testnet;
|
|
40
|
+
this.network = testnet ? 'testnet' : 'livenet';
|
|
14
41
|
|
|
15
42
|
if (!this.testnet) {
|
|
16
|
-
this.api = "https://
|
|
17
|
-
this.explorer = "https://
|
|
43
|
+
this.api = "https://blockstream.info/api/";
|
|
44
|
+
this.explorer = "https://blockstream.info/";
|
|
18
45
|
} else {
|
|
19
46
|
this.api = "https://blockstream.info/testnet/api/";
|
|
20
47
|
this.explorer = "https://blockstream.info/testnet/";
|
|
21
48
|
}
|
|
49
|
+
|
|
50
|
+
this.detectWallets();
|
|
22
51
|
}
|
|
23
52
|
|
|
24
53
|
getWalletOpenLink(address, amount) {
|
|
25
54
|
return 'bitcoin' + ':' + String(address).toUpperCase() + '?amount=' + amount;
|
|
26
55
|
}
|
|
27
56
|
|
|
28
|
-
|
|
57
|
+
errorCheck(data) {
|
|
58
|
+
if (typeof data == 'string') {
|
|
59
|
+
if (data == 'Address on invalid network') {
|
|
60
|
+
return {
|
|
61
|
+
error: 'invalid-address'
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
return {
|
|
65
|
+
error: 'any-error'
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} else if (data.error) {
|
|
69
|
+
if (data.error == 'not-found-or-invalid-arg') {
|
|
70
|
+
return {
|
|
71
|
+
error: 'invalid-address'
|
|
72
|
+
}
|
|
73
|
+
} else {
|
|
74
|
+
return {
|
|
75
|
+
error: 'any-error'
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return data;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {String} receiver
|
|
85
|
+
* @returns
|
|
86
|
+
*/
|
|
87
|
+
async getLastTransactionByReceiver(receiver) {
|
|
29
88
|
|
|
30
|
-
let apiUrl;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
89
|
+
let apiUrl = this.api + 'address/' + receiver + '/txs';
|
|
90
|
+
let data = await fetch(apiUrl).then(response => response.text());
|
|
91
|
+
try {
|
|
92
|
+
data = JSON.parse(data);
|
|
93
|
+
} catch (error) {}
|
|
94
|
+
|
|
95
|
+
data = this.errorCheck(data);
|
|
96
|
+
if (data.error) {
|
|
97
|
+
return data;
|
|
35
98
|
}
|
|
36
99
|
|
|
37
|
-
|
|
100
|
+
if (data.length == 0) {
|
|
101
|
+
return {
|
|
102
|
+
hash: null,
|
|
103
|
+
amount: 0
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
let tx = data[0];
|
|
38
108
|
|
|
39
|
-
|
|
109
|
+
let index = tx.vout.findIndex(object => {
|
|
110
|
+
return object.scriptpubkey_address == receiver;
|
|
111
|
+
});
|
|
40
112
|
|
|
41
|
-
|
|
113
|
+
data = tx.vout[index];
|
|
42
114
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
115
|
+
return {
|
|
116
|
+
hash: tx.txid,
|
|
117
|
+
amount: utils.toDec(data.value, 8)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
46
120
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
121
|
+
/**
|
|
122
|
+
* @param {Wallet} wallet
|
|
123
|
+
*/
|
|
124
|
+
setConnectedWallet(wallet) {
|
|
125
|
+
this.connectedWallet = wallet;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @param {String} adapter
|
|
130
|
+
* @returns {Promise}
|
|
131
|
+
*/
|
|
132
|
+
connectWallet(adapter) {
|
|
133
|
+
return new Promise(async (resolve, reject) => {
|
|
134
|
+
if (this.detectedWallets[adapter]) {
|
|
135
|
+
let wallet = this.detectedWallets[adapter];
|
|
136
|
+
wallet.connect()
|
|
137
|
+
.then(() => {
|
|
138
|
+
resolve(wallet);
|
|
139
|
+
})
|
|
140
|
+
.catch(error => {
|
|
141
|
+
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
reject('wallet-not-found');
|
|
52
145
|
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let tx = data[0];
|
|
146
|
+
});
|
|
147
|
+
}
|
|
56
148
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
149
|
+
/**
|
|
150
|
+
* @param {Array} filter
|
|
151
|
+
* @returns {Array}
|
|
152
|
+
*/
|
|
153
|
+
getDetectedWallets(filter) {
|
|
154
|
+
if (!filter) return this.detectedWallets;
|
|
155
|
+
return Object.fromEntries(Object.entries(this.detectedWallets).filter(([key]) => {
|
|
156
|
+
return filter.includes(key);
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
60
159
|
|
|
61
|
-
|
|
160
|
+
detectWallets() {
|
|
161
|
+
if (typeof window != 'undefined') {
|
|
162
|
+
const Wallet = require('./wallet');
|
|
62
163
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
};
|
|
164
|
+
if (typeof window.unisat !== 'undefined') {
|
|
165
|
+
this.detectedWallets['unisat'] = new Wallet('unisat', this);
|
|
166
|
+
}
|
|
67
167
|
}
|
|
68
168
|
}
|
|
69
169
|
|
|
170
|
+
Coin() {
|
|
171
|
+
return new Coin(this);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Token(address) {
|
|
175
|
+
return new Token(address, this);
|
|
176
|
+
}
|
|
177
|
+
|
|
70
178
|
Transaction(hash) {
|
|
71
179
|
return new Transaction(hash, this);
|
|
72
180
|
}
|
package/src/utils.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const BigNumber = require('bignumber.js');
|
|
2
|
+
const utils = require('@multiplechain/utils');
|
|
3
|
+
|
|
4
|
+
module.exports = Object.assign(utils, {
|
|
5
|
+
toSatoshi(amount) {
|
|
6
|
+
let decimals = 8;
|
|
7
|
+
let length = '1' + '0'.repeat(decimals);
|
|
8
|
+
let value = new BigNumber(amount.toString(10), 10).times(length);
|
|
9
|
+
return parseInt(value.toString(10));
|
|
10
|
+
},
|
|
11
|
+
rejectMessage(error, reject) {
|
|
12
|
+
|
|
13
|
+
if (typeof error == 'object') {
|
|
14
|
+
if (error.code == 4001 || error.message == 'User rejected the request.') {
|
|
15
|
+
return reject('request-rejected');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return reject(error);
|
|
20
|
+
}
|
|
21
|
+
})
|
package/src/wallet.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const getAdapter = require('./get-adapter');
|
|
2
|
+
const utils = require('./utils');
|
|
3
|
+
|
|
4
|
+
class Wallet {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @var {Object}
|
|
8
|
+
*/
|
|
9
|
+
adapter;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @var {Object}
|
|
13
|
+
*/
|
|
14
|
+
wallet;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @var {Object}
|
|
18
|
+
*/
|
|
19
|
+
provider;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @var {String}
|
|
23
|
+
*/
|
|
24
|
+
connectedAccount;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {String} adapter
|
|
28
|
+
* @param {Object} provider
|
|
29
|
+
*/
|
|
30
|
+
constructor(adapter, provider) {
|
|
31
|
+
this.provider = provider;
|
|
32
|
+
this.setAdapter(adapter);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {String} adapter
|
|
37
|
+
*/
|
|
38
|
+
setAdapter(adapter) {
|
|
39
|
+
this.adapter = getAdapter(adapter, this.provider);
|
|
40
|
+
this.wallet = this.adapter.wallet;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @returns {String}
|
|
45
|
+
*/
|
|
46
|
+
getKey() {
|
|
47
|
+
return this.adapter.key;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @returns {String}
|
|
52
|
+
*/
|
|
53
|
+
getName() {
|
|
54
|
+
return this.adapter.name;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @returns {String}
|
|
59
|
+
*/
|
|
60
|
+
getType() {
|
|
61
|
+
return this.adapter.type;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @returns {String}
|
|
66
|
+
*/
|
|
67
|
+
getDeepLink() {
|
|
68
|
+
return this.adapter.deepLink;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @returns {String}
|
|
73
|
+
*/
|
|
74
|
+
getDownloadLink() {
|
|
75
|
+
return this.adapter.download;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @returns {String}
|
|
80
|
+
*/
|
|
81
|
+
connect() {
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
let time = 0;
|
|
84
|
+
let timeout = 15;
|
|
85
|
+
let timer = setInterval(async () => {
|
|
86
|
+
time += 1;
|
|
87
|
+
if (time > timeout) {
|
|
88
|
+
clearInterval(timer);
|
|
89
|
+
reject('timeout');
|
|
90
|
+
}
|
|
91
|
+
}, 1000);
|
|
92
|
+
|
|
93
|
+
this.adapter.connect()
|
|
94
|
+
.then(async (connectedAccount) => {
|
|
95
|
+
let network = await this.wallet.getNetwork();
|
|
96
|
+
if (this.provider.network == network) {
|
|
97
|
+
this.provider.setConnectedWallet(this);
|
|
98
|
+
resolve(this.connectedAccount = connectedAccount);
|
|
99
|
+
} else {
|
|
100
|
+
reject('not-accepted-chain');
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
.catch((error) => {
|
|
104
|
+
utils.rejectMessage(error, reject);
|
|
105
|
+
})
|
|
106
|
+
.finally(() => {
|
|
107
|
+
clearInterval(timer);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @returns {Array}
|
|
114
|
+
*/
|
|
115
|
+
getAccounts() {
|
|
116
|
+
return this.wallet.getAccounts();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @returns {String}
|
|
121
|
+
*/
|
|
122
|
+
getPublicKey() {
|
|
123
|
+
return this.wallet.getPublicKey();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @param {String} to
|
|
129
|
+
* @param {Integer} amount
|
|
130
|
+
* @return {Transaction|Object}
|
|
131
|
+
* @throws {Error}
|
|
132
|
+
*/
|
|
133
|
+
coinTransfer(to, amount) {
|
|
134
|
+
return new Promise(async (resolve, reject) => {
|
|
135
|
+
try {
|
|
136
|
+
let coin = this.provider.Coin();
|
|
137
|
+
|
|
138
|
+
coin.transfer(this.connectedAccount, to, amount)
|
|
139
|
+
.then((transactionId) => {
|
|
140
|
+
resolve(this.provider.Transaction(transactionId));
|
|
141
|
+
})
|
|
142
|
+
.catch((error) => {
|
|
143
|
+
utils.rejectMessage(error, reject);
|
|
144
|
+
});
|
|
145
|
+
} catch (error) {
|
|
146
|
+
utils.rejectMessage(error, reject);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// TODO: implement
|
|
152
|
+
tokenTransfer(to, amount, tokenAddress) {
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @param {String} to
|
|
157
|
+
* @param {Integer} amount
|
|
158
|
+
* @param {String|null} tokenAddress
|
|
159
|
+
* @return {Transaction|Object}
|
|
160
|
+
* @throws {Error}
|
|
161
|
+
*/
|
|
162
|
+
transfer(to, amount, tokenAddress = null) {
|
|
163
|
+
if (tokenAddress) {
|
|
164
|
+
return this.tokenTransfer(to, amount, tokenAddress);
|
|
165
|
+
} else {
|
|
166
|
+
return this.coinTransfer(to, amount);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Events
|
|
171
|
+
accountsChanged(callback) {
|
|
172
|
+
this.wallet.on('accountsChanged', (accounts) => {
|
|
173
|
+
callback(accounts);
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
networkChanged(callback) {
|
|
178
|
+
this.wallet.on('networkChanged', (network) => {
|
|
179
|
+
callback(network);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = Wallet;
|