Skip to content

Commit

Permalink
🪚 Options CLI Builder (#206)
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Goulding <goulding@layerzerolabs.org>
Co-authored-by: Ján Jakub Naništa <jan.jakub.nanista@gmail.com>
  • Loading branch information
ryandgoulding and janjakubnanista authored Jan 26, 2024
1 parent a11441a commit d332c6d
Show file tree
Hide file tree
Showing 17 changed files with 644 additions and 4 deletions.
2 changes: 2 additions & 0 deletions packages/build-lz-options/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
dist/
node_modules/
31 changes: 31 additions & 0 deletions packages/build-lz-options/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<p align="center">
<a href="https://layerzero.network">
<img alt="LayerZero" style="max-width: 500px" src="https://d3a2dpnnrypp5h.cloudfront.net/bridge-app/lz.png"/>
</a>
</p>

<h1 align="center">build-lz-oapp</h1>

<!-- The badges section -->
<p align="center">
<!-- Shields.io NPM published package version -->
<a href="https://www.npmjs.com/package/build-lz-oapp"><img alt="NPM Version" src="https://img.shields.io/npm/v/build-lz-oapp"/></a>
<!-- Shields.io NPM downloads -->
<a href="https://www.npmjs.com/package/build-lz-oapp"><img alt="Downloads" src="https://img.shields.io/npm/dm/build-lz-oapp"/></a>
<!-- Shields.io license badge -->
<a href="https://www.npmjs.com/package/build-lz-oapp"><img alt="NPM License" src="https://img.shields.io/npm/l/build-lz-oapp"/></a>
</p>

## Create LayerZero OApp Options <img alt="Static Badge" src="https://img.shields.io/badge/status-work_in_progress-yellow">

This package provides a convenient way to build and serialize Options for LayerZero OApps.

```bash
npx build-lz-options@latest
# or
yarn build-lz-options
# or
pnpm build-lz-options
# or
bunx build-lz-options
```
3 changes: 3 additions & 0 deletions packages/build-lz-options/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node

import('./dist/index.js');
9 changes: 9 additions & 0 deletions packages/build-lz-options/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testTimeout: 15000,
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
57 changes: 57 additions & 0 deletions packages/build-lz-options/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "build-lz-options",
"version": "0.0.1",
"description": "Build LayerZero options with one command",
"keywords": [
"LayerZero",
"OApp",
"Options"
],
"repository": {
"type": "git",
"url": "git+https://github.com/LayerZero-Labs/devtools.git",
"directory": "packages/build-lz-options"
},
"license": "MIT",
"bin": {
"build-lz-options": "./cli.js"
},
"files": [
"cli.js",
"dist"
],
"scripts": {
"prebuild": "tsc -noEmit",
"build": "$npm_execpath tsup",
"clean": "rm -rf dist",
"dev": "$npm_execpath tsup --watch",
"lint": "$npm_execpath eslint '**/*.{js,ts,json}'",
"start": "./cli.js"
},
"dependencies": {
"yoga-layout-prebuilt": "^1.10.0"
},
"devDependencies": {
"@layerzerolabs/devtools-evm": "~0.0.4",
"@layerzerolabs/io-devtools": "~0.0.5",
"@layerzerolabs/lz-v2-utilities": "~2.0.14",
"@types/prompts": "^2.4.9",
"@types/react": "^17.0.74",
"commander": "^11.1.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"ink": "^3.2.0",
"ink-gradient": "^2.0.0",
"prompts": "^2.4.2",
"react": "^17.0.2",
"ts-node": "^10.9.2",
"tsup": "~8.0.1",
"typescript": "^5.3.3"
},
"engines": {
"node": ">=18"
},
"publishConfig": {
"access": "public"
}
}
55 changes: 55 additions & 0 deletions packages/build-lz-options/src/components/config.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from "react";
import { Box, Text } from "ink";
import {
OptionType1Summary,
OptionTypeInput,
OptionType2Summary,
} from "@/types";

interface Props {
value: OptionTypeInput;
}

interface OptionType1Props {
props: OptionType1Summary;
}

interface OptionType2Props {
props: OptionType2Summary;
}

export const ConfigSummary: React.FC<Props> = ({ value }) => {
return (
<Box flexDirection="column" marginTop={1} marginBottom={1}>
<Text>
Creating LayerZero options <Text bold>{value.type.label}</Text>
</Text>
</Box>
);
};

export const Option1Summary: React.FC<OptionType1Props> = ({ props }) => {
return (
<Box flexDirection="column" marginTop={1} marginBottom={1}>
<Text>
Gas Limit: <Text bold>{props.gasLimit}</Text>
</Text>
</Box>
);
};

