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

[DX-1541] Add random Stark keygen to user reg onboarding script, update onboarding scripts to use Core SDK #29

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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 .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ module.exports = {
'no-async-promise-executor': 'off',
'no-restricted-properties': 'off',
'import/no-cycle': 'off',
'prefer-destructuring': ["error", { "object": true, "array": false }],
},
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"@ethersproject/solidity": "^5.0.5",
"@ethersproject/strings": "^5.0.5",
"@ethersproject/wallet": "^5.0.7",
"@imtbl/core-sdk": "^1.0.0",
"@imtbl/imlogging": "^1.0.33",
"@imtbl/imx-sdk": "^1.28.0",
"@typescript-eslint/eslint-plugin": "^4.29.2",
Expand Down Expand Up @@ -87,4 +88,4 @@
"publishConfig": {
"access": "public"
}
}
}
2 changes: 1 addition & 1 deletion src/admin/get-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { ImmutableXClient } from '@imtbl/imx-sdk';
import { requireEnvironmentVariable } from 'libs/utils';
import { parse } from 'ts-command-line-args';

import env from '../config/client';
import { env } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
Expand Down
2 changes: 1 addition & 1 deletion src/admin/get-projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ImLogger, WinstonLogger } from '@imtbl/imlogging';
import { ImmutableXClient } from '@imtbl/imx-sdk';
import { requireEnvironmentVariable } from 'libs/utils';

import env from '../config/client';
import { env } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
Expand Down
2 changes: 1 addition & 1 deletion src/admin/get-withdrawal-balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from '@imtbl/imx-sdk';
import { requireEnvironmentVariable } from 'libs/utils';

import env from '../config/client';
import { env } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
Expand Down
2 changes: 1 addition & 1 deletion src/admin/update-collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ImLogger, WinstonLogger } from '@imtbl/imlogging';
import { ImmutableXClient, UpdateCollectionParams } from '@imtbl/imx-sdk';
import { requireEnvironmentVariable } from 'libs/utils';

import env from '../config/client';
import { env } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
Expand Down
2 changes: 1 addition & 1 deletion src/admin/update-metadata-by-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { requireEnvironmentVariable } from 'libs/utils';
import { parse } from 'ts-command-line-args';

