|
|
@ -43,9 +43,6 @@ function _signRequest(method, url, args, privKey) { |
|
|
|
return WalletUtils.signMessage(message, privKey); |
|
|
|
}; |
|
|
|
|
|
|
|
function _createXPrivKey(network) { |
|
|
|
return new Bitcore.HDPrivateKey(network).toString(); |
|
|
|
}; |
|
|
|
|
|
|
|
function API(opts) { |
|
|
|
if (!opts.storage) { |
|
|
@ -146,6 +143,41 @@ API.prototype._doGetRequest = function(url, data, cb) { |
|
|
|
return this._doRequest('get', url, {}, data, cb); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
API.prototype._initData = function(network, walletPrivKey, m, n) { |
|
|
|
var xPrivKey = new Bitcore.HDPrivateKey(network); |
|
|
|
var signingPrivKey = (new Bitcore.HDPrivateKey(xPrivKey)).derive('m/1/0').privateKey.toWIF(); |
|
|
|
var xPubKey = (new Bitcore.HDPublicKey(xPrivKey)).toString(); |
|
|
|
var copayerId = WalletUtils.xpubToCopayerId(xPubKey); |
|
|
|
|
|
|
|
var data = { |
|
|
|
copayerId: copayerId, |
|
|
|
xPrivKey: xPrivKey.toString(), |
|
|
|
publicKeyRing: [xPubKey], |
|
|
|
network: network, |
|
|
|
m: m, |
|
|
|
n: n, |
|
|
|
signingPrivKey: signingPrivKey, |
|
|
|
walletPrivKey: walletPrivKey.toWIF(), |
|
|
|
}; |
|
|
|
return data; |
|
|
|
}; |
|
|
|
|
|
|
|
API.prototype._doJoinWallet = function(walletId, walletPrivKey, xPubKey, copayerName, cb) { |
|
|
|
var args = { |
|
|
|
walletId: walletId, |
|
|
|
name: copayerName, |
|
|
|
xPubKey: xPubKey, |
|
|
|
xPubKeySignature: WalletUtils.signMessage(xPubKey, walletPrivKey), |
|
|
|
}; |
|
|
|
var url = '/v1/wallets/' + walletId + '/copayers'; |
|
|
|
this._doPostRequest(url, args, {}, function(err, body) { |
|
|
|
if (err) return cb(err); |
|
|
|
return cb(null, body.wallet); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb) { |
|
|
|
var self = this; |
|
|
|
network = network || 'livenet'; |
|
|
@ -169,59 +201,53 @@ API.prototype.createWallet = function(walletName, copayerName, m, n, network, cb |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var walletId = body.walletId; |
|
|
|
var secret = walletId + ':' + walletPrivKey.toWIF() + ':' + (network == 'testnet' ? 'T' : 'L'); |
|
|
|
var ret; |
|
|
|
|
|
|
|
if (n > 1) |
|
|
|
ret = secret; |
|
|
|
|
|
|
|
self._joinWallet(secret, copayerName, function(err) { |
|
|
|
return cb(err, ret); |
|
|
|
}); |
|
|
|
var secret = WalletUtils.toSecret(walletId, walletPrivKey, network); |
|
|
|
var data = self._initData(network, walletPrivKey, m, n); |
|
|
|
self._doJoinWallet(walletId, walletPrivKey, data.publicKeyRing[0], copayerName, |
|
|
|
function(err, wallet) { |
|
|
|
if (err) return cb(err); |
|
|
|
self.storage.save(data, function(err) { |
|
|
|
return cb(err, n > 1 ? secret : null); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
API.prototype._joinWallet = function(secret, copayerName, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
var secretSplit = secret.split(':'); |
|
|
|
var walletId = secretSplit[0]; |
|
|
|
|
|
|
|
var walletPrivKey = Bitcore.PrivateKey.fromString(secretSplit[1]); |
|
|
|
var network = secretSplit[2] == 'T' ? 'testnet' : 'livenet'; |
|
|
|
var xPrivKey = _createXPrivKey(network); |
|
|
|
API.prototype.reCreateWallet = function(walletName, cb) { |
|
|
|
var self = this; |
|
|
|
this._loadAndCheck(function(err, data) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var xPubKey = new Bitcore.HDPublicKey(xPrivKey); |
|
|
|
var xPubKeySignature = WalletUtils.signMessage(xPubKey.toString(), walletPrivKey); |
|
|
|
var walletPrivKey = new Bitcore.PrivateKey(); |
|
|
|
var args = { |
|
|
|
name: walletName, |
|
|
|
m: data.m, |
|
|
|
n: data.n, |
|
|
|
pubKey: walletPrivKey.toPublicKey().toString(), |
|
|
|
network: data.network, |
|
|
|
}; |
|
|
|
var url = '/v1/wallets/'; |
|
|
|
self._doPostRequest(url, args, {}, function(err, body) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var signingPrivKey = (new Bitcore.HDPrivateKey(xPrivKey)).derive('m/1/0').privateKey; |
|
|
|
var args = { |
|
|
|
walletId: walletId, |
|
|
|
name: copayerName, |
|
|
|
xPubKey: xPubKey.toString(), |
|
|
|
xPubKeySignature: xPubKeySignature, |
|
|
|
}; |
|
|
|
var url = '/v1/wallets/' + walletId + '/copayers'; |
|
|
|
var walletId = body.walletId; |
|
|
|
|
|
|
|
this._doPostRequest(url, args, {}, function(err, body) { |
|
|
|
var wallet = body.wallet; |
|
|
|
var data = { |
|
|
|
copayerId: body.copayerId, |
|
|
|
|
|
|
|
publicKeyRing: wallet.publicKeyRing, |
|
|
|
network: wallet.network, |
|
|
|
m: wallet.m, |
|
|
|
n: wallet.n, |
|
|
|
|
|
|
|
xPrivKey: xPrivKey, |
|
|
|
walletPrivKey: walletPrivKey.toWIF(), |
|
|
|
signingPrivKey: signingPrivKey.toWIF(), |
|
|
|
}; |
|
|
|
self.storage.save(data, cb); |
|
|
|
var secret = WalletUtils.toSecret(walletId, walletPrivKey, data.network); |
|
|
|
var i = 0; |
|
|
|
async.each(data.publicKeyRing, function(xpub, next) { |
|
|
|
var copayerName = 'recovered Copayer #' + i; |
|
|
|
self._doJoinWallet(walletId, walletPrivKey, data.publicKeyRing[i++], copayerName, next); |
|
|
|
}, function(err) { |
|
|
|
return cb(err); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
API.prototype.joinWallet = function(secret, copayerName, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
@ -229,7 +255,15 @@ API.prototype.joinWallet = function(secret, copayerName, cb) { |
|
|
|
if (data) |
|
|
|
return cb('Storage already contains a wallet'); |
|
|
|
|
|
|
|
self._joinWallet(secret, copayerName, cb); |
|
|
|
var secretData = WalletUtils.fromSecret(secret); |
|
|
|
var data = self._initData(secretData.network, secretData.walletPrivKey); |
|
|
|
self._doJoinWallet(secretData.walletId, secretData.walletPrivKey, data.publicKeyRing[0], copayerName, |
|
|
|
function(err, wallet) { |
|
|
|
if (err) return cb(err); |
|
|
|
data.m = wallet.m; |
|
|
|
data.n = wallet.n; |
|
|
|
self.storage.save(data, cb); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
@ -344,7 +378,7 @@ API.prototype.import = function(str, cb) { |
|
|
|
|
|
|
|
data.publicKeyRing.push(xPubKey); |
|
|
|
data.copayerId = WalletUtils.xPubToCopayerId(xPubKey); |
|
|
|
data.m = data.publicKeyRing.length; |
|
|
|
data.n = data.publicKeyRing.length; |
|
|
|
data.signingPrivKey = (new Bitcore.HDPrivateKey(data.xPrivKey)).derive('m/1/0').privateKey.toWIF(); |
|
|
|
data.network = data.xPrivKey.substr(0, 4) === 'tprv' ? 'testnet' : 'livenet'; |
|
|
|
self.storage.save(data, cb); |
|
|
|