From 5214c3d15c0e7908663419a6802bf16f9e6a93ef Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 18 Oct 2023 20:50:09 -0400 Subject: [PATCH] getTez: Allow users to specify a local Tezos address alias --- getTez/README.md | 14 +++++++++++++ getTez/getTez.ts | 51 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/getTez/README.md b/getTez/README.md index 856edd8..bd5f947 100644 --- a/getTez/README.md +++ b/getTez/README.md @@ -13,6 +13,7 @@ npm install @oxheadalpha/get-tez ## Usage ### JS / TS + After installing the package, you can import it in your Node.js JavaScript or TypeScript project: ```javascript @@ -29,6 +30,7 @@ You can then use the `getTez` function to interact with the Tezos faucet. The fu - `amount`: The amount of Tez to request. - `network`: The faucet's network name. Must match a network name with a faucet listed at https://teztnets.xyz. Ignored if `faucetUrl` is set. - `faucetUrl`: The custom faucet URL. Ignores `network`. +- `clientDir`: (Optional) Specifies a custom client directory path to look up address aliases. If not set, it will default to `$HOME/.tezos-client/` or `$TEZOS_CLIENT_DIR/public_key_hashs` if the `TEZOS_CLIENT_DIR` environment variable is specified. Here is an example of how to use the `getTez` function: @@ -41,7 +43,19 @@ const txHash = await getTez({ // txHash: ooaEskbj... ``` +Using an address alias: + +```javascript +const txHash = await getTez({ + address: "alice", + amount: 10, + network: "ghostnet", +}) +// txHash: ooaEskbj... +``` + Example using the `faucetUrl` parameter: + ```js const txHash = await getTez({ address: "tz1...", diff --git a/getTez/getTez.ts b/getTez/getTez.ts index c8514ab..e8103f2 100755 --- a/getTez/getTez.ts +++ b/getTez/getTez.ts @@ -1,6 +1,7 @@ #!/usr/bin/env node - import * as crypto from "crypto" +import * as fs from "fs" +import * as path from "path" import * as pkgJson from "./package.json" const isMainModule = require.main === module @@ -30,6 +31,13 @@ const [time, timeLog, timeEnd] = [ const displayHelp = () => { log(`CLI Usage: npx @oxheadalpha/get-tez [options]
+ +
: + The address where Tez should be sent. This can be either a standard Tezos public key hash (e.g. tz1234abc...) + or a local alias. If an alias is provided (e.g., 'alice'), the program will attempt to resolve it to a public + key hash by looking it up in the specified client directory (set by --client-dir or by the TEZOS_CLIENT_DIR + environment variable). If neither is set, the default lookup location is $HOME/.tezos-client/public_key_hashes. + Options: -h, --help Display help information. -a, --amount The amount of Tez to request. @@ -37,6 +45,7 @@ Options: network name with a faucet listed at https://teztnets.xyz. Ignored if --faucet-url is set. -f, --faucet-url Set the custom faucet URL. Ignores --network. + -d, --client-dir Custom client directory path to look up an address alias. -t, --time Enable PoW challenges timer. -v, --verbose Enable verbose logging. --version Log the package version.`) @@ -55,11 +64,30 @@ const handleError = (message: string, help?: boolean) => { } } +const DEFAULT_CLIENT_DIR = + process.env.TEZOS_CLIENT_DIR || path.join(process.env.HOME!, ".tezos-client") + +const resolveAliasToPkh = ( + alias: string, + clientDir: string = DEFAULT_CLIENT_DIR +): string | null => { + const pkhsFilePath = path.join(clientDir, "public_key_hashs") + if (fs.existsSync(pkhsFilePath)) { + const pkhsData: Array<{ name: string; value: string }> = JSON.parse( + fs.readFileSync(pkhsFilePath, "utf8") + ) + return pkhsData.find(({ name }) => name === alias)?.value || null + } + return null +} + type GetTezArgs = { /** The address to send Tez to. */ address: string /** The amount of Tez to request. */ amount: number + /** Custom client directory path to look up address alias. */ + clientDir?: string /** Set the faucet's network name. Must match a network name with a faucet * listed at https://teztnets.xyz. Ignored if `faucetUrl` is set. */ network?: string @@ -104,6 +132,14 @@ const parseCliArgs = (args: string | string[]): GetTezArgs => { case "--faucet-url": parsedArgs.faucetUrl = args.shift() || "" break + case "-d": + case "--client-dir": + const clientDir = args.shift() + if (!clientDir) { + handleError(`The ${arg} flag expects an argument.`, DISPLAY_HELP) + } + parsedArgs.clientDir = clientDir + break case "-v": case "--verbose": VERBOSE = true @@ -119,7 +155,7 @@ const parseCliArgs = (args: string | string[]): GetTezArgs => { if (!parsedArgs.address) { parsedArgs.address = arg || "" } else { - handleError(`Unexpected argument provided '${arg}'.`, DISPLAY_HELP) + handleError(`Unexpected argument provided: '${arg}'`, DISPLAY_HELP) } break } @@ -131,8 +167,19 @@ const parseCliArgs = (args: string | string[]): GetTezArgs => { type ValidatedArgs = Required> const validateArgs = async (args: GetTezArgs): Promise => { + if (args.clientDir && !fs.existsSync(args.clientDir)) { + handleError(`Client dir '${args.clientDir}' doesn't exist.`) + } + if (!args.address) { handleError("Tezos address is required.", DISPLAY_HELP) + } else if (!args.address.startsWith("tz")) { + const resolvedAddress = resolveAliasToPkh(args.address, args.clientDir) + if (!resolvedAddress) { + handleError(`Alias '${args.address}' not found.`) + } else { + args.address = resolvedAddress + } } if (!args.amount || args.amount <= 0) {