Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generate keypair and add to .env if one doesn't exist #5

Merged
merged 2 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
src/temp
dist
node_modules
16 changes: 14 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"dependencies": {
"@digitak/esrun": "^3.2.24",
"bs58": "^5.0.0",
"dotenv": "^16.3.1",
"prettier": "^3.0.3",
"typescript": "^5.2.2"
},
Expand Down
38 changes: 28 additions & 10 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { describe, test, before } from "node:test";
import { before, describe, test } from "node:test";
import { getKeypairFromEnvironment, getKeypairFromFile } from "./index";

import { Keypair } from "@solana/web3.js";
import assert from "node:assert/strict";
import { promisify } from "util";
import base58 from "bs58";
import dotenv from "dotenv";
import { exec as execForOldPeople } from "child_process";
const exec = promisify(execForOldPeople);
import { Keypair } from "@solana/web3.js";
import { getKeypairFromFile, getKeypairFromEnvironment } from "./index";
import { promisify } from "util";
import { unlinkSync } from "node:fs";
mikemaccana marked this conversation as resolved.
Show resolved Hide resolved
import { writeFile } from "node:fs/promises";
import base58 from "bs58";

const exec = promisify(execForOldPeople);

const log = console.log;

Expand Down Expand Up @@ -68,10 +72,24 @@ describe("getKeypairFromEnvironment", () => {
await getKeypairFromEnvironment(TEST_ENV_VAR_BASE58);
});

test("throws a nice error if the env var doesn't exist", async () => {
assert.rejects(async () => getKeypairFromEnvironment("MISSING_ENV_VAR"), {
message: `Please set 'MISSING_ENV_VAR' in environment.`,
});
test("generates new keypair and writes to env if variable doesn't exist", async () => {
ZYJLiu marked this conversation as resolved.
Show resolved Hide resolved
// Returns a new keypair and writes it to the .env file
const newKeypair = await getKeypairFromEnvironment("MISSING_ENV_VAR");
// Load the .env file
dotenv.config();
// Get the secret from the .env file
const secretKeyString = process.env["MISSING_ENV_VAR"];

if (!secretKeyString) {
throw new Error("MISSING_ENV_VAR not found in environment");
}
const decodedSecretKey = Uint8Array.from(JSON.parse(secretKeyString));
const envKeypair = Keypair.fromSecretKey(decodedSecretKey);

assert.deepStrictEqual(newKeypair.secretKey, envKeypair.secretKey);

// delete the .env file
unlinkSync(".env");
});

test("throws a nice error if the value of the env var isn't valid", async () => {
Expand Down
11 changes: 9 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Keypair } from "@solana/web3.js";
import { readFile } from "fs/promises";
import base58 from "bs58";
import fs from "fs";
import path from "path";
import { readFile } from "fs/promises";
const log = console.log;

// Default value from Solana CLI
Expand Down Expand Up @@ -45,7 +46,13 @@ export const getKeypairFromFile = async (filepath?: string) => {
export const getKeypairFromEnvironment = (variableName: string) => {
const secretKeyString = process.env[variableName];
if (!secretKeyString) {
throw new Error(`Please set '${variableName}' in environment.`);
// Generate a new keypair if one doesn't exist and add it to a `.env` file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an easy way to save keypairs is good PR, but my concern with adding this to an existing function is that something called getKeypairFromEnvironment() shouldn't have any side effects. Generally things called get() should be fetching data, not changing it. Also I'm concerned if someone wants to get a keypair with a particular name, it doesn't exist, and they get it made - it's possible we could be silently throwing away errors. Maybe I have a keypair called TEMP_WALLET and run getKeypairFromEnvironment('TEMPORARY_WALLET') and what should have failed succeeds.

I'd called the code that appends keypairs something like appendKeypairToFile(). Whatever you think is the most obvious for users.

const keypair = Keypair.generate();
fs.appendFileSync(
ZYJLiu marked this conversation as resolved.
Show resolved Hide resolved
".env",
`\n${variableName}=${JSON.stringify(Array.from(keypair.secretKey))}`,
);
return keypair;
}

// Try the shorter base58 format first
Expand Down