import env from '../config/client';
import { env } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
Expand Down
4 changes: 2 additions & 2 deletions src/bulk-mint.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { AlchemyProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import { ImLogger, WinstonLogger } from '@imtbl/imlogging';
import { ImmutableXClient, ImmutableMethodParams } from '@imtbl/imx-sdk';
import { ImmutableMethodParams, ImmutableXClient } from '@imtbl/imx-sdk';
import { parse } from 'ts-command-line-args';

import env from './config/client';
import { env } from './config/client';
import { loggerConfig } from './config/logging';

interface BulkMintScriptArgs {
Expand Down
34 changes: 33 additions & 1 deletion src/config/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { AlchemyProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import { Config, ImmutableX } from '@imtbl/core-sdk';

import { getEnv } from '../libs/utils';

export default {
export const env = {
alchemyApiKey: getEnv('ALCHEMY_API_KEY'),
ethNetwork: getEnv('ETH_NETWORK'),
client: {
Expand All @@ -19,4 +23,32 @@ export default {
ownerAccountPrivateKey: getEnv('OWNER_ACCOUNT_PRIVATE_KEY'),
collectionContractAddress: getEnv('COLLECTION_CONTRACT_ADDRESS'),
collectionProjectId: getEnv('COLLECTION_PROJECT_ID'),
projectName: getEnv('PROJECT_NAME'),
companyName: getEnv('COMPANY_NAME'),
contactEmail: getEnv('CONTACT_EMAIL'),
};

function ensureNetworkSet() {
if (env.ethNetwork !== ('goerli' || 'mainnet')) {
throw new Error("Set ETH_NETWORK to 'goerli' or 'mainnet'");
}
}

export function createIMXClient() {
ensureNetworkSet();

if (env.ethNetwork === 'mainnet') {
return new ImmutableX(Config.PRODUCTION);
}
return new ImmutableX(Config.SANDBOX);
}

export function getEthWalletAndSigner() {
ensureNetworkSet();

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
const wallet = new Wallet(env.ownerAccountPrivateKey);
const ethSigner = wallet.connect(provider);

return { wallet, ethSigner };
}
108 changes: 80 additions & 28 deletions src/onboarding/1-user-registration.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,104 @@
import { AlchemyProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import {
createStarkSigner,
generateLegacyStarkPrivateKey,
generateStarkPrivateKey,
} from '@imtbl/core-sdk';
import { ImLogger, WinstonLogger } from '@imtbl/imlogging';
import { ImmutableXClient } from '@imtbl/imx-sdk';
import { requireEnvironmentVariable } from 'libs/utils';
import { parse } from 'ts-command-line-args';

import env from '../config/client';
import { createIMXClient, getEthWalletAndSigner } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
const log: ImLogger = new WinstonLogger(loggerConfig);

const component = '[IMX-USER-REGISTRATION]';

(async (): Promise<void> => {
const privateKey = requireEnvironmentVariable('OWNER_ACCOUNT_PRIVATE_KEY');
interface StarkKeyType {
starkKeyType: string;
}

// Initialize ImmutableX client
const client = createIMXClient();

const user = await ImmutableXClient.build({
...env.client,
signer: new Wallet(privateKey).connect(provider),
(async (): Promise<void> => {
// Get user input for type of Stark key to generate
const { starkKeyType } = parse<StarkKeyType>({
starkKeyType: {
type: String,
alias: 's',
description: "Stark key type: 'random' (default: 'deterministic')",
},
});

log.info(component, 'Registering user...');
// Check that value entered is exactly 'random'
if (starkKeyType !== 'random') {
const text =
"Enter 'random' or do not use '-s' flag.\n\n" +
'To generate a non-deterministic Stark key (more secure, recommended for ' +
'collection owners): `npm run onboarding:user-registration -- -s random`\n' +
'***NOTE*** You must persist and store this key securely as it cannot be ' +
'regenerated for you.\n\n' +
'To generate a deterministic Stark key: `npm run onboarding:user-registration`\n';

console.log(text);
return;
}

// Create Ethereum signer
const { ethSigner } = getEthWalletAndSigner();

// Check if user already exists
let starkPublicKey;
let starkPrivateKey;

let existingUser;
let newUser;
try {
// Fetching existing user
existingUser = await user.getUser({
user: user.address,
});
const existingUser = await client.getUser(ethSigner.address);
starkPublicKey = existingUser.accounts[0];

const message =
`This user is already registered.\nEthereum (L1) public key: ${ethSigner.address}` +
`\nStark (L2) public key: ${starkPublicKey}`;

console.log(message);
return;
} catch {
// If user doesn't exist, register user
try {
// If user doesnt exist, create user
newUser = await user.registerImx({
etherKey: user.address,
starkPublicKey: user.starkPublicKey,
});
log.info(component, 'Registering user...');

// Generate Stark private key
if (starkKeyType === 'random') {
starkPrivateKey = generateStarkPrivateKey();
} else {
starkPrivateKey = await generateLegacyStarkPrivateKey(ethSigner);
}

// Create Stark signer
const starkSigner = createStarkSigner(starkPrivateKey);

// Register user
await client.registerOffchain({ ethSigner, starkSigner });

// Get registered user Stark key
const registeredUser = await client.getUser(ethSigner.address);
starkPublicKey = registeredUser.accounts[0];
} catch (error) {
throw new Error(JSON.stringify(error, null, 2));
}
}

if (existingUser) {
log.info(component, 'User already exists', user.address);
} else {
log.info(component, 'User has been created', user.address);
// Return details about the user created
console.log('User has been registered.');
console.log(`Ethereum (L1) public key: ${ethSigner.address}`);
console.log(`Stark (L2) public key: ${starkPublicKey}`);

if (starkKeyType === 'random') {
const message =
`Stark (L2) private key: ${starkPrivateKey}\n` +
'***NOTE*** You must persist and store this key securely as it cannot be ' +
'regenerated for you.';
console.log(message);
}
console.log(JSON.stringify({ newUser, existingUser }, null, 2));
})().catch(e => {
log.error(component, e);
process.exit(1);
Expand Down
44 changes: 17 additions & 27 deletions src/onboarding/2-create-project.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,37 @@
import { AlchemyProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import { ImLogger, WinstonLogger } from '@imtbl/imlogging';
import { CreateProjectParams, ImmutableXClient } from '@imtbl/imx-sdk';
import { requireEnvironmentVariable } from 'libs/utils';

import env from '../config/client';
import { createIMXClient, env, getEthWalletAndSigner } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
const log: ImLogger = new WinstonLogger(loggerConfig);

const component = '[IMX-CREATE-PROJECT]';

// Initialize ImmutableX client
const client = createIMXClient();

(async (): Promise<void> => {
const privateKey = requireEnvironmentVariable('OWNER_ACCOUNT_PRIVATE_KEY');
// Create Ethereum signer
const { ethSigner } = getEthWalletAndSigner();

const signer = new Wallet(privateKey).connect(provider);
log.info(component, 'Creating project...');

const user = await ImmutableXClient.build({
...env.client,
signer,
enableDebug: true,
});
// Create project
try {
const createProjectResponse = await client.createProject(ethSigner, {
name: env.projectName,
company_name: env.companyName,
contact_email: env.contactEmail,
});

log.info(component, 'Creating project...');
const projectId = createProjectResponse.id.toString();

/**
* Edit your values here
*/
const params: CreateProjectParams = {
name: 'ENTER_PROJECT_NAME_HERE-2',
company_name: 'ENTER_COMPANY_NAME_HERE',
contact_email: '[email protected]',
};
const getProjectResponse = await client.getProject(ethSigner, projectId);

let project;
try {
project = await user.createProject(params);
log.info(component, `Created project with ID: ${getProjectResponse.id}`);
} catch (error) {
throw new Error(JSON.stringify(error, null, 2));
}

log.info(component, `Created project with ID: ${project.id}`);
})().catch(e => {
log.error(component, e);
process.exit(1);
Expand Down
41 changes: 14 additions & 27 deletions src/onboarding/3-create-collection.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,40 @@
import { AlchemyProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import { CreateCollectionRequest } from '@imtbl/core-sdk';
import { ImLogger, WinstonLogger } from '@imtbl/imlogging';
import { CreateCollectionParams, ImmutableXClient } from '@imtbl/imx-sdk';
import { requireEnvironmentVariable } from 'libs/utils';

import env from '../config/client';
import { createIMXClient, env, getEthWalletAndSigner } from '../config/client';
import { loggerConfig } from '../config/logging';

const provider = new AlchemyProvider(env.ethNetwork, env.alchemyApiKey);
const log: ImLogger = new WinstonLogger(loggerConfig);

const component = '[IMX-CREATE-COLLECTION]';

(async (): Promise<void> => {
const privateKey = requireEnvironmentVariable('OWNER_ACCOUNT_PRIVATE_KEY');
const collectionContractAddress = requireEnvironmentVariable(
'COLLECTION_CONTRACT_ADDRESS',
);
const projectId = requireEnvironmentVariable('COLLECTION_PROJECT_ID');

const wallet = new Wallet(privateKey);
const signer = wallet.connect(provider);
const ownerPublicKey = wallet.publicKey;
// Initialize ImmutableX client
const client = createIMXClient();

const user = await ImmutableXClient.build({
...env.client,
signer,
enableDebug: true,
});
(async (): Promise<void> => {
// Get Ethereum wallet and signer
const { wallet, ethSigner } = getEthWalletAndSigner();

log.info(component, 'Creating collection...', collectionContractAddress);
log.info(component, 'Creating collection...', env.collectionContractAddress);

/**
* Edit your values here
*/
const params: CreateCollectionParams = {
const params: CreateCollectionRequest = {
name: 'ENTER_COLLECTION_NAME',
// description: 'ENTER_COLLECTION_DESCRIPTION (OPTIONAL)',
contract_address: collectionContractAddress,
owner_public_key: ownerPublicKey,
contract_address: env.collectionContractAddress,
owner_public_key: wallet.publicKey,
// icon_url: '',
// metadata_api_url: '',
// collection_image_url: '',
project_id: parseInt(projectId, 10),
project_id: parseInt(env.collectionProjectId, 10),
};

let collection;

try {
collection = await user.createCollection(params);
collection = await client.createCollection(ethSigner, params);
} catch (error) {
throw new Error(JSON.stringify(error, null, 2));
}
Expand Down
Loading