export const Option2Summary: React.FC<OptionType2Props> = ({ props }) => {
return (
<Box flexDirection="column" marginTop={1} marginBottom={1}>
<Text>
Gas Limit: <Text bold>{props.gasLimit}</Text>
</Text>
<Text>
Native Drop Amount: <Text bold>{props.nativeDropAmount}</Text>
</Text>
<Text>
Native Drop Address: <Text bold>{props.nativeDropAddress}</Text>
</Text>
</Box>
);
};
23 changes: 23 additions & 0 deletions packages/build-lz-options/src/components/outputOptions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import type { OptionOutput } from "@/types";
import { Box, Text } from "ink";

interface OptionOutputProps {
props: OptionOutput;
}

/**
* Render the options output to the user.
* @param {OptionOutputProps} props
*/
export const OutputOptions: React.FC<OptionOutputProps> = ({
props,
}: OptionOutputProps) => {
return (
<Box flexDirection="column">
<Text>
Result: <Text color={"green"}>{props.hex}</Text>
</Text>
</Box>
);
};
59 changes: 59 additions & 0 deletions packages/build-lz-options/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { OptionType } from '@/types'
import { ExecutorOptionType, WorkerId } from '@layerzerolabs/lz-v2-utilities'

/**
* Supported Option Types.
*/
export const OPTION_TYPES: OptionType[] = [
{
// TODO: use OptionType.TYPE_1 once exported from lz-v2-utility
id: '1',
label: '1: gas for remote execution',
},
{
// TODO: use OptionType.TYPE_2 once exported from lz-v2-utility
id: '2',
label: '2: gas for remote execution and native drop',
},
{
// TODO: use OptionType.TYPE_3 once exported from lz-v2-utility
id: '3',
label: '3: options builder (EndpointV2 only)',
},
]

/**
* Supported Executor Option Types.
*/
export const EXECUTOR_OPTION_TYPE = [
{
id: ExecutorOptionType.LZ_RECEIVE,
label: '1: lzReceive',
},
{
id: ExecutorOptionType.NATIVE_DROP,
label: '2: nativeDrop',
},
{
id: ExecutorOptionType.COMPOSE,
label: '3: compose',
},
{
id: ExecutorOptionType.ORDERED,
label: '4: ordered',
},
]

/**
* Supported Worker Types.
*/
export const WORKER_TYPE = [
{
id: WorkerId.EXECUTOR,
label: '1 Executor',
},
{
id: WorkerId.VERIFIER,
label: '2 Verifier',
},
]
71 changes: 71 additions & 0 deletions packages/build-lz-options/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { makeBytes32 } from "@layerzerolabs/devtools-evm";
import { optionsType1, optionsType2 } from "@layerzerolabs/lz-v2-utilities";
import React from "react";
import { render } from "ink";
import { Command } from "commander";
import {
promptForOptionType,
promptForOptionType1,
promptForOptionType2,
promptForOptionType3,
} from "@/utilities/prompts";
import {
ConfigSummary,
Option1Summary,
Option2Summary,
} from "@/components/config";
import { OutputOptions } from "@/components/outputOptions";
import { printLogo } from "@layerzerolabs/io-devtools/swag";
import { version } from "../package.json";

new Command("build-lz-options")
.description("Create LayerZero OApp options with one command")
.version(version)
.action(async () => {
printLogo();

const config = await promptForOptionType();
render(<ConfigSummary value={config} />).unmount();

let output: string = "";

switch (config.type.id) {
case "1": {
const options = await promptForOptionType1();
render(
<Option1Summary
props={{
gasLimit: options.gasLimit,
}}
/>,
).unmount();
output = optionsType1(options.gasLimit);
break;
}
case "2": {
const options = await promptForOptionType2();
render(
<Option2Summary
props={{
gasLimit: options.gasLimit,
nativeDropAmount: options.nativeDropAmount,
nativeDropAddress: options.nativeDropAddress,
}}
/>,
).unmount();
output = optionsType2(
options.gasLimit,
options.nativeDropAmount,
makeBytes32(options.nativeDropAddress),
);
break;
}
case "3": {
const options = await promptForOptionType3();
output = options.toHex();
break;
}
}
render(<OutputOptions props={{ hex: output }} />);
})
.parseAsync();
36 changes: 36 additions & 0 deletions packages/build-lz-options/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Used to render OptionType input from the user.
*/
export interface OptionType {
id: string
label: string
}

/**
* Input OptionType selection.
*/
export interface OptionTypeInput {
type: OptionType
}

/**
* The result of building an Option.
*/
export interface OptionOutput {
hex: string
}

/**
* Summary of OptionType.TYPE_1.
*/
export interface OptionType1Summary {
gasLimit: string
}

/**
* Summary of OptionType.TYPE_2.
*/
export interface OptionType2Summary extends OptionType1Summary {
nativeDropAmount: string
nativeDropAddress: string
}
Loading

0 comments on commit d332c6d

Please sign in to comment.