Merge branch 'release-8.0' into 8.0-to-8.1-merge

This commit is contained in:
André Sá 2022-07-26 11:25:04 +01:00
commit e7c2456ff7
25 changed files with 149 additions and 75 deletions

View file

@ -144,7 +144,7 @@ function run () {
_.filter(c => c.type !== 'erc-20'),
_.map(c => {
const checked = isInstalledSoftware(c) && isInstalledVolume(c)
const name = c.code === 'ethereum' ? 'Ethereum' : c.display
const name = c.code === 'ethereum' ? 'Ethereum and/or USDT' : c.display
return {
name,
value: c.code,

View file

@ -484,7 +484,7 @@ function getCustomersList (phone = null, name = null, address = null, id = null)
const sql = `SELECT id, authorized_override, days_suspended, is_suspended, front_camera_path, front_camera_override,
phone, sms_override, id_card_data, id_card_data_override, id_card_data_expiration,
id_card_photo_path, id_card_photo_override, us_ssn, us_ssn_override, sanctions, sanctions_at,
sanctions_override, total_txs, total_spent, LEAST(created, last_transaction) AS last_active, fiat AS last_tx_fiat,
sanctions_override, total_txs, total_spent, GREATEST(created, last_transaction, last_data_provided) AS last_active, fiat AS last_tx_fiat,
fiat_code AS last_tx_fiat_code, tx_class AS last_tx_class, custom_fields, notes, is_test_customer
FROM (
SELECT c.id, c.authorized_override,
@ -493,6 +493,7 @@ function getCustomersList (phone = null, name = null, address = null, id = null)
c.front_camera_path, c.front_camera_override,
c.phone, c.sms_override, c.id_card_data, c.id_card_data_override, c.id_card_data_expiration,
c.id_card_photo_path, c.id_card_photo_override, c.us_ssn, c.us_ssn_override, c.sanctions,
GREATEST(c.phone_at, c.id_card_data_at, c.front_camera_at, c.id_card_photo_at, c.us_ssn_at) AS last_data_provided,
c.sanctions_at, c.sanctions_override, c.is_test_customer, c.created, t.tx_class, t.fiat, t.fiat_code, t.created as last_transaction, cn.notes,
row_number() OVER (partition by c.id order by t.created desc) AS rn,
sum(CASE WHEN t.id IS NOT NULL THEN 1 ELSE 0 END) OVER (partition by c.id) AS total_txs,

View file

@ -3,8 +3,8 @@ const _ = require('lodash/fp')
const { ALL } = require('../../plugins/common/ccxt')
const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR } = COINS
const { bitpay, coinbase, itbit, bitstamp, kraken, binanceus, cex, ftx, binance } = ALL
const { BTC, BCH, DASH, ETH, LTC, USDT, ZEC, XMR } = COINS
const { bitpay, coinbase, itbit, bitstamp, kraken, binanceus, cex, ftx } = ALL
const TICKER = 'ticker'
const WALLET = 'wallet'
@ -29,8 +29,8 @@ const ALL_ACCOUNTS = [
{ code: 'mock-ticker', display: 'Mock (Caution!)', class: TICKER, cryptos: ALL_CRYPTOS, dev: true },
{ code: 'bitcoind', display: 'bitcoind', class: WALLET, cryptos: [BTC] },
{ code: 'no-layer2', display: 'No Layer 2', class: LAYER_2, cryptos: ALL_CRYPTOS },
{ code: 'infura', display: 'Infura', class: WALLET, cryptos: [ETH] },
{ code: 'geth', display: 'geth', class: WALLET, cryptos: [ETH] },
{ code: 'infura', display: 'Infura', class: WALLET, cryptos: [ETH, USDT] },
{ code: 'geth', display: 'geth', class: WALLET, cryptos: [ETH, USDT] },
{ code: 'zcashd', display: 'zcashd', class: WALLET, cryptos: [ZEC] },
{ code: 'litecoind', display: 'litecoind', class: WALLET, cryptos: [LTC] },
{ code: 'dashd', display: 'dashd', class: WALLET, cryptos: [DASH] },

View file

@ -218,6 +218,7 @@ function plugins (settings, deviceId) {
return {
cryptoCode,
display: cryptoRec.display,
isCashInOnly: Boolean(cryptoRec.isCashinOnly),
minimumTx: BN.max(minimumTx, cashInFee),
cashInFee,
cashInCommission,

View file

@ -11,7 +11,7 @@ const bitpay = require('../ticker/bitpay')
const binance = require('../exchange/binance')
const logger = require('../../logger')
const { BTC, BCH, DASH, ETH, LTC, ZEC } = COINS
const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT } = COINS
const ALL = {
cex: cex,
@ -22,7 +22,7 @@ const ALL = {
itbit: itbit,
bitpay: bitpay,
coinbase: {
CRYPTO: [BTC, ETH, LTC, DASH, ZEC, BCH],
CRYPTO: [BTC, ETH, LTC, DASH, ZEC, BCH, USDT],
FIAT: 'ALL_CURRENCIES'
},
binance: binance

View file

@ -4,8 +4,8 @@ const _ = require('lodash/fp')
const { ORDER_TYPES } = require('./consts')
const ORDER_TYPE = ORDER_TYPES.MARKET
const { BTC, BCH, DASH, ETH, LTC, ZEC } = COINS
const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH]
const { BTC, BCH, DASH, ETH, LTC, ZEC, USDT } = COINS
const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, USDT]
const FIAT = ['USD']
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey']

View file

@ -4,8 +4,8 @@ const _ = require('lodash/fp')
const { ORDER_TYPES } = require('./consts')
const ORDER_TYPE = ORDER_TYPES.MARKET
const { BTC, ETH, LTC, BCH } = COINS
const CRYPTO = [BTC, ETH, LTC, BCH]
const { BTC, ETH, LTC, BCH, USDT } = COINS
const CRYPTO = [BTC, ETH, LTC, BCH, USDT]
const FIAT = ['USD', 'EUR']
const AMOUNT_PRECISION = 8
const REQUIRED_CONFIG_FIELDS = ['key', 'secret', 'clientId']

View file

@ -4,8 +4,8 @@ const _ = require('lodash/fp')
const { ORDER_TYPES } = require('./consts')
const ORDER_TYPE = ORDER_TYPES.MARKET
const { BTC, BCH, DASH, ETH, LTC } = COINS
const CRYPTO = [BTC, ETH, LTC, DASH, BCH]
const { BTC, BCH, DASH, ETH, LTC, USDT } = COINS
const CRYPTO = [BTC, ETH, LTC, DASH, BCH, USDT]
const FIAT = ['USD', 'EUR']
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey']

View file

@ -4,8 +4,8 @@ const _ = require('lodash/fp')
const { ORDER_TYPES } = require('./consts')
const ORDER_TYPE = ORDER_TYPES.MARKET
const { BTC, BCH, ETH, LTC } = COINS
const CRYPTO = [BTC, ETH, LTC, BCH]
const { BTC, BCH, ETH, LTC, USDT } = COINS
const CRYPTO = [BTC, ETH, LTC, BCH, USDT]
const FIAT = ['USD']
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey']

View file

@ -4,8 +4,8 @@ const { ORDER_TYPES } = require('./consts')
const { COINS } = require('@lamassu/coins')
const ORDER_TYPE = ORDER_TYPES.LIMIT
const { BTC, ETH } = COINS
const CRYPTO = [BTC, ETH]
const { BTC, ETH, USDT } = COINS
const CRYPTO = [BTC, ETH, USDT]
const FIAT = ['USD']
const AMOUNT_PRECISION = 4
const REQUIRED_CONFIG_FIELDS = ['clientKey', 'clientSecret', 'userId', 'walletId']

View file

@ -4,8 +4,8 @@ const { ORDER_TYPES } = require('./consts')
const { COINS } = require('@lamassu/coins')
const ORDER_TYPE = ORDER_TYPES.MARKET
const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR } = COINS
const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, XMR]
const { BTC, BCH, DASH, ETH, LTC, ZEC, XMR, USDT } = COINS
const CRYPTO = [BTC, ETH, LTC, DASH, ZEC, BCH, XMR, USDT]
const FIAT = ['USD', 'EUR']
const AMOUNT_PRECISION = 6
const REQUIRED_CONFIG_FIELDS = ['apiKey', 'privateKey']

View file

@ -6,13 +6,15 @@ const web3 = new Web3()
const hdkey = require('ethereumjs-wallet/hdkey')
const { FeeMarketEIP1559Transaction } = require('@ethereumjs/tx')
const { default: Common, Chain, Hardfork } = require('@ethereumjs/common')
const Tx = require('ethereumjs-tx')
const { default: PQueue } = require('p-queue')
const util = require('ethereumjs-util')
const coins = require('@lamassu/coins')
const { default: PQueue } = require('p-queue')
const pify = require('pify')
const _pify = require('pify')
const BN = require('../../../bn')
const ABI = require('../../tokens')
const logger = require('../../../logger')
exports.SUPPORTED_MODULES = ['wallet']
@ -40,6 +42,19 @@ const SWEEP_QUEUE = new PQueue({
interval: 250,
})
const infuraCalls = {}
const pify = _function => {
if (_.isString(_function.call)) logInfuraCall(_function.call)
return _pify(_function)
}
const logInfuraCall = call => {
if (!_.includes('infura', web3.currentProvider.host)) return
_.isNil(infuraCalls[call]) ? infuraCalls[call] = 1 : infuraCalls[call]++
logger.info(`Calling web3 method ${call} via Infura. Current count for this session: ${JSON.stringify(infuraCalls)}`)
}
function connect (url) {
web3.setProvider(new web3.providers.HttpProvider(url))
}
@ -56,7 +71,9 @@ function isStrictAddress (cryptoCode, toAddress, settings, operatorId) {
function sendCoins (account, tx, settings, operatorId, feeMultiplier) {
const { toAddress, cryptoAtoms, cryptoCode } = tx
return generateTx(toAddress, defaultWallet(account), cryptoAtoms, false, cryptoCode)
const isErc20Token = coins.utils.isErc20Token(cryptoCode)
return (isErc20Token ? generateErc20Tx : generateTx)(toAddress, defaultWallet(account), cryptoAtoms, false, cryptoCode)
.then(pify(web3.eth.sendSignedTransaction))
.then(txid => {
return pify(web3.eth.getTransaction)(txid)
@ -84,14 +101,16 @@ function balance (account, cryptoCode, settings, operatorId) {
const pendingBalance = (address, cryptoCode) => {
const promises = [_balance(true, address, cryptoCode), _balance(false, address, cryptoCode)]
return Promise.all(promises).then(([pending, confirmed]) => pending.minus(confirmed))
return Promise.all(promises).then(([pending, confirmed]) => BN(pending).minus(confirmed))
}
const confirmedBalance = (address, cryptoCode) => _balance(false, address, cryptoCode)
function _balance (includePending, address, cryptoCode) {
if (coins.utils.isErc20Token(cryptoCode)) {
const contract = web3.eth.contract(ABI.ERC20).at(coins.utils.getErc20Token(cryptoCode).contractAddress)
return contract.balanceOf(address.toLowerCase())
const contract = new web3.eth.Contract(ABI.ERC20, coins.utils.getErc20Token(cryptoCode).contractAddress)
return contract.methods.balanceOf(address.toLowerCase()).call((_, balance) => {
return contract.methods.decimals().call((_, decimals) => BN(balance).div(10 ** decimals))
})
}
const block = includePending ? 'pending' : undefined
return pify(web3.eth.getBalance)(address.toLowerCase(), block)
@ -99,17 +118,66 @@ function _balance (includePending, address, cryptoCode) {
.then(balance => balance ? BN(balance) : BN(0))
}
function generateErc20Tx (_toAddress, wallet, amount, includesFee, cryptoCode) {
const fromAddress = '0x' + wallet.getAddress().toString('hex')
const toAddress = coins.utils.getErc20Token(cryptoCode).contractAddress
const contract = new web3.eth.Contract(ABI.ERC20, toAddress)
const contractData = contract.methods.transfer(_toAddress.toLowerCase(), hex(amount))
const txTemplate = {
from: fromAddress,
to: toAddress,
value: hex(BN(0)),
data: contractData.encodeABI()
}
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
const promises = [
pify(contractData.estimateGas)(txTemplate),
pify(web3.eth.getTransactionCount)(fromAddress),
pify(web3.eth.getBlock)('pending')
]
return Promise.all(promises)
.then(([gas, txCount, { baseFeePerGas }]) => [
BN(gas),
_.max([0, txCount, lastUsedNonces[fromAddress] + 1]),
BN(baseFeePerGas)
])
.then(([gas, txCount, baseFeePerGas]) => {
lastUsedNonces[fromAddress] = txCount
const maxPriorityFeePerGas = new BN(web3.utils.toWei('2.5', 'gwei')) // web3 default value
const maxFeePerGas = new BN(2).times(baseFeePerGas).plus(maxPriorityFeePerGas)
const rawTx = {
chainId: 1,
nonce: txCount,
maxPriorityFeePerGas: web3.utils.toHex(maxPriorityFeePerGas),
maxFeePerGas: web3.utils.toHex(maxFeePerGas),
gasLimit: hex(gas),
to: toAddress,
from: fromAddress,
value: hex(BN(0)),
data: contractData.encodeABI()
}
const tx = FeeMarketEIP1559Transaction.fromTxData(rawTx, { common })
const privateKey = wallet.getPrivateKey()
const signedTx = tx.sign(privateKey)
return '0x' + signedTx.serialize().toString('hex')
})
}
function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) {
const fromAddress = '0x' + wallet.getAddress().toString('hex')
const isErc20Token = coins.utils.isErc20Token(cryptoCode)
const toAddress = isErc20Token ? coins.utils.getErc20Token(cryptoCode).contractAddress : _toAddress.toLowerCase()
let contract, contractData
if (isErc20Token) {
contract = web3.eth.contract(ABI.ERC20).at(toAddress)
contractData = isErc20Token && contract.transfer.getData(_toAddress.toLowerCase(), hex(toSend))
}
const toAddress = _toAddress.toLowerCase()
const txTemplate = {
from: fromAddress,
@ -117,9 +185,7 @@ function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) {
value: amount.toString()
}
if (isErc20Token) txTemplate.data = contractData
const common = new Common({ chain: Chain.Ropsten, hardfork: Hardfork.London })
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London })
const promises = [
pify(web3.eth.estimateGas)(txTemplate),
@ -129,10 +195,11 @@ function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) {
]
return Promise.all(promises)
.then(([gas, gasPrice, txCount]) => [
.then(([gas, gasPrice, txCount, { baseFeePerGas }]) => [
BN(gas),
BN(gasPrice),
_.max([0, txCount, lastUsedNonces[fromAddress] + 1])
_.max([0, txCount, lastUsedNonces[fromAddress] + 1]),
BN(baseFeePerGas)
])
.then(([gas, gasPrice, txCount, baseFeePerGas]) => {
lastUsedNonces[fromAddress] = txCount
@ -141,7 +208,7 @@ function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) {
? amount.minus(gasPrice.times(gas))
: amount
const maxPriorityFeePerGas = new BN(2.5) // web3 default value
const maxPriorityFeePerGas = new BN(web3.utils.toWei('2.5', 'gwei')) // web3 default value
const maxFeePerGas = new BN(2).times(baseFeePerGas).plus(maxPriorityFeePerGas)
const rawTx = {
@ -152,11 +219,7 @@ function generateTx (_toAddress, wallet, amount, includesFee, cryptoCode) {
gasLimit: hex(gas),
to: toAddress,
from: fromAddress,
value: isErc20Token ? hex(BN(0)) : hex(toSend)
}
if (isErc20Token) {
rawTx.data = contractData
value: hex(toSend)
}
const tx = FeeMarketEIP1559Transaction.fromTxData(rawTx, { common })

View file

@ -1,3 +1,4 @@
const _ = require('lodash/fp')
const mem = require('mem')
const configManager = require('./new-config-manager')
const logger = require('./logger')
@ -9,6 +10,8 @@ const bitpay = require('./plugins/ticker/bitpay')
const FETCH_INTERVAL = 58000
const PEGGED_FIAT_CURRENCIES = { NAD: 'ZAR' }
function _getRates (settings, fiatCode, cryptoCode) {
return Promise.resolve()
.then(() => {
@ -33,9 +36,12 @@ function _getRates (settings, fiatCode, cryptoCode) {
}
function buildTicker (fiatCode, cryptoCode, tickerName) {
if (tickerName === 'bitpay') return bitpay.ticker(fiatCode, cryptoCode)
if (tickerName === 'mock-ticker') return mockTicker.ticker(fiatCode, cryptoCode)
return ccxt.ticker(fiatCode, cryptoCode, tickerName)
const fiatPeggedEquivalent = _.includes(fiatCode, _.keys(PEGGED_FIAT_CURRENCIES))
? PEGGED_FIAT_CURRENCIES[fiatCode]
: fiatCode
if (tickerName === 'bitpay') return bitpay.ticker(fiatPeggedEquivalent, cryptoCode)
if (tickerName === 'mock-ticker') return mockTicker.ticker(fiatPeggedEquivalent, cryptoCode)
return ccxt.ticker(fiatPeggedEquivalent, cryptoCode, tickerName)
}
const getRates = mem(_getRates, {

View file

@ -34,6 +34,7 @@ const BlackListModal = ({
DASH: 'XqQ7gU8eM76rEfey726cJpT2RGKyJyBrcn',
ZEC: 't1KGyyv24eL354C9gjveBGEe8Xz9UoPKvHR',
BCH: 'qrd6za97wm03lfyg82w0c9vqgc727rhemg5yd9k3dm',
USDT: '0x5754284f345afc66a98fbb0a0afe71e0f007b949',
XMR:
'888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H'
}

View file

@ -195,7 +195,7 @@ const getAdvancedWalletElementsOverrides = (
const has0Conf = R.complement(
/* NOTE: List of coins without 0conf settings. */
R.pipe(R.prop('id'), R.flip(R.includes)(['ETH']))
R.pipe(R.prop('id'), R.flip(R.includes)(['ETH', 'USDT']))
)
const getElements = (cryptoCurrencies, accounts, onChange, wizard = false) => {

24
package-lock.json generated
View file

@ -1431,7 +1431,7 @@
"resolved": "https://registry.npmjs.org/@celo/utils/-/utils-0.1.17.tgz",
"integrity": "sha512-XKIoGAij/FHWCzgIlZxkQR6PVWEGeE1V6rjOwDrM7WwGx9HJ3q3WBBUTibGTCz5gypMeurBbYGym/AZD/Nb78g==",
"requires": {
"@umpirsky/country-list": "https://github.com/umpirsky/country-list.git#05fda51",
"@umpirsky/country-list": "git://github.com/umpirsky/country-list.git#05fda51",
"bigi": "^1.1.0",
"bignumber.js": "^9.0.0",
"bip32": "2.0.5",
@ -1455,6 +1455,10 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
"integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
},
"@umpirsky/country-list": {
"version": "git://github.com/umpirsky/country-list.git#05fda51cd97b3294e8175ffed06104c44b3c71d7",
"from": "git://github.com/umpirsky/country-list.git#05fda51"
},
"bip39": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.2.tgz",
@ -4362,10 +4366,6 @@
"resolved": "https://registry.npmjs.org/@types/zen-observable/-/zen-observable-0.8.2.tgz",
"integrity": "sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg=="
},
"@umpirsky/country-list": {
"version": "https://github.com/umpirsky/country-list.git#05fda51cd97b3294e8175ffed06104c44b3c71d7",
"from": "https://github.com/umpirsky/country-list.git#05fda51"
},
"@ungap/global-this": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@ungap/global-this/-/global-this-0.4.4.tgz",
@ -5457,7 +5457,14 @@
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-2.1.1.tgz",
"integrity": "sha512-t9u0dU0rJN4ML+uxgN6VM2Z4H5jWIYm0w8LsZLzMJaQsgL3IJNbxHgmbWDvJAwspyHpDFuzUaUFh4c05UB4+6g==",
"requires": {
"pvutils": "^1.0.17"
"pvutils": "^1.1.3"
},
"dependencies": {
"pvutils": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz",
"integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="
}
}
},
"assert": {
@ -17950,11 +17957,6 @@
}
}
},
"pvutils": {
"version": "1.0.17",
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.0.17.tgz",
"integrity": "sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ=="
},
"q": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz",

View file

@ -1,13 +1,13 @@
{
"files": {
"main.js": "/static/js/main.25dad505.chunk.js",
"main.js.map": "/static/js/main.25dad505.chunk.js.map",
"main.js": "/static/js/main.82144b16.chunk.js",
"main.js.map": "/static/js/main.82144b16.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.5b925903.js",
"runtime-main.js.map": "/static/js/runtime-main.5b925903.js.map",
"static/js/2.539ca5ff.chunk.js": "/static/js/2.539ca5ff.chunk.js",
"static/js/2.539ca5ff.chunk.js.map": "/static/js/2.539ca5ff.chunk.js.map",
"static/js/2.b9be2e01.chunk.js": "/static/js/2.b9be2e01.chunk.js",
"static/js/2.b9be2e01.chunk.js.map": "/static/js/2.b9be2e01.chunk.js.map",
"index.html": "/index.html",
"static/js/2.539ca5ff.chunk.js.LICENSE.txt": "/static/js/2.539ca5ff.chunk.js.LICENSE.txt",
"static/js/2.b9be2e01.chunk.js.LICENSE.txt": "/static/js/2.b9be2e01.chunk.js.LICENSE.txt",
"static/media/3-cassettes-open-1-left.d6d9aa73.svg": "/static/media/3-cassettes-open-1-left.d6d9aa73.svg",
"static/media/3-cassettes-open-2-left.a9ee8d4c.svg": "/static/media/3-cassettes-open-2-left.a9ee8d4c.svg",
"static/media/3-cassettes-open-3-left.08fed660.svg": "/static/media/3-cassettes-open-3-left.08fed660.svg",
@ -153,7 +153,7 @@
},
"entrypoints": [
"static/js/runtime-main.5b925903.js",
"static/js/2.539ca5ff.chunk.js",
"static/js/main.25dad505.chunk.js"
"static/js/2.b9be2e01.chunk.js",
"static/js/main.82144b16.chunk.js"
]
}

View file

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="robots" content="noindex"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Lamassu Admin</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root" class="root"></div><script>!function(e){function r(r){for(var n,a,l=r[0],i=r[1],f=r[2],c=0,s=[];c<l.length;c++)a=l[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var i=t[l];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/";var l=this["webpackJsonplamassu-admin"]=this["webpackJsonplamassu-admin"]||[],i=l.push.bind(l);l.push=r,l=l.slice();for(var f=0;f<l.length;f++)r(l[f]);var p=i;t()}([])</script><script src="/static/js/2.539ca5ff.chunk.js"></script><script src="/static/js/main.25dad505.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="robots" content="noindex"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Lamassu Admin</title></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root" class="root"></div><script>!function(e){function r(r){for(var n,a,l=r[0],i=r[1],f=r[2],c=0,s=[];c<l.length;c++)a=l[c],Object.prototype.hasOwnProperty.call(o,a)&&o[a]&&s.push(o[a][0]),o[a]=0;for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,f||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var i=t[l];0!==o[i]&&(n=!1)}n&&(u.splice(r--,1),e=a(a.s=t[0]))}return e}var n={},o={1:0},u=[];function a(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.m=e,a.c=n,a.d=function(e,r,t){a.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,r){if(1&r&&(e=a(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)a.d(t,n,function(r){return e[r]}.bind(null,n));return t},a.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(r,"a",r),r},a.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},a.p="/";var l=this["webpackJsonplamassu-admin"]=this["webpackJsonplamassu-admin"]||[],i=l.push.bind(l);l.push=r,l=l.slice();for(var f=0;f<l.length;f++)r(l[f]);var p=i;t()}([])</script><script src="/static/js/2.b9be2e01.chunk.js"></script><script src="/static/js/main.82144b16.chunk.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long