mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 06:52:41 +01:00
ADD: HodlHodl accept offers (#1162)
This commit is contained in:
parent
35b4a30bdf
commit
ddd1255e27
15 changed files with 2031 additions and 539 deletions
|
@ -29,6 +29,10 @@ import WalletExport from './screen/wallets/export';
|
|||
import WalletXpub from './screen/wallets/xpub';
|
||||
import BuyBitcoin from './screen/wallets/buyBitcoin';
|
||||
import HodlHodl from './screen/wallets/hodlHodl';
|
||||
import HodlHodlViewOffer from './screen/wallets/hodlHodlViewOffer';
|
||||
import HodlHodlLogin from './screen/wallets/hodlHodlLogin';
|
||||
import HodlHodlWebview from './screen/wallets/hodlHodlWebview';
|
||||
import HodlHodlMyContracts from './screen/wallets/hodlHodlMyContracts';
|
||||
import Marketplace from './screen/wallets/marketplace';
|
||||
import ReorderWallets from './screen/wallets/reorderWallets';
|
||||
import SelectWallet from './screen/wallets/selectWallet';
|
||||
|
@ -201,6 +205,17 @@ const LNDCreateInvoiceRoot = () => (
|
|||
</LNDCreateInvoiceStack.Navigator>
|
||||
);
|
||||
|
||||
const HodlHodlStack = createStackNavigator();
|
||||
const HodlHodlRoot = () => (
|
||||
<HodlHodlStack.Navigator>
|
||||
<HodlHodlStack.Screen name="HodlHodl" component={HodlHodl} options={HodlHodl.navigationOptions} />
|
||||
<HodlHodlStack.Screen name="HodlHodlViewOffer" component={HodlHodlViewOffer} options={HodlHodlViewOffer.navigationOptions} />
|
||||
<HodlHodlStack.Screen name="HodlHodlLogin" component={HodlHodlLogin} options={HodlHodlLogin.navigationOptions} />
|
||||
<HodlHodlStack.Screen name="HodlHodlMyContracts" component={HodlHodlMyContracts} options={HodlHodlMyContracts.navigationOptions} />
|
||||
<HodlHodlStack.Screen name="HodlHodlWebview" component={HodlHodlWebview} options={HodlHodlWebview.navigationOptions} />
|
||||
</HodlHodlStack.Navigator>
|
||||
);
|
||||
|
||||
// LightningScanInvoiceStackNavigator === ScanLndInvoiceStack
|
||||
const ScanLndInvoiceStack = createStackNavigator();
|
||||
const ScanLndInvoiceRoot = () => (
|
||||
|
@ -236,6 +251,7 @@ const Navigation = () => (
|
|||
<RootStack.Screen name="LNDCreateInvoiceRoot" component={LNDCreateInvoiceRoot} options={{ headerShown: false }} />
|
||||
<RootStack.Screen name="ScanLndInvoiceRoot" component={ScanLndInvoiceRoot} options={{ headerShown: false }} />
|
||||
<RootStack.Screen name="AztecoRedeemRoot" component={AztecoRedeemRoot} options={{ headerShown: false }} />
|
||||
<RootStack.Screen name="HodlHodlRoot" component={HodlHodlRoot} options={{ headerShown: false }} />
|
||||
<RootStack.Screen
|
||||
name="ScanQRCodeRoot"
|
||||
component={ScanQRCodeRoot}
|
||||
|
|
|
@ -29,6 +29,9 @@ export class AppStorage {
|
|||
static PREFERRED_CURRENCY = 'preferredCurrency';
|
||||
static ADVANCED_MODE_ENABLED = 'advancedmodeenabled';
|
||||
static DELETE_WALLET_AFTER_UNINSTALL = 'deleteWalletAfterUninstall';
|
||||
static HODL_HODL_API_KEY = 'HODL_HODL_API_KEY';
|
||||
static HODL_HODL_SIGNATURE_KEY = 'HODL_HODL_SIGNATURE_KEY';
|
||||
static HODL_HODL_CONTRACTS = 'HODL_HODL_CONTRACTS';
|
||||
|
||||
constructor() {
|
||||
/** {Array.<AbstractWallet>} */
|
||||
|
@ -523,6 +526,51 @@ export class AppStorage {
|
|||
return finalBalance;
|
||||
}
|
||||
|
||||
async getHodlHodlApiKey() {
|
||||
try {
|
||||
return await this.getItem(AppStorage.HODL_HODL_API_KEY);
|
||||
} catch (_) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
async getHodlHodlSignatureKey() {
|
||||
try {
|
||||
return await this.getItem(AppStorage.HODL_HODL_SIGNATURE_KEY);
|
||||
} catch (_) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we cant fetch list of contracts from hodlhodl api yet, we have to keep track of it ourselves
|
||||
*
|
||||
* @returns {Promise<string[]>} String ids of contracts in an array
|
||||
*/
|
||||
async getHodlHodlContracts() {
|
||||
try {
|
||||
let json = await this.getItem(AppStorage.HODL_HODL_CONTRACTS);
|
||||
return JSON.parse(json);
|
||||
} catch (_) {}
|
||||
return [];
|
||||
}
|
||||
|
||||
async addHodlHodlContract(id) {
|
||||
let json;
|
||||
try {
|
||||
json = await this.getItem(AppStorage.HODL_HODL_CONTRACTS);
|
||||
json = JSON.parse(json);
|
||||
} catch (_) {
|
||||
json = [];
|
||||
}
|
||||
|
||||
json.push(id);
|
||||
return this.setItem(AppStorage.HODL_HODL_CONTRACTS, JSON.stringify(json));
|
||||
}
|
||||
|
||||
async setHodlHodlApiKey(key, sigKey) {
|
||||
if (sigKey) await this.setItem(AppStorage.HODL_HODL_SIGNATURE_KEY, sigKey);
|
||||
return this.setItem(AppStorage.HODL_HODL_API_KEY, key);
|
||||
}
|
||||
|
||||
async isAdancedModeEnabled() {
|
||||
try {
|
||||
return !!(await this.getItem(AppStorage.ADVANCED_MODE_ENABLED));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Frisbee from 'frisbee';
|
||||
const CryptoJS = require('crypto-js');
|
||||
|
||||
export class HodlHodlApi {
|
||||
static PAGINATION_LIMIT = 'limit'; // int
|
||||
|
@ -74,18 +75,27 @@ export class HodlHodlApi {
|
|||
|
||||
async getMyCountryCode() {
|
||||
const _api = new Frisbee({ baseURI: 'https://ifconfig.co/' });
|
||||
const _api2 = new Frisbee({ baseURI: 'https://geolocation-db.com/' });
|
||||
let response;
|
||||
|
||||
let allowedTries = 6;
|
||||
while (allowedTries > 0) {
|
||||
// this API fails a lot, so lets retry several times
|
||||
response = await _api.get('/country-iso', {
|
||||
headers: { 'Access-Control-Allow-Origin': '*' },
|
||||
});
|
||||
response = await _api.get('/country-iso', { headers: { 'Access-Control-Allow-Origin': '*' } });
|
||||
|
||||
let body = response.body;
|
||||
if (typeof body === 'string') body = body.replace('\n', '');
|
||||
if (!body || body.length !== 2) {
|
||||
// trying api2
|
||||
const response = await _api2.get('/json/', { headers: { 'Access-Control-Allow-Origin': '*' } });
|
||||
body = response.body;
|
||||
let json;
|
||||
try {
|
||||
json = JSON.parse(body);
|
||||
} catch (_) {}
|
||||
if (json && json.country_code) return (this._myCountryCode = json.country_code);
|
||||
// failed, retry
|
||||
|
||||
allowedTries--;
|
||||
await (async () => new Promise(resolve => setTimeout(resolve, 3000)))(); // sleep
|
||||
} else {
|
||||
|
@ -118,6 +128,17 @@ export class HodlHodlApi {
|
|||
return (this._currencies = json.currencies.sort((a, b) => (a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1)));
|
||||
}
|
||||
|
||||
async getOffer(id) {
|
||||
const response = await this._api.get('/api/v1/offers/' + id, this._getHeadersWithoutAuthorization());
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.offer || json.status === 'error') {
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return json.offer;
|
||||
}
|
||||
|
||||
async getOffers(pagination = {}, filters = {}, sort = {}) {
|
||||
const uri = [];
|
||||
for (const key in sort) {
|
||||
|
@ -138,4 +159,141 @@ export class HodlHodlApi {
|
|||
|
||||
return (this._offers = json.offers);
|
||||
}
|
||||
|
||||
createSignature(apiKey, sigKey, nonce) {
|
||||
const sourceMessageForSigning = apiKey + ':' + nonce; // <api_key>:<nonce>
|
||||
return CryptoJS.HmacSHA256(sourceMessageForSigning, sigKey).toString(CryptoJS.enc.Hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://gitlab.com/hodlhodl-public/public_docs/-/blob/master/autologin.md
|
||||
*
|
||||
* @param apiSigKey {string}
|
||||
* @param nonce {integer|null} Optional unix timestamp (sec, not msec), or nothing
|
||||
* @returns {Promise<string>} Token usable for autologin (works only once and only about 30 seconds)
|
||||
*/
|
||||
async requestAutologinToken(apiSigKey, nonce) {
|
||||
nonce = nonce || Math.floor(+new Date() / 1000);
|
||||
const signature = this.createSignature(this.apiKey, apiSigKey, nonce);
|
||||
|
||||
const response = await this._api.get('/api/v1/users/login_token?nonce=' + nonce + '&hmac=' + signature, this._getHeaders());
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.token || json.status === 'error') {
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return json.token;
|
||||
}
|
||||
|
||||
async getMyself() {
|
||||
const response = await this._api.get('/api/v1/users/me', this._getHeaders());
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.user || json.status === 'error') {
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return (this._user = json.user);
|
||||
}
|
||||
|
||||
async acceptOffer(id, version, paymentMethodInstructionId, paymentMethodInstructionVersion, value) {
|
||||
const response = await this._api.post(
|
||||
'/api/v1/contracts',
|
||||
Object.assign({}, this._getHeaders(), {
|
||||
body: {
|
||||
contract: {
|
||||
offer_id: id,
|
||||
offer_version: version,
|
||||
payment_method_instruction_id: paymentMethodInstructionId,
|
||||
payment_method_instruction_version: paymentMethodInstructionVersion,
|
||||
comment: 'I accept your offer',
|
||||
value,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.contract || json.status === 'error') {
|
||||
if (json && json.validation_errors) throw new Error(this.validationErrorsToReadable(json.validation_errors));
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return json.contract;
|
||||
}
|
||||
|
||||
validationErrorsToReadable(errorz) {
|
||||
const ret = [];
|
||||
for (const er of Object.keys(errorz)) {
|
||||
ret.push(errorz[er].join('; '));
|
||||
}
|
||||
|
||||
return ret.join('\n');
|
||||
}
|
||||
|
||||
async getContract(id) {
|
||||
const response = await this._api.get('/api/v1/contracts/' + id, this._getHeaders());
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.contract || json.status === 'error') {
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return json.contract;
|
||||
}
|
||||
|
||||
verifyEscrowAddress(encryptedSeed, encryptPassword, index, address, witnessScript) {
|
||||
// TODO
|
||||
// @see https://gitlab.com/hodlhodl-public/hodl-client-js
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to confirm that client-side validation of escrow data was successful.
|
||||
* This method should be called immediately after escrow address appeared in Getting contract response and this escrow address has been verified locally by the client.
|
||||
*
|
||||
* @param id
|
||||
* @returns {Promise<{}>}
|
||||
*/
|
||||
async markContractAsConfirmed(id) {
|
||||
const response = await this._api.post('/api/v1/contracts/' + id + '/confirm', this._getHeaders());
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.contract || json.status === 'error') {
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return json.contract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buyer (and only buyer) should call this method when fiat payment was made.
|
||||
* This method could be called only if contract’s status is "in_progress".
|
||||
*
|
||||
* @param id
|
||||
* @returns {Promise<{}>}
|
||||
*/
|
||||
async markContractAsPaid(id) {
|
||||
const response = await this._api.post('/api/v1/contracts/' + id + '/mark_as_paid', this._getHeaders());
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.contract || json.status === 'error') {
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return json.contract;
|
||||
}
|
||||
|
||||
async cancelContract(id) {
|
||||
const response = await this._api.post('/api/v1/contracts/' + id + '/cancel', this._getHeaders());
|
||||
|
||||
const json = response.body;
|
||||
if (!json || !json.contract || json.status === 'error') {
|
||||
if (json && json.validation_errors) throw new Error(this.validationErrorsToReadable(json.validation_errors));
|
||||
throw new Error('API failure: ' + JSON.stringify(response));
|
||||
}
|
||||
|
||||
return json.contract;
|
||||
}
|
||||
}
|
||||
|
|
BIN
img/hodlhodl-default-avatar.png
Normal file
BIN
img/hodlhodl-default-avatar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
467
package-lock.json
generated
467
package-lock.json
generated
|
@ -2644,7 +2644,6 @@
|
|||
"version": "6.12.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz",
|
||||
"integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
|
@ -2825,7 +2824,6 @@
|
|||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
|
||||
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safer-buffer": "~2.1.0"
|
||||
}
|
||||
|
@ -2857,8 +2855,26 @@
|
|||
"assert-plus": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
|
||||
},
|
||||
"assign": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/assign/-/assign-0.1.7.tgz",
|
||||
"integrity": "sha1-5jv+Ooh7hjCRPCdmPkzJv/Hd0l8=",
|
||||
"requires": {
|
||||
"fusing": "0.4.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"fusing": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/fusing/-/fusing-0.4.0.tgz",
|
||||
"integrity": "sha1-yZBo9Uyj4R3AEYkCFSq/Nnq6Sk0=",
|
||||
"requires": {
|
||||
"emits": "1.0.x",
|
||||
"predefine": "0.1.x"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"assign-symbols": {
|
||||
"version": "1.0.0",
|
||||
|
@ -2893,8 +2909,7 @@
|
|||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
||||
"dev": true
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"atob": {
|
||||
"version": "2.1.2",
|
||||
|
@ -2919,14 +2934,12 @@
|
|||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
|
||||
},
|
||||
"aws4": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
|
||||
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
|
||||
"dev": true
|
||||
"integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug=="
|
||||
},
|
||||
"babel-cli": {
|
||||
"version": "6.26.0",
|
||||
|
@ -3727,6 +3740,14 @@
|
|||
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
|
||||
"dev": true
|
||||
},
|
||||
"back": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/back/-/back-1.0.2.tgz",
|
||||
"integrity": "sha1-qT9ebOaXKZhNWQGiuxbjsBpNY2k=",
|
||||
"requires": {
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
|
@ -3819,7 +3840,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
||||
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
|
@ -4592,16 +4612,53 @@
|
|||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.1.0.tgz",
|
||||
"integrity": "sha512-6S062WDQUXi6hOfkO/sBPVwE5ASXY4G2+b4atvhJfSsuUUhIaUKlkjLe9692Ipyt5/a+IPF5aVTu3V5gvXq5cg=="
|
||||
},
|
||||
"colornames": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/colornames/-/colornames-0.0.2.tgz",
|
||||
"integrity": "sha1-2BH9bIT1kClJmorEQ2ICk1uSvjE="
|
||||
},
|
||||
"colors": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
|
||||
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
|
||||
},
|
||||
"colorspace": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.0.1.tgz",
|
||||
"integrity": "sha1-yZx5btMRKLmHalLh7l7gOkpxl0k=",
|
||||
"requires": {
|
||||
"color": "0.8.x",
|
||||
"text-hex": "0.0.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"color": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-0.8.0.tgz",
|
||||
"integrity": "sha1-iQwHw/1OZJU3Y4kRz2keVFi2/KU=",
|
||||
"requires": {
|
||||
"color-convert": "^0.5.0",
|
||||
"color-string": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
|
||||
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
|
||||
},
|
||||
"color-string": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
|
||||
"integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
|
||||
"requires": {
|
||||
"color-name": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
|
@ -4951,7 +5008,6 @@
|
|||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
|
@ -5104,8 +5160,7 @@
|
|||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"denodeify": {
|
||||
"version": "1.2.1",
|
||||
|
@ -5326,6 +5381,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"diagnostics": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.0.1.tgz",
|
||||
"integrity": "sha1-rM2wgMgrsl0N1zQwqeaof7tDFUE=",
|
||||
"requires": {
|
||||
"colorspace": "1.0.x",
|
||||
"enabled": "1.0.x",
|
||||
"kuler": "0.0.x"
|
||||
}
|
||||
},
|
||||
"didyoumean": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz",
|
||||
|
@ -5413,7 +5478,6 @@
|
|||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jsbn": "~0.1.0",
|
||||
"safer-buffer": "^2.1.0"
|
||||
|
@ -5466,11 +5530,24 @@
|
|||
"minimalistic-crypto-utils": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"emits": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/emits/-/emits-1.0.2.tgz",
|
||||
"integrity": "sha1-2yDsZmgyUHHDE0QeMM/ipp6nOFk="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
|
||||
},
|
||||
"enabled": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
|
||||
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
|
||||
"requires": {
|
||||
"env-variable": "0.0.x"
|
||||
}
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
|
@ -5497,6 +5574,11 @@
|
|||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
|
||||
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
|
||||
},
|
||||
"env-variable": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz",
|
||||
"integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg=="
|
||||
},
|
||||
"envinfo": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.5.0.tgz",
|
||||
|
@ -6494,8 +6576,7 @@
|
|||
"extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"extend-shallow": {
|
||||
"version": "3.0.2",
|
||||
|
@ -6516,6 +6597,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"extendible": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/extendible/-/extendible-0.1.1.tgz",
|
||||
"integrity": "sha1-4qN+2HEp+0+VM+io11BiMKU5yQU="
|
||||
},
|
||||
"external-editor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||
|
@ -6585,11 +6671,49 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"extract-github": {
|
||||
"version": "0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/extract-github/-/extract-github-0.0.5.tgz",
|
||||
"integrity": "sha1-9UJTbbjBm5g6O+yduW0u8qX/GoY="
|
||||
},
|
||||
"extract-zip": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz",
|
||||
"integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==",
|
||||
"requires": {
|
||||
"concat-stream": "^1.6.2",
|
||||
"debug": "^2.6.9",
|
||||
"mkdirp": "^0.5.4",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
}
|
||||
}
|
||||
},
|
||||
"extsprintf": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
|
||||
},
|
||||
"fancy-log": {
|
||||
"version": "1.3.3",
|
||||
|
@ -6605,8 +6729,7 @@
|
|||
"fast-deep-equal": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
|
||||
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
|
||||
},
|
||||
"fast-diff": {
|
||||
"version": "1.2.0",
|
||||
|
@ -6616,8 +6739,7 @@
|
|||
"fast-json-stable-stringify": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
|
||||
},
|
||||
"fast-levenshtein": {
|
||||
"version": "2.0.6",
|
||||
|
@ -6682,6 +6804,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"fd-slicer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
"integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
|
||||
"requires": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"figures": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
|
||||
|
@ -6841,14 +6971,12 @@
|
|||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
|
||||
},
|
||||
"form-data": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.6",
|
||||
|
@ -7472,6 +7600,14 @@
|
|||
"resolved": "https://registry.npmjs.org/funpermaproxy/-/funpermaproxy-1.0.1.tgz",
|
||||
"integrity": "sha512-9pEzs5vnNtR7ZGihly98w/mQ7blsvl68Wj30ZCDAXy7qDN4CWLLjdfjtH/P2m6whsnaJkw15hysCNHMXue+wdA=="
|
||||
},
|
||||
"fusing": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/fusing/-/fusing-0.2.3.tgz",
|
||||
"integrity": "sha1-0O76+YXSuv3tRK+LGFMW9uQp4ds=",
|
||||
"requires": {
|
||||
"predefine": "0.1.x"
|
||||
}
|
||||
},
|
||||
"fwd-stream": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/fwd-stream/-/fwd-stream-1.0.4.tgz",
|
||||
|
@ -7549,11 +7685,27 @@
|
|||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
|
||||
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"githulk": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/githulk/-/githulk-0.0.7.tgz",
|
||||
"integrity": "sha1-2Wyinw7EMRfFOOUh1mNWbqhLTv8=",
|
||||
"requires": {
|
||||
"debug": "0.7.x",
|
||||
"extract-github": "0.0.x",
|
||||
"mana": "0.1.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz",
|
||||
"integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk="
|
||||
}
|
||||
}
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
|
@ -7606,14 +7758,12 @@
|
|||
"har-schema": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
|
||||
"dev": true
|
||||
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
|
||||
},
|
||||
"har-validator": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
|
||||
"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.5.5",
|
||||
"har-schema": "^2.0.0"
|
||||
|
@ -7631,7 +7781,6 @@
|
|||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
},
|
||||
|
@ -7639,8 +7788,7 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7767,7 +7915,6 @@
|
|||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
|
||||
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"jsprim": "^1.2.2",
|
||||
|
@ -8217,8 +8364,7 @@
|
|||
"isstream": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||
"dev": true
|
||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
|
||||
},
|
||||
"istanbul-lib-coverage": {
|
||||
"version": "2.0.5",
|
||||
|
@ -8974,8 +9120,7 @@
|
|||
"jsbn": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
|
||||
},
|
||||
"jsc-android": {
|
||||
"version": "245459.0.0",
|
||||
|
@ -9046,14 +9191,12 @@
|
|||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
|
||||
},
|
||||
"json-stable-stringify": {
|
||||
"version": "1.0.1",
|
||||
|
@ -9072,8 +9215,7 @@
|
|||
"json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.1.3",
|
||||
|
@ -9100,7 +9242,6 @@
|
|||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
|
||||
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "1.0.0",
|
||||
"extsprintf": "1.3.0",
|
||||
|
@ -9134,8 +9275,15 @@
|
|||
"kleur": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
|
||||
},
|
||||
"kuler": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-0.0.0.tgz",
|
||||
"integrity": "sha1-tmu0a5NOVQ9Z2BiEjgq7pPf1VTw=",
|
||||
"requires": {
|
||||
"colornames": "0.0.2"
|
||||
}
|
||||
},
|
||||
"lcid": {
|
||||
"version": "2.0.0",
|
||||
|
@ -9348,6 +9496,30 @@
|
|||
"type-check": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"licenses": {
|
||||
"version": "0.0.20",
|
||||
"resolved": "https://registry.npmjs.org/licenses/-/licenses-0.0.20.tgz",
|
||||
"integrity": "sha1-8YpXsmp46vKKhz4qN4oz6B9Z0TY=",
|
||||
"requires": {
|
||||
"async": "0.6.x",
|
||||
"debug": "0.8.x",
|
||||
"fusing": "0.2.x",
|
||||
"githulk": "0.0.x",
|
||||
"npm-registry": "0.1.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-0.6.2.tgz",
|
||||
"integrity": "sha1-Qf0DijgSwKi8GELs8IumPrA5K+8="
|
||||
},
|
||||
"debug": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz",
|
||||
"integrity": "sha1-IP9NJvXkIstoobrLu2EDmtjBwTA="
|
||||
}
|
||||
}
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
|
||||
|
@ -9477,6 +9649,41 @@
|
|||
"tmpl": "1.0.x"
|
||||
}
|
||||
},
|
||||
"mana": {
|
||||
"version": "0.1.41",
|
||||
"resolved": "https://registry.npmjs.org/mana/-/mana-0.1.41.tgz",
|
||||
"integrity": "sha1-fLE/cyGGaGVCKWNcT8Wxfib5O30=",
|
||||
"requires": {
|
||||
"assign": ">=0.1.7",
|
||||
"back": "1.0.x",
|
||||
"diagnostics": "1.0.x",
|
||||
"eventemitter3": "1.2.x",
|
||||
"fusing": "1.0.x",
|
||||
"millisecond": "0.1.x",
|
||||
"request": "2.x.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"emits": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emits/-/emits-3.0.0.tgz",
|
||||
"integrity": "sha1-MnUrupXhcHshlWI4Srm7ix/WL3A="
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz",
|
||||
"integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg="
|
||||
},
|
||||
"fusing": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fusing/-/fusing-1.0.0.tgz",
|
||||
"integrity": "sha1-VQwV12r5Jld4qgUezkTUAAoJjUU=",
|
||||
"requires": {
|
||||
"emits": "3.0.x",
|
||||
"predefine": "0.1.x"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"map-age-cleaner": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
|
||||
|
@ -10270,6 +10477,11 @@
|
|||
"to-regex": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"millisecond": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/millisecond/-/millisecond-0.1.2.tgz",
|
||||
"integrity": "sha1-bMWtOGJByrjniv+WT4cCjuyS2sU="
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
|
@ -10532,6 +10744,30 @@
|
|||
"remove-trailing-separator": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"npm-registry": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/npm-registry/-/npm-registry-0.1.13.tgz",
|
||||
"integrity": "sha1-nl2LL9/Bq1mQ1H99674jHXmp6CI=",
|
||||
"requires": {
|
||||
"debug": "0.8.x",
|
||||
"extract-github": "0.0.x",
|
||||
"licenses": "0.0.x",
|
||||
"mana": "0.1.x",
|
||||
"semver": "2.2.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz",
|
||||
"integrity": "sha1-IP9NJvXkIstoobrLu2EDmtjBwTA="
|
||||
},
|
||||
"semver": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-2.2.1.tgz",
|
||||
"integrity": "sha1-eUEYKz/8xYC/8cF5QqzfeVHA0hM="
|
||||
}
|
||||
}
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
|
||||
|
@ -10567,8 +10803,7 @@
|
|||
"oauth-sign": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
|
||||
},
|
||||
"ob1": {
|
||||
"version": "0.56.4",
|
||||
|
@ -11033,11 +11268,15 @@
|
|||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
|
||||
},
|
||||
"performance-now": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
|
||||
},
|
||||
"picomatch": {
|
||||
"version": "2.2.2",
|
||||
|
@ -11194,6 +11433,14 @@
|
|||
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
||||
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
|
||||
},
|
||||
"predefine": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/predefine/-/predefine-0.1.2.tgz",
|
||||
"integrity": "sha1-KqkrRJa8H4VU5DpF92v75Q0z038=",
|
||||
"requires": {
|
||||
"extendible": "0.1.x"
|
||||
}
|
||||
},
|
||||
"prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
|
@ -11276,7 +11523,6 @@
|
|||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz",
|
||||
"integrity": "sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"kleur": "^3.0.3",
|
||||
"sisteransi": "^1.0.4"
|
||||
|
@ -11320,8 +11566,7 @@
|
|||
"psl": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz",
|
||||
"integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ=="
|
||||
},
|
||||
"pump": {
|
||||
"version": "3.0.0",
|
||||
|
@ -11335,8 +11580,7 @@
|
|||
"punycode": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
|
||||
},
|
||||
"pushdata-bitcoin": {
|
||||
"version": "1.0.1",
|
||||
|
@ -12182,12 +12426,20 @@
|
|||
"integrity": "sha512-es/c1yPRc5aQXNjKuNr0nCgYvuD126bGDRAhq5OaKpnccWHGQorctqxKYRKyNjloOM/NGc97C7DDNnfF1cCfJw=="
|
||||
},
|
||||
"react-native-webview": {
|
||||
"version": "6.11.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-6.11.1.tgz",
|
||||
"integrity": "sha512-0OaNCEzdyywJZ70y6Z4fmmuAd2AHYq2AEByIr15z3YetpMXhm9lXUe2V/8BXQIZXeC9FJosj2DAKu48lpZ0nEg==",
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-9.0.2.tgz",
|
||||
"integrity": "sha512-HnQ0+8jt3556QocsYTtmG3Y8eAG88GzmBodDT0PTz4TuLzPJukubj41OFkP7hytZlSdXIxyoV9A06GruyxXeLQ==",
|
||||
"requires": {
|
||||
"escape-string-regexp": "1.0.5",
|
||||
"invariant": "2.2.4"
|
||||
"escape-string-regexp": "2.0.0",
|
||||
"invariant": "2.2.4",
|
||||
"rnpm-plugin-windows": "^0.5.1-0"
|
||||
},
|
||||
"dependencies": {
|
||||
"escape-string-regexp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
|
||||
"integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-refresh": {
|
||||
|
@ -12477,7 +12729,6 @@
|
|||
"version": "2.88.2",
|
||||
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
|
||||
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aws-sign2": "~0.7.0",
|
||||
"aws4": "^1.8.0",
|
||||
|
@ -12504,8 +12755,7 @@
|
|||
"qs": {
|
||||
"version": "6.5.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -12643,6 +12893,63 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"rnpm-plugin-windows": {
|
||||
"version": "0.5.1-0",
|
||||
"resolved": "https://registry.npmjs.org/rnpm-plugin-windows/-/rnpm-plugin-windows-0.5.1-0.tgz",
|
||||
"integrity": "sha512-0EX2shP1OI18MylpVHmZRhDX5GSdvHDgSQoFDZx/Ir73dt3dPVtz7iNviiz3vPa8/8HgTOog3Xzn/gXxfPRrnw==",
|
||||
"requires": {
|
||||
"chalk": "^1.1.3",
|
||||
"extract-zip": "^1.6.7",
|
||||
"fs-extra": "^7.0.1",
|
||||
"npm-registry": "^0.1.13",
|
||||
"prompts": "^2.3.0",
|
||||
"request": "^2.88.0",
|
||||
"semver": "^6.1.1",
|
||||
"valid-url": "^1.0.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||
"requires": {
|
||||
"ansi-styles": "^2.2.1",
|
||||
"escape-string-regexp": "^1.0.2",
|
||||
"has-ansi": "^2.0.0",
|
||||
"strip-ansi": "^3.0.0",
|
||||
"supports-color": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||
}
|
||||
}
|
||||
},
|
||||
"rsvp": {
|
||||
"version": "4.8.5",
|
||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||
|
@ -12952,8 +13259,7 @@
|
|||
"sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
|
||||
},
|
||||
"sjcl": {
|
||||
"version": "1.0.8",
|
||||
|
@ -13178,7 +13484,6 @@
|
|||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
|
||||
"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"asn1": "~0.2.3",
|
||||
"assert-plus": "^1.0.0",
|
||||
|
@ -13558,6 +13863,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"text-hex": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-0.0.0.tgz",
|
||||
"integrity": "sha1-V4+8haapJjbkLdF7QdAhjM6esrM="
|
||||
},
|
||||
"text-table": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||
|
@ -13694,7 +14004,6 @@
|
|||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
|
||||
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"psl": "^1.1.28",
|
||||
"punycode": "^2.1.1"
|
||||
|
@ -13741,7 +14050,6 @@
|
|||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
|
@ -13749,8 +14057,7 @@
|
|||
"tweetnacl": {
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
|
||||
"dev": true
|
||||
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
|
||||
},
|
||||
"type-check": {
|
||||
"version": "0.3.2",
|
||||
|
@ -13905,7 +14212,6 @@
|
|||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
|
@ -14029,6 +14335,11 @@
|
|||
"user-home": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"valid-url": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz",
|
||||
"integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA="
|
||||
},
|
||||
"validate-npm-package-license": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||
|
@ -14055,7 +14366,6 @@
|
|||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"assert-plus": "^1.0.0",
|
||||
"core-util-is": "1.0.2",
|
||||
|
@ -14358,6 +14668,15 @@
|
|||
"camelcase": "^5.0.0",
|
||||
"decamelize": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
"integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
|
||||
"requires": {
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
"react-native-tooltip": "git+https://github.com/marcosrdz/react-native-tooltip.git",
|
||||
"react-native-vector-icons": "6.6.0",
|
||||
"react-native-watch-connectivity": "0.4.2",
|
||||
"react-native-webview": "6.11.1",
|
||||
"react-native-webview": "9.0.2",
|
||||
"react-test-render": "1.1.2",
|
||||
"readable-stream": "3.6.0",
|
||||
"rn-nodeify": "10.2.0",
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import { Platform } from 'react-native';
|
||||
import prompt from 'react-native-prompt-android';
|
||||
|
||||
module.exports = (title, text, isCancelable = true, type = 'secure-text') => {
|
||||
if (Platform.OS === 'ios' && type === 'numeric') {
|
||||
// `react-native-prompt-android` on ios does not support numeric input
|
||||
type = 'plain-text';
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const buttons = isCancelable
|
||||
? [
|
||||
|
|
|
@ -249,6 +249,7 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
marginLeft: 4,
|
||||
minHeight: 33,
|
||||
color: '#81868e',
|
||||
},
|
||||
safeURLHome: {
|
||||
alignContent: 'flex-end',
|
||||
|
@ -455,6 +456,7 @@ export default class Browser extends Component {
|
|||
onChangeText={text => this.setState({ stateURL: text })}
|
||||
value={this.state.stateURL}
|
||||
numberOfLines={1}
|
||||
placeholderTextColor="#81868e"
|
||||
style={styles.safeURLText}
|
||||
editable
|
||||
onSubmitEditing={() => {
|
||||
|
@ -486,11 +488,7 @@ export default class Browser extends Component {
|
|||
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
const reloadUrl = this.state.url;
|
||||
this.setState({ url: 'about:blank' });
|
||||
processedInvoices = {};
|
||||
setTimeout(() => this.setState({ url: reloadUrl }), 500);
|
||||
// this.webview.reload();
|
||||
this.webview.reload();
|
||||
}}
|
||||
>
|
||||
{!this.state.pageIsLoading ? (
|
||||
|
|
File diff suppressed because one or more lines are too long
75
screen/wallets/hodlHodlLogin.js
Normal file
75
screen/wallets/hodlHodlLogin.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
import React, { Component } from 'react';
|
||||
import { WebView } from 'react-native-webview';
|
||||
import { BlueNavigationStyle, SafeBlueArea } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const url = 'https://accounts.hodlhodl.com/accounts/request_access?attributes=api_key,api_signature_key';
|
||||
|
||||
let lastTimeIvebeenHere = 0;
|
||||
|
||||
const INJECTED_JAVASCRIPT = `(function() {
|
||||
|
||||
window.postMessage = function (data) {
|
||||
window.ReactNativeWebView && window.ReactNativeWebView.postMessage(data);
|
||||
}
|
||||
|
||||
})();`;
|
||||
|
||||
export default class HodlHodlLogin extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: 'Login',
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
url: url,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SafeBlueArea>
|
||||
<WebView
|
||||
injectedJavaScript={INJECTED_JAVASCRIPT}
|
||||
ref={ref => (this.webview = ref)}
|
||||
source={{ uri: this.state.url }}
|
||||
onMessage={e => {
|
||||
// this is a handler which receives messages sent from within the browser
|
||||
|
||||
if (lastTimeIvebeenHere && +new Date() - lastTimeIvebeenHere < 5000) return;
|
||||
lastTimeIvebeenHere = +new Date();
|
||||
// page can post messages several times, and that can confuse our react navigation, so we have protection
|
||||
// against that
|
||||
|
||||
let json = false;
|
||||
try {
|
||||
json = JSON.parse(e.nativeEvent.data);
|
||||
} catch (_) {}
|
||||
|
||||
if (json && json.allowed && json.data && json.data.api_key) {
|
||||
this.props.route.params.cb(json.data.api_key, json.data.api_signature_key);
|
||||
this.props.navigation.pop();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HodlHodlLogin.propTypes = {
|
||||
route: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
cb: PropTypes.func.isRequired,
|
||||
}),
|
||||
}),
|
||||
navigation: PropTypes.shape({
|
||||
getParam: PropTypes.func,
|
||||
navigate: PropTypes.func,
|
||||
pop: PropTypes.func,
|
||||
}),
|
||||
};
|
418
screen/wallets/hodlHodlMyContracts.js
Normal file
418
screen/wallets/hodlHodlMyContracts.js
Normal file
|
@ -0,0 +1,418 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import {
|
||||
Alert,
|
||||
FlatList,
|
||||
Keyboard,
|
||||
KeyboardAvoidingView,
|
||||
Linking,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { BlueButton, BlueLoading, BlueNavigationStyle, BlueSpacing10, BlueSpacing20, SafeBlueArea } from '../../BlueComponents';
|
||||
import { AppStorage } from '../../class';
|
||||
import { HodlHodlApi } from '../../class/hodl-hodl-api';
|
||||
import Modal from 'react-native-modal';
|
||||
import NavigationService from '../../NavigationService';
|
||||
|
||||
const BlueApp: AppStorage = require('../../BlueApp');
|
||||
|
||||
export default class HodlHodlMyContracts extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: 'My contracts',
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
contracts: [],
|
||||
isLoading: true,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.state.inverval);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const hodlApiKey = await BlueApp.getHodlHodlApiKey();
|
||||
const hodlApi = new HodlHodlApi(hodlApiKey);
|
||||
this.setState({ hodlApi: hodlApi, contracts: [] });
|
||||
|
||||
const inverval = setInterval(async () => {
|
||||
await this.refetchContracts();
|
||||
}, 60 * 1000);
|
||||
|
||||
this.setState({ inverval });
|
||||
await this.refetchContracts();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.isLoading) return <BlueLoading />;
|
||||
return (
|
||||
<SafeBlueArea>
|
||||
<FlatList
|
||||
scrollEnabled={false}
|
||||
keyExtractor={(item, index) => {
|
||||
return item.id;
|
||||
}}
|
||||
ListEmptyComponent={() => <Text style={styles.emptyComponentText}>You dont have any contracts in progress</Text>}
|
||||
style={styles.flatList}
|
||||
ItemSeparatorComponent={() => <View style={styles.itemSeparatorComponent} />}
|
||||
data={this.state.contracts}
|
||||
renderItem={({ item: contract, index, separators }) => (
|
||||
<TouchableHighlight
|
||||
onShowUnderlay={separators.highlight}
|
||||
onHideUnderlay={separators.unhighlight}
|
||||
onPress={() => this._onContractPress(contract)}
|
||||
>
|
||||
<View style={styles.flexDirectionRow}>
|
||||
<View style={['paid', 'completed'].includes(contract.status) ? styles.statusGreenWrapper : styles.statusGrayWrapper}>
|
||||
<Text style={['paid', 'completed'].includes(contract.status) ? styles.statusGreenText : styles.statusGrayText}>
|
||||
{contract.status}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.flexDirectionColumn}>
|
||||
<View style={styles.flexDirectionRow}>
|
||||
<Text style={styles.volumeBreakdownText}>
|
||||
{contract.volume_breakdown.goes_to_buyer} {contract.asset_code}
|
||||
</Text>
|
||||
<Text style={styles.roleText}>{contract.your_role === 'buyer' ? 'buying' : 'selling'}</Text>
|
||||
</View>
|
||||
|
||||
<View>
|
||||
<Text style={styles.contractStatusText}>{contract.statusText}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
)}
|
||||
/>
|
||||
{this.renderContract()}
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
|
||||
async refetchContracts() {
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
});
|
||||
|
||||
const hodlApi = this.state.hodlApi;
|
||||
const contracts = [];
|
||||
let contractToDisplay = this.state.contractToDisplay;
|
||||
|
||||
const contractIds = await BlueApp.getHodlHodlContracts();
|
||||
|
||||
/*
|
||||
* Initiator sends “Getting contract” request once every 1-3 minutes until contract.escrow.address is not null (thus, waiting for offer’s creator to confirm his payment password in case he uses the website)
|
||||
* Each party verifies the escrow address locally
|
||||
* Each party sends “Confirming contract’s escrow validity” request to the server
|
||||
*/
|
||||
for (const id of contractIds) {
|
||||
let contract;
|
||||
try {
|
||||
contract = await hodlApi.getContract(id);
|
||||
} catch (_) {
|
||||
continue;
|
||||
}
|
||||
if (contract.status === 'canceled') continue;
|
||||
if (contract.escrow && contract.escrow.address && hodlApi.verifyEscrowAddress()) {
|
||||
await hodlApi.markContractAsConfirmed(id);
|
||||
contract.isDepositedEnought =
|
||||
contract.escrow.confirmations >= contract.confirmations && +contract.escrow.amount_deposited >= +contract.volume;
|
||||
// technically, we could fetch balance of escrow address ourselved and verify, but we are relying on api here
|
||||
|
||||
contract.statusText = 'Waiting for seller to deposit bitcoins to escrow...';
|
||||
if (contract.isDepositedEnought && contract.status !== 'paid')
|
||||
contract.statusText = 'Bitcoins are in escrow! Please pay seller\nvia agreed payment method';
|
||||
if (contract.status === 'paid') contract.statusText = 'Waiting for seller to release coins from escrow';
|
||||
if (contract.status === 'in_progress' && contract.your_role === 'buyer')
|
||||
contract.statusText = 'Coins are in escrow, please pay seller';
|
||||
|
||||
if (contract.status === 'completed') contract.statusText = 'All done!';
|
||||
}
|
||||
|
||||
contracts.push(contract);
|
||||
|
||||
if (contractToDisplay && contract.id === this.state.contractToDisplay.id) {
|
||||
// refreshing contract that is currently being displayed
|
||||
contractToDisplay = contract;
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({ hodlApi: hodlApi, contracts, contractToDisplay, isLoading: false });
|
||||
}
|
||||
|
||||
_onContractPress(contract) {
|
||||
this.setState({
|
||||
contractToDisplay: contract,
|
||||
isRenderContractVisible: true,
|
||||
});
|
||||
}
|
||||
|
||||
renderContract = () => {
|
||||
if (!this.state.contractToDisplay) return;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isVisible={this.state.isRenderContractVisible}
|
||||
style={styles.bottomModal}
|
||||
onBackdropPress={() => {
|
||||
Keyboard.dismiss();
|
||||
this.setState({ isRenderContractVisible: false });
|
||||
}}
|
||||
>
|
||||
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
|
||||
<View style={styles.modalContent}>
|
||||
<View style={styles.modalContentCentered}>
|
||||
<Text style={styles.btcText}>
|
||||
{this.state.contractToDisplay.volume_breakdown.goes_to_buyer} {this.state.contractToDisplay.asset_code}
|
||||
</Text>
|
||||
|
||||
<View style={styles.statusGreenWrapper}>
|
||||
<Text style={styles.statusGreenText}>
|
||||
{this.state.contractToDisplay.price} {this.state.contractToDisplay.currency_code}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={styles.subheaderText}>To</Text>
|
||||
<View style={styles.modalContentCentered}>
|
||||
<View style={styles.statusGrayWrapper2}>
|
||||
<Text
|
||||
style={styles.statusGrayText2}
|
||||
onPress={() => Linking.openURL(`https://blockstream.info/address/${this.state.contractToDisplay.release_address}`)}
|
||||
>
|
||||
{this.state.contractToDisplay.release_address}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<BlueSpacing10 />
|
||||
|
||||
<Text style={styles.subheaderText}>Escrow</Text>
|
||||
<View style={styles.modalContentCentered}>
|
||||
<View style={styles.statusGrayWrapper2}>
|
||||
<Text
|
||||
style={styles.statusGrayText2}
|
||||
onPress={() => Linking.openURL(`https://blockstream.info/address/${this.state.contractToDisplay.escrow.address}`)}
|
||||
>
|
||||
{this.state.contractToDisplay.escrow.address}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<BlueSpacing20 />
|
||||
|
||||
{this.isAllowedToMarkContractAsPaid() ? (
|
||||
<View>
|
||||
<Text style={styles.subheaderText}>How to pay</Text>
|
||||
<View style={styles.modalContentCentered}>
|
||||
<View style={styles.statusGrayWrapper2}>
|
||||
<Text style={styles.statusGrayText2}>{this.state.contractToDisplay.payment_method_instruction.details}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View />
|
||||
)}
|
||||
|
||||
<BlueSpacing20 />
|
||||
|
||||
{this.isAllowedToMarkContractAsPaid() ? (
|
||||
<View>
|
||||
<BlueButton title="Mark contract as Paid" onPress={() => this._onMarkContractAsPaid()} />
|
||||
<BlueSpacing20 />
|
||||
</View>
|
||||
) : (
|
||||
<View />
|
||||
)}
|
||||
|
||||
<BlueSpacing20 />
|
||||
|
||||
{this.state.contractToDisplay.can_be_canceled && (
|
||||
<Text onPress={() => this._onCancelContract()} style={styles.cancelContractText}>
|
||||
Cancel contract
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Text onPress={() => this._onOpenContractOnWebsite()} style={styles.openChatText}>
|
||||
Open chat with counterparty
|
||||
</Text>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* If you are the buyer, DO NOT SEND PAYMENT UNTIL CONTRACT STATUS IS "in_progress".
|
||||
*/
|
||||
_onMarkContractAsPaid() {
|
||||
if (!this.state.contractToDisplay) return;
|
||||
|
||||
Alert.alert(
|
||||
'Are you sure you want to mark this contract as paid?',
|
||||
`Do this only if you sent funds to the seller via agreed payment method`,
|
||||
[
|
||||
{
|
||||
text: 'Yes',
|
||||
onPress: async () => {
|
||||
const hodlApi = this.state.hodlApi;
|
||||
try {
|
||||
await hodlApi.markContractAsPaid(this.state.contractToDisplay.id);
|
||||
this.setState({ isRenderContractVisible: false });
|
||||
await this.refetchContracts();
|
||||
} catch (Error) {
|
||||
alert(Error);
|
||||
}
|
||||
},
|
||||
style: 'default',
|
||||
},
|
||||
{
|
||||
text: 'Cancel',
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
],
|
||||
{ cancelable: true },
|
||||
);
|
||||
}
|
||||
|
||||
async _onOpenContractOnWebsite() {
|
||||
if (!this.state.contractToDisplay) return;
|
||||
const hodlApi = this.state.hodlApi;
|
||||
const sigKey = await BlueApp.getHodlHodlSignatureKey();
|
||||
if (!sigKey) {
|
||||
alert('Error: signature key not set'); // should never happen
|
||||
return;
|
||||
}
|
||||
|
||||
const autologinKey = await hodlApi.requestAutologinToken(sigKey);
|
||||
const uri = 'https://hodlhodl.com/contracts/' + this.state.contractToDisplay.id + '?sign_in_token=' + autologinKey;
|
||||
this.setState({ isRenderContractVisible: false }, () => {
|
||||
NavigationService.navigate('HodlHodlWebview', { uri });
|
||||
});
|
||||
}
|
||||
|
||||
_onCancelContract() {
|
||||
if (!this.state.contractToDisplay) return;
|
||||
|
||||
Alert.alert(
|
||||
'Are you sure you want to cancel this contract?',
|
||||
``,
|
||||
[
|
||||
{
|
||||
text: 'Yes, cancel contract',
|
||||
onPress: async () => {
|
||||
const hodlApi = this.state.hodlApi;
|
||||
try {
|
||||
await hodlApi.cancelContract(this.state.contractToDisplay.id);
|
||||
this.setState({ isRenderContractVisible: false });
|
||||
await this.refetchContracts();
|
||||
} catch (Error) {
|
||||
alert(Error);
|
||||
}
|
||||
},
|
||||
style: 'default',
|
||||
},
|
||||
{
|
||||
text: 'No',
|
||||
onPress: () => {},
|
||||
style: 'cancel',
|
||||
},
|
||||
],
|
||||
{ cancelable: true },
|
||||
);
|
||||
}
|
||||
|
||||
isAllowedToMarkContractAsPaid() {
|
||||
return this.state.contractToDisplay.status === 'in_progress' && this.state.contractToDisplay.your_role === 'buyer';
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
bottomModal: {
|
||||
justifyContent: 'flex-end',
|
||||
margin: 0,
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
padding: 22,
|
||||
borderTopLeftRadius: 16,
|
||||
borderTopRightRadius: 16,
|
||||
borderColor: 'rgba(0, 0, 0, 0.1)',
|
||||
minHeight: 425,
|
||||
},
|
||||
modalContentCentered: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
statusGreenWrapper: {
|
||||
backgroundColor: '#d2f8d5',
|
||||
borderRadius: 20,
|
||||
height: 28,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
margin: 15,
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
},
|
||||
statusGreenText: {
|
||||
fontSize: 12,
|
||||
color: '#37bfa0',
|
||||
},
|
||||
statusGrayWrapper: {
|
||||
backgroundColor: '#ebebeb',
|
||||
borderRadius: 20,
|
||||
height: 28,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
margin: 15,
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
},
|
||||
statusGrayText: {
|
||||
fontSize: 12,
|
||||
color: 'gray',
|
||||
},
|
||||
statusGrayWrapper2: {
|
||||
backgroundColor: '#f8f8f8',
|
||||
borderRadius: 5,
|
||||
height: 28,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
},
|
||||
statusGrayText2: {
|
||||
fontSize: 12,
|
||||
color: 'gray',
|
||||
},
|
||||
btcText: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
color: '#0c2550',
|
||||
},
|
||||
subheaderText: {
|
||||
fontSize: 12,
|
||||
fontWeight: 'bold',
|
||||
color: '#0c2550',
|
||||
},
|
||||
emptyComponentText: { textAlign: 'center', color: '#9AA0AA', paddingHorizontal: 16 },
|
||||
itemSeparatorComponent: { height: 0.5, width: '100%', backgroundColor: '#C8C8C8' },
|
||||
flexDirectionRow: { flexDirection: 'row' },
|
||||
flexDirectionColumn: { flexDirection: 'column' },
|
||||
volumeBreakdownText: { fontSize: 18, color: '#0c2550' },
|
||||
contractStatusText: { fontSize: 14, color: 'gray', fontWeight: 'normal' },
|
||||
cancelContractText: { color: '#d0021b', fontSize: 15, paddingTop: 20, fontWeight: '500', textAlign: 'center' },
|
||||
openChatText: { color: '#1b02d0', fontSize: 15, paddingTop: 20, fontWeight: '500', textAlign: 'center' },
|
||||
flatList: { paddingTop: 30 },
|
||||
roleText: { fontSize: 14, color: 'gray', padding: 5 },
|
||||
});
|
351
screen/wallets/hodlHodlViewOffer.js
Normal file
351
screen/wallets/hodlHodlViewOffer.js
Normal file
|
@ -0,0 +1,351 @@
|
|||
/* global alert */
|
||||
import React, { Component } from 'react';
|
||||
import { Alert, FlatList, Image, KeyboardAvoidingView, Platform, ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
import { BlueButton, BlueLoading, BlueNavigationStyle, BlueSpacing10, SafeBlueArea } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
import { HodlHodlApi } from '../../class/hodl-hodl-api';
|
||||
import { Icon } from 'react-native-elements';
|
||||
import { AppStorage } from '../../class';
|
||||
import NavigationService from '../../NavigationService';
|
||||
|
||||
const BlueApp: AppStorage = require('../../BlueApp');
|
||||
const prompt = require('../../prompt');
|
||||
|
||||
export default class HodlHodlViewOffer extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(),
|
||||
title: '',
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const offerToDisplay = props.route.params.offerToDisplay;
|
||||
|
||||
const horizontalScrollData = [];
|
||||
horizontalScrollData.push({ id: 'window', body: offerToDisplay.payment_window_minutes + ' min' });
|
||||
horizontalScrollData.push({
|
||||
id: 'min / max',
|
||||
body:
|
||||
offerToDisplay.min_amount.replace('.00', '') +
|
||||
' - ' +
|
||||
offerToDisplay.max_amount.replace('.00', '') +
|
||||
' ' +
|
||||
offerToDisplay.currency_code,
|
||||
});
|
||||
offerToDisplay.first_trade_limit &&
|
||||
horizontalScrollData.push({
|
||||
id: '1st trade',
|
||||
body: offerToDisplay.first_trade_limit.replace('.00', '') + ' ' + offerToDisplay.currency_code,
|
||||
});
|
||||
|
||||
for (const paymentInstruction of offerToDisplay.payment_method_instructions || []) {
|
||||
horizontalScrollData.push({
|
||||
id: paymentInstruction.id + paymentInstruction.version,
|
||||
header: paymentInstruction.payment_method_type,
|
||||
body: paymentInstruction.payment_method_name,
|
||||
});
|
||||
}
|
||||
|
||||
horizontalScrollData.push({ id: 'confirmations', body: offerToDisplay.confirmations });
|
||||
|
||||
this.state = {
|
||||
hodlApi: false,
|
||||
isLoading: true,
|
||||
horizontalScrollData,
|
||||
offerToDisplay,
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
console.log('wallets/hodlHodlViewOffer - componentDidMount');
|
||||
|
||||
const hodlApiKey = await BlueApp.getHodlHodlApiKey();
|
||||
const hodlApi = new HodlHodlApi(hodlApiKey);
|
||||
this.setState({ hodlApi, hodlApiKey });
|
||||
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
}
|
||||
|
||||
async _onAcceptOfferPress(offer) {
|
||||
if (!this.state.hodlApiKey) {
|
||||
alert('Please login to HodlHodl to accept offers');
|
||||
return;
|
||||
}
|
||||
const myself = await this.state.hodlApi.getMyself();
|
||||
if (!myself.encrypted_seed || myself.encrypted_seed.length < 10) {
|
||||
const buttons = [
|
||||
{
|
||||
text: 'Yes',
|
||||
onPress: async a => {
|
||||
const sigKey = await BlueApp.getHodlHodlSignatureKey();
|
||||
if (!sigKey) {
|
||||
alert('Error: signature key not set'); // should never happen
|
||||
return;
|
||||
}
|
||||
|
||||
const autologinKey = await this.state.hodlApi.requestAutologinToken(sigKey);
|
||||
const uri = 'https://hodlhodl.com/dashboards/settings?sign_in_token=' + autologinKey;
|
||||
NavigationService.navigate('HodlHodlWebview', { uri });
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Cancel',
|
||||
onPress: async a => {},
|
||||
},
|
||||
];
|
||||
Alert.alert('HodlHodl', `Looks like you didn't finish setting up account on HodlHodl, would you like to finish setup now?`, buttons, {
|
||||
cancelable: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let fiatValue;
|
||||
try {
|
||||
fiatValue = await prompt('How much ' + offer.currency_code + ' do you want to buy?', 'For example 100', true, 'numeric');
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
if (!fiatValue) return;
|
||||
|
||||
const buttons = [];
|
||||
for (const paym of offer.payment_method_instructions) {
|
||||
buttons.push({
|
||||
text: paym.payment_method_name + ' (' + paym.payment_method_type + ')',
|
||||
onPress: async a => {
|
||||
let noError = true;
|
||||
this.setState({ isLoading: true });
|
||||
let contract;
|
||||
try {
|
||||
contract = await this.state.hodlApi.acceptOffer(offer.id, offer.version, paym.id, paym.version, fiatValue);
|
||||
} catch (Error) {
|
||||
noError = false;
|
||||
alert(Error);
|
||||
}
|
||||
this.setState({ isLoading: false });
|
||||
|
||||
if (noError && contract.id) {
|
||||
await BlueApp.addHodlHodlContract(contract.id);
|
||||
NavigationService.navigate('HodlHodlMyContracts');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
Alert.alert('Choose payment method', ``, buttons, { cancelable: true });
|
||||
}
|
||||
|
||||
_renderHorizontalScrollItem(item) {
|
||||
return (
|
||||
<View style={styles.horizontalScrollWrapper}>
|
||||
<Text style={styles.horizontalScrollIemHeader}>{item.item.header || item.item.id}</Text>
|
||||
<Text style={styles.horizontalScrollItemBody}>{item.item.body}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.isLoading ? (
|
||||
<BlueLoading />
|
||||
) : (
|
||||
<SafeBlueArea>
|
||||
<ScrollView>
|
||||
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
|
||||
<View style={styles.modalContent}>
|
||||
<Text style={styles.Title}>{this.state.offerToDisplay.title}</Text>
|
||||
|
||||
{/* horizontal panel with bubbles */}
|
||||
<View style={styles.flexDirRow}>
|
||||
<View style={styles.grayTextContainerContainer}>
|
||||
<View style={styles.grayTextContainer}>
|
||||
<Icon name="place" type="material" size={16} color="#9BA0A9" containerStyle={styles.iconWithPadding} />
|
||||
<Text style={styles.locationText}>{this.state.offerToDisplay.country}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.greenTextContainerContainer}>
|
||||
<Text style={styles.priceText}>
|
||||
{this.state.offerToDisplay.price} {this.state.offerToDisplay.currency_code}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
{/* end */}
|
||||
|
||||
<Text style={styles.descriptionText}>{this.state.offerToDisplay.description}</Text>
|
||||
|
||||
<View style={styles._hr} />
|
||||
|
||||
<FlatList horizontal data={this.state.horizontalScrollData} renderItem={this._renderHorizontalScrollItem} />
|
||||
|
||||
<View style={styles._hr} />
|
||||
|
||||
{/* avatar and rating */}
|
||||
<View style={styles.avatarWrapper}>
|
||||
<View>
|
||||
<Image
|
||||
style={styles.avatarImg}
|
||||
source={
|
||||
this.state.offerToDisplay.trader.avatar_url.endsWith('.svg')
|
||||
? require('../../img/hodlhodl-default-avatar.png')
|
||||
: {
|
||||
uri: this.state.offerToDisplay.trader.avatar_url,
|
||||
}
|
||||
}
|
||||
/>
|
||||
{this.state.offerToDisplay.trader.online_status === 'online' && (
|
||||
<View style={styles.circleWhite}>
|
||||
<View style={styles.circleGreen} />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.traderWrapper}>
|
||||
<View style={styles.flexDirRow}>
|
||||
{this.state.offerToDisplay.trader.strong_hodler && (
|
||||
<Icon name="verified-user" type="material" size={14} color="#0071fc" containerStyle={styles.verifiedIcon} />
|
||||
)}
|
||||
<Text style={styles.nicknameText}>{this.state.offerToDisplay.trader.login}</Text>
|
||||
</View>
|
||||
<Text style={styles.traderRatingText}>
|
||||
{this.state.offerToDisplay.trader.trades_count > 0
|
||||
? Math.round(this.state.offerToDisplay.trader.rating * 100) +
|
||||
'%' +
|
||||
' / ' +
|
||||
this.state.offerToDisplay.trader.trades_count +
|
||||
' trades'
|
||||
: 'No rating'}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
{/* end */}
|
||||
|
||||
{this.state.offerToDisplay.side === 'sell' ? (
|
||||
<View style={styles.acceptOfferButtonWrapperWrapper}>
|
||||
<View style={styles.acceptOfferButtonWrapper}>
|
||||
<BlueSpacing10 />
|
||||
<BlueButton
|
||||
title="Accept offer"
|
||||
onPress={async () => {
|
||||
await this._onAcceptOfferPress(this.state.offerToDisplay);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View />
|
||||
)}
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</ScrollView>
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HodlHodlViewOffer.propTypes = {
|
||||
route: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
offerToDisplay: PropTypes.object,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
modalContent: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
padding: 22,
|
||||
},
|
||||
Title: {
|
||||
fontWeight: '600',
|
||||
fontSize: 24,
|
||||
color: '#0c2550',
|
||||
},
|
||||
circleWhite: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 3,
|
||||
backgroundColor: 'white',
|
||||
width: 13,
|
||||
height: 13,
|
||||
borderRadius: 6,
|
||||
},
|
||||
circleGreen: {
|
||||
position: 'absolute',
|
||||
bottom: 1,
|
||||
right: 1,
|
||||
backgroundColor: '#00d327',
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
},
|
||||
grayTextContainerContainer: {
|
||||
backgroundColor: '#EEF0F4',
|
||||
borderRadius: 20,
|
||||
height: 30,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: 15,
|
||||
marginRight: 10,
|
||||
paddingRight: 20,
|
||||
},
|
||||
greenTextContainerContainer: {
|
||||
backgroundColor: '#d2f8d5',
|
||||
borderRadius: 20,
|
||||
height: 30,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginTop: 15,
|
||||
paddingLeft: 15,
|
||||
paddingRight: 15,
|
||||
},
|
||||
grayTextContainer: {
|
||||
width: '100%',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
priceText: {
|
||||
top: 0,
|
||||
color: '#37bfa0',
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
},
|
||||
descriptionText: {
|
||||
top: 0,
|
||||
color: '#818893',
|
||||
fontSize: 14,
|
||||
paddingTop: 20,
|
||||
paddingBottom: 20,
|
||||
fontWeight: '500',
|
||||
minHeight: 150,
|
||||
lineHeight: 23,
|
||||
},
|
||||
nicknameText: {
|
||||
color: '#0c2550',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
traderRatingText: {
|
||||
color: '#9AA0AA',
|
||||
fontSize: 12,
|
||||
},
|
||||
locationText: {
|
||||
color: '#9BA0A9',
|
||||
},
|
||||
horizontalScrollIemHeader: { fontSize: 12, color: '#9AA0AA' },
|
||||
horizontalScrollItemBody: { fontSize: 14, fontWeight: 'bold', color: '#0c2550' },
|
||||
horizontalScrollWrapper: { flexDirection: 'column', paddingTop: 20, paddingBottom: 20, paddingRight: 40 },
|
||||
flexDirRow: { flexDirection: 'row' },
|
||||
iconWithPadding: { paddingLeft: 16 },
|
||||
_hr: {
|
||||
borderWidth: 0,
|
||||
borderBottomWidth: 1,
|
||||
borderColor: '#ebebeb',
|
||||
},
|
||||
avatarImg: { width: 60, height: 60, borderRadius: 60 },
|
||||
avatarWrapper: { backgroundColor: 'white', flex: 1, flexDirection: 'column', alignItems: 'center', marginTop: 32 },
|
||||
verifiedIcon: { marginTop: 3, marginRight: 5 },
|
||||
traderWrapper: { alignItems: 'center', marginTop: 8 },
|
||||
acceptOfferButtonWrapper: { width: '70%', alignItems: 'center' },
|
||||
acceptOfferButtonWrapperWrapper: { marginTop: 24, alignItems: 'center' },
|
||||
});
|
38
screen/wallets/hodlHodlWebview.js
Normal file
38
screen/wallets/hodlHodlWebview.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import React, { Component } from 'react';
|
||||
import { WebView } from 'react-native-webview';
|
||||
import { BlueNavigationStyle, SafeBlueArea } from '../../BlueComponents';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default class HodlHodlWebview extends Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
...BlueNavigationStyle(navigation, true),
|
||||
title: '',
|
||||
headerLeft: null,
|
||||
});
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const uri = props.route.params.uri;
|
||||
|
||||
this.state = {
|
||||
uri,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SafeBlueArea>
|
||||
<WebView source={{ uri: this.state.uri }} incognito />
|
||||
</SafeBlueArea>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
HodlHodlWebview.propTypes = {
|
||||
route: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
uri: PropTypes.string.isRequired,
|
||||
}),
|
||||
}),
|
||||
};
|
|
@ -436,7 +436,7 @@ export default class WalletsList extends Component {
|
|||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.props.navigation.navigate('HodlHodl', { fromWallet: this.state.wallet });
|
||||
this.props.navigation.navigate('HodlHodlRoot', { params: { wallet: this.state.wallet }, screen: 'HodlHodl' });
|
||||
}}
|
||||
style={styles.ltRoot}
|
||||
>
|
||||
|
|
|
@ -5,6 +5,20 @@ import { HodlHodlApi } from '../../class/hodl-hodl-api';
|
|||
const bitcoin = require('bitcoinjs-lib');
|
||||
const assert = require('assert');
|
||||
|
||||
it.skip('can verify escrow address', () => {
|
||||
const encryptedSeed =
|
||||
'ES1:b2dc8bd89782f70ef11ff1d1c6bf6adde0bea78fb959391de48f49acbf7f9766ca128b89c1a9a013d158b6c4dabee77997f8a15764d1b083f213b1d6aa9fb3a14a1edb406930a25423a1df3be72306f120b08972cea669dba1284bd8:bf5af8737529b419cc20935a1c05c742:pbkdf2:10000';
|
||||
const encryptPassword = 'Qwert12345';
|
||||
const address = '34n3rBtPA16BQYWycphnhK7C9DoucWb527';
|
||||
const index = 10298;
|
||||
const witnessScript =
|
||||
'522103dc0edfea797214be15a69148bfb1dffa1c8295c05300b7632143a77d918b4a0821031fec42b60942633616aff7e245796b5caae6bf59ef5ba688b0a59f33f08b2896210351fd6e52d38a37b9834909e3f8345c471346e1f5990ec00dafcc53e238d3c7c553ae';
|
||||
|
||||
const Hodl = new HodlHodlApi();
|
||||
assert.ok(Hodl.verifyEscrowAddress(encryptedSeed, encryptPassword, index, address, witnessScript));
|
||||
assert.ok(!Hodl.verifyEscrowAddress(encryptedSeed, encryptPassword, index, '3QDf45WU88t2kEBJTHcTPvtrXZx88SkmKC', witnessScript));
|
||||
});
|
||||
|
||||
it('can create escrow address', () => {
|
||||
const keyPairServer = bitcoin.ECPair.fromPrivateKey(
|
||||
Buffer.from('9a8cfd0e33a37c90a46d358c84ca3d8dd089ed35409a6eb1973148c0df492288', 'hex'),
|
||||
|
@ -109,12 +123,58 @@ describe('HodlHodl API', function () {
|
|||
assert.ok(offers[0].asset_code === 'BTC');
|
||||
assert.ok(offers[0].country_code);
|
||||
assert.ok(offers[0].side === HodlHodlApi.FILTERS_SIDE_VALUE_SELL);
|
||||
assert.ok(offers[0].title || offers[0].description || offers[1].title || offers[1].description, JSON.stringify(offers[0], null, 2));
|
||||
assert.ok(typeof offers[0].title !== 'undefined', JSON.stringify(offers[0], null, 2));
|
||||
assert.ok(typeof offers[0].description !== 'undefined', JSON.stringify(offers[0], null, 2));
|
||||
assert.ok(offers[0].price);
|
||||
assert.ok(offers[0].payment_method_instructions);
|
||||
assert.ok(offers[0].trader);
|
||||
});
|
||||
|
||||
it('can get offer', async () => {
|
||||
if (!process.env.HODLHODL_OFFER_ID) return;
|
||||
const Hodl = new HodlHodlApi();
|
||||
const offer = await Hodl.getOffer(process.env.HODLHODL_OFFER_ID);
|
||||
assert.ok(offer.id);
|
||||
assert.ok(offer.version);
|
||||
});
|
||||
|
||||
it('can accept offer', async () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
|
||||
if (!process.env.HODLHODL_OFFER_ID) return;
|
||||
const Hodl = new HodlHodlApi();
|
||||
const offer = await Hodl.getOffer(process.env.HODLHODL_OFFER_ID);
|
||||
assert.strictEqual(offer.side, 'sell');
|
||||
const paymentMethodInstructionId = offer.payment_method_instructions[0].id;
|
||||
const paymentMethodInstructionVersion = offer.payment_method_instructions[0].version;
|
||||
const fiatValue = 100;
|
||||
const contract = await Hodl.acceptOffer(
|
||||
offer.id,
|
||||
offer.version,
|
||||
paymentMethodInstructionId,
|
||||
paymentMethodInstructionVersion,
|
||||
fiatValue,
|
||||
);
|
||||
console.warn({ contract });
|
||||
});
|
||||
|
||||
it('can get contract', async () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
|
||||
if (!process.env.HODLHODL_CONTRACT_ID) return;
|
||||
const Hodl = new HodlHodlApi();
|
||||
const contract = await Hodl.getContract(process.env.HODLHODL_CONTRACT_ID);
|
||||
assert.ok(contract.your_role);
|
||||
assert.ok(contract.volume);
|
||||
assert.ok(contract.escrow);
|
||||
});
|
||||
|
||||
it('can mark contract as confirmed', async () => {
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 200 * 1000;
|
||||
if (!process.env.HODLHODL_CONTRACT_ID) return;
|
||||
const Hodl = new HodlHodlApi();
|
||||
const result = await Hodl.markContractAsConfirmed(process.env.HODLHODL_CONTRACT_ID);
|
||||
console.warn(result);
|
||||
});
|
||||
|
||||
it('can get payment methods', async () => {
|
||||
const Hodl = new HodlHodlApi();
|
||||
const methods = await Hodl.getPaymentMethods(HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL);
|
||||
|
@ -132,4 +192,20 @@ describe('HodlHodl API', function () {
|
|||
assert.ok(currencies[0].name);
|
||||
assert.ok(currencies[0].type);
|
||||
});
|
||||
|
||||
it('cat get myself', async () => {
|
||||
const Hodl = new HodlHodlApi();
|
||||
const myself = await Hodl.getMyself();
|
||||
assert.ok(myself.encrypted_seed);
|
||||
});
|
||||
|
||||
it('can create signature for autologin', async () => {
|
||||
const Hodl = new HodlHodlApi('');
|
||||
const sig = Hodl.createSignature(
|
||||
'iqZC7uUmx4sVeIwFQN2YqGT5SyrXNLhxVX7QMGUeJK1CDdy87OcrOt3QvPE5LFC56Lgu7WLlg12U55Vy',
|
||||
'cce14197a08ebab7cfbb41cfce9fe91e0f31d572d3f48571ca3c30bfd516f769',
|
||||
1589980224,
|
||||
);
|
||||
assert.strictEqual(sig, '1d2a51ca2c54ff9107a3460b22f01bc877e527a9a719d81b32038741332159fc');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue