From c24fbf5f5c1f0966da3fa9e7f460d401b3ae3db8 Mon Sep 17 00:00:00 2001 From: Tim Moreton Date: Thu, 5 Dec 2019 10:45:59 -0800 Subject: [PATCH] Add checkzero,blockscout,mulit-address support to faucet. Fix broken envType checks --- packages/celotool/src/cmds/account/faucet.ts | 91 ++++++++++++++++---- packages/celotool/src/lib/artifacts.ts | 4 +- packages/celotool/src/lib/env-utils.ts | 30 ++----- packages/celotool/src/lib/helm_deploy.ts | 4 +- 4 files changed, 82 insertions(+), 47 deletions(-) diff --git a/packages/celotool/src/cmds/account/faucet.ts b/packages/celotool/src/cmds/account/faucet.ts index 725ba589ce7..f5718e4f1f5 100644 --- a/packages/celotool/src/cmds/account/faucet.ts +++ b/packages/celotool/src/cmds/account/faucet.ts @@ -1,9 +1,12 @@ /* tslint:disable no-console */ import { newKit } from '@celo/contractkit' +import { sleep } from '@celo/utils/lib/async' import { switchToClusterFromEnv } from 'src/lib/cluster' import { convertToContractDecimals } from 'src/lib/contract-utils' +import { getBlockscoutUrl } from 'src/lib/endpoints' +import { envVar, fetchEnv } from 'src/lib/env-utils' import { portForwardAnd } from 'src/lib/port_forward' -import { validateAccountAddress } from 'src/lib/utils' +import { execCmd, validateAccountAddress } from 'src/lib/utils' import yargs from 'yargs' import { AccountArgv } from '../account' @@ -15,19 +18,26 @@ interface FaucetArgv extends AccountArgv { account: string gold: number dollar: number + checkzero: boolean + blockscout: boolean } export const builder = (argv: yargs.Argv) => { return argv .option('account', { type: 'string', - description: 'Account to faucet', - demand: 'Please specify account to faucet', - coerce: (address) => { - if (!validateAccountAddress(address)) { - throw Error(`Receiver Address is invalid: "${address}"`) - } - return address + description: 'Account(s) to faucet', + demand: 'Please specify comma-separated accounts to faucet', + coerce: (addresses) => { + return addresses.split(',').map((a: string) => { + if (!a.startsWith('0x')) { + a = `0x${a}` + } + if (!validateAccountAddress(a)) { + throw Error(`Receiver Address is invalid: "${a}"`) + } + return a + }) }, }) .option('dollar', { @@ -40,12 +50,22 @@ export const builder = (argv: yargs.Argv) => { description: 'Amount of gold to faucet', demand: 'Please specify gold to faucet', }) + .option('checkzero', { + type: 'boolean', + description: 'Check that the gold balance is zero before fauceting', + default: false, + }) + .option('blockscout', { + type: 'boolean', + description: 'Open in blockscout afterwards', + default: false, + }) } export const handler = async (argv: FaucetArgv) => { await switchToClusterFromEnv() - const address = argv.account + const addresses = argv.account const cb = async () => { const kit = newKit('http://localhost:8545') @@ -58,18 +78,51 @@ export const handler = async (argv: FaucetArgv) => { kit.contracts.getStableToken(), kit.contracts.getReserve(), ]) - const goldAmount = await convertToContractDecimals(argv.gold, goldToken) - const stableTokenAmount = await convertToContractDecimals(argv.dollar, stableToken) - console.log(`Fauceting ${argv.gold} Gold and ${argv.dollar} StableToken to ${address}`) - if (!goldAmount.isZero()) { - if (await reserve.isSpender(account)) { - await reserve.transferGold(address, goldAmount.toFixed()).sendAndWaitForReceipt() - } else { - await goldToken.transfer(address, goldAmount.toFixed()).sendAndWaitForReceipt() + + if (argv.checkzero) { + for (const address of addresses) { + // Check this address hasn't already been fauceted and has zero gold + if ( + (argv.gold !== 0 && !(await goldToken.balanceOf(address)).isZero()) || + (argv.dollar !== 0 && !(await stableToken.balanceOf(address)).isZero()) + ) { + console.error( + `Unable to faucet ${address} on ${ + argv.celoEnv + }: --checkzero specified, but balance is non-zero` + ) + process.exit(1) + } + } + } + + for (const address of addresses) { + const goldAmount = await convertToContractDecimals(argv.gold, goldToken) + const stableTokenAmount = await convertToContractDecimals(argv.dollar, stableToken) + + console.log( + `Fauceting ${goldAmount.toFixed()} Gold and ${stableTokenAmount.toFixed()} StableToken to ${address}` + ) + + if (!goldAmount.isZero()) { + if (await reserve.isSpender(account)) { + // await reserve.transferGold(address, goldAmount.toFixed()).sendAndWaitForReceipt() + } else { + // await goldToken.transfer(address, goldAmount.toFixed()).sendAndWaitForReceipt() + } + } + if (!stableTokenAmount.isZero()) { + // await stableToken.transfer(address, stableTokenAmount.toFixed()).sendAndWaitForReceipt() } } - if (!stableTokenAmount.isZero()) { - await stableToken.transfer(address, stableTokenAmount.toFixed()).sendAndWaitForReceipt() + + if (argv.blockscout) { + // Open addresses in blockscout + await sleep(1 + parseInt(fetchEnv(envVar.BLOCK_TIME), 10) * 1000) + const blockscoutUrl = getBlockscoutUrl(argv) + for (const address of addresses) { + await execCmd(`open ${blockscoutUrl}/address/${address}`) + } } } diff --git a/packages/celotool/src/lib/artifacts.ts b/packages/celotool/src/lib/artifacts.ts index 6c9f5aaf91c..e1c0b7e5a88 100644 --- a/packages/celotool/src/lib/artifacts.ts +++ b/packages/celotool/src/lib/artifacts.ts @@ -17,7 +17,7 @@ export const CONTRACTS_TO_COPY = [ export async function downloadArtifacts(celoEnv: string) { let baseCmd = `yarn --cwd ../protocol run download-artifacts -n ${celoEnv}` console.log(`Downloading artifacts for ${celoEnv}`) - if (isProduction(celoEnv)) { + if (isProduction()) { baseCmd += ` -b contract_artifacts_production` } try { @@ -35,7 +35,7 @@ export async function uploadArtifacts(celoEnv: string, checkOrPromptIfStagingOrP } let baseCmd = `yarn --cwd ../protocol run upload-artifacts -n ${celoEnv}` - if (isProduction(celoEnv)) { + if (isProduction()) { baseCmd += ` -b contract_artifacts_production` } console.log(`Uploading artifacts for ${celoEnv}`) diff --git a/packages/celotool/src/lib/env-utils.ts b/packages/celotool/src/lib/env-utils.ts index 1aaabea3d48..b29fd756f69 100644 --- a/packages/celotool/src/lib/env-utils.ts +++ b/packages/celotool/src/lib/env-utils.ts @@ -128,15 +128,6 @@ export function validateAndSwitchToEnv(celoEnv: string) { process.exit(1) } - const indicatesStagingOrProductionEnv = isStaging(celoEnv) || isProduction(celoEnv) - - if (indicatesStagingOrProductionEnv && !isValidStagingOrProductionEnv(celoEnv)) { - console.error( - `${celoEnv} indicated to be a staging or production environment but did not conform to the expected regex ^[a-z][a-z0-9]*(staging|production)$.` - ) - process.exit(1) - } - const envResult = config({ path: getEnvFile(celoEnv) }) const envMemonicResult = config({ path: getEnvFile(celoEnv, '.mnemonic') }) @@ -159,33 +150,24 @@ export function validateAndSwitchToEnv(celoEnv: string) { process.env.CELOTOOL_CELOENV = celoEnv } -export function isStaging(env: string) { - return env.endsWith(EnvTypes.STAGING) -} - -export function isProduction(env: string) { - return env.endsWith(EnvTypes.PRODUCTION) +export function isProduction() { + return fetchEnv(envVar.ENV_TYPE).toLowerCase() === EnvTypes.PRODUCTION } export function isValidCeloEnv(celoEnv: string) { return new RegExp('^[a-z][a-z0-9]*$').test(celoEnv) } -function isValidStagingOrProductionEnv(celoEnv: string) { - return new RegExp('^[a-z][a-z0-9]*(staging|production)$').test(celoEnv) -} - function celoEnvMiddleware(argv: CeloEnvArgv) { validateAndSwitchToEnv(argv.celoEnv) } export async function doCheckOrPromptIfStagingOrProduction() { - if ( - process.env.CELOTOOL_CONFIRMED !== 'true' && - isValidStagingOrProductionEnv(process.env.CELOTOOL_CELOENV!) - ) { + if (process.env.CELOTOOL_CONFIRMED !== 'true' && isProduction()) { await confirmAction( - 'You are about to apply a possibly irreversable action on a staging/production environment. Are you sure?' + `You are about to apply a possibly irreversible action on a production env: ${ + process.env.CELOTOOL_CELOENV + }. Are you sure?` ) process.env.CELOTOOL_CONFIRMED = 'true' } diff --git a/packages/celotool/src/lib/helm_deploy.ts b/packages/celotool/src/lib/helm_deploy.ts index e3209735c8d..ceeac647b10 100644 --- a/packages/celotool/src/lib/helm_deploy.ts +++ b/packages/celotool/src/lib/helm_deploy.ts @@ -512,8 +512,8 @@ async function helmIPParameters(celoEnv: string) { } async function helmParameters(celoEnv: string) { - const bucketName = isProduction(celoEnv) ? 'contract_artifacts_production' : 'contract_artifacts' - const productionTagOverrides = isProduction(celoEnv) + const bucketName = isProduction() ? 'contract_artifacts_production' : 'contract_artifacts' + const productionTagOverrides = isProduction() ? [ `--set gethexporter.image.repository=${fetchEnv('GETH_EXPORTER_DOCKER_IMAGE_REPOSITORY')}`, `--set gethexporter.image.tag=${fetchEnv('GETH_EXPORTER_DOCKER_IMAGE_TAG')}`,