Skip to content

Commit

Permalink
add local private key signer #1
Browse files Browse the repository at this point in the history
  • Loading branch information
ukorvl committed May 16, 2024
1 parent 2e2481f commit 9191627
Show file tree
Hide file tree
Showing 24 changed files with 307 additions and 44 deletions.
26 changes: 26 additions & 0 deletions .github/actions/build/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: "Build"
description: "Install dependencies, lint, test and build the project."

runs:
using: "composite"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Nodejs
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: Install dependencies
run: |
export SKIP_INSTALL_SIMPLE_GIT_HOOKS=1
npm ci
- name: Lint
run: npm run lint
- name: Format
run: npm run format
- name: Test
run: npm run test:ci
- name: Build
run: |
npm run build
ls -lh dist
20 changes: 1 addition & 19 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,5 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Nodejs
uses: actions/setup-node@v3
with:
node-version: 20.x
- name: Install dependencies
run: |
export SKIP_INSTALL_SIMPLE_GIT_HOOKS=1
npm ci
- name: Lint
run: npm run lint
- name: Format
run: npm run format
- name: Test
run: npm run test:ci
- name: Build
run: |
npm run build
ls -lh dist
uses: ./.github/actions/build
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
node_modules
build
dist

logs
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<h1 align="center">Nil.js</h1>

<br />

<p align="center">
=nil; Foundation Typescript client to interact with the Nil network.
</p>

<p align="center">
<a href="https://github.com/NilFoundation/nil.js/actions/workflows/build.yaml">
<picture>
<img src="https://img.shields.io/github/actions/workflow/status/NilFoundation/nil.js/actions/workflows/build.yaml?color=%23212121">
</picture>
</a>
</p>
27 changes: 26 additions & 1 deletion package-lock.json

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

13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
"scripts": {
"test": "vitest -c ./test/vitest.config.ts",
"test:ci": "CI=true vitest -c ./test/vitest.config.ts",
"build": "rimraf dist && tsc -p tsconfig.json",
"build": "rimraf dist && tsc -p tsconfig.json --excludeFiles '**/*.test.ts'",
"prepare": "npx simple-git-hooks",
"format": "biome format src",
"lint": "biome check src"
},
"license": "MIT",
"peerDependencies": {
"@open-rpc/client-js": ">=1.8.1 <1.9.0",
"@noble/curves": ">=1.4.0 <1.5.0"
"@noble/curves": ">=1.4.0 <1.5.0",
"@open-rpc/client-js": ">=1.8.1 <1.9.0"
},
"devDependencies": {
"@biomejs/biome": "^1.7.3",
Expand All @@ -41,8 +41,9 @@
"pre-commit": "npm run lint",
"pre-push": "npm run format",
"commit-msg": "npx --no-install commitlint --edit $1",
"preserveUnused": [
"commit-msg"
]
"preserveUnused": ["commit-msg"]
},
"dependencies": {
"@chainsafe/ssz": "^0.16.0"
}
}
File renamed without changes.
12 changes: 6 additions & 6 deletions src/publicClient.ts → src/clients/PublicClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createRPCClient } from "./rpc/rpcClient.js";
import type { IPublicClientConfig } from "./types/ClientConfigs.ts";
import { createRPCClient } from "../rpc/rpcClient.js";
import type { IPublicClientConfig } from "../types/ClientConfigs.js";

/**
* Public client is a class that allows you to interact with the network via JSON-RPC api.
Expand Down Expand Up @@ -34,7 +34,7 @@ class PublicClient {
*/
public async getBlockByHash(hash: Uint8Array): Promise<Uint8Array> {
const block = await this.rpcClient.request({
method: "GetBlockByHash",
method: "eth_getBlockByHash",
params: {
hash: hash,
},
Expand All @@ -58,7 +58,7 @@ class PublicClient {
*/
public async getBlockByNumber(number: number): Promise<Uint8Array> {
const block = await this.rpcClient.request({
method: "GetBlockByNumber",
method: "eth_getBlockByNumber",
params: {
number: number,
},
Expand All @@ -84,7 +84,7 @@ class PublicClient {
number: number,
): Promise<number> {
const count = await this.rpcClient.request({
method: "GetBlockTransactionCountByNumber",
method: "eth_getBlockTransactionCountByNumber",
params: {
number: number,
},
Expand All @@ -110,7 +110,7 @@ class PublicClient {
hash: Uint8Array,
): Promise<number> {
const count = await this.rpcClient.request({
method: "GetBlockTransactionCountByHash",
method: "eth_getBlockTransactionCountByHash",
params: {
hash: hash,
},
Expand Down
File renamed without changes.
34 changes: 32 additions & 2 deletions src/walletClient.ts → src/clients/WalletClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createRPCClient } from "./rpc/rpcClient.js";
import type { IWalletClientConfig } from "./types/ClientConfigs.ts";
import { createRPCClient } from "../rpc/rpcClient.js";
import type { IWalletClientConfig } from "../types/ClientConfigs.js";

/**
* Wallet client is a class that allows you to interact with the network via JSON-RPC api.
Expand All @@ -14,6 +14,8 @@ import type { IWalletClientConfig } from "./types/ClientConfigs.ts";
*/
class WalletClient {
private rpcClient: ReturnType<typeof createRPCClient>;
private signer: IWalletClientConfig["signer"];
private serializer: IWalletClientConfig["serializer"];

constructor(config: IWalletClientConfig) {
this.rpcClient = createRPCClient(config.endpoint);
Expand All @@ -39,10 +41,38 @@ class WalletClient {
params: {
transaction: transaction,
},

// if we pass local private key, we can sign the transaction here.
// we have 2 options: 1. sign the transaction here, 2. sign the transaction in the snap.

// we can accept here base tx object
// and sign it here
// or we can accept here signed tx
// and send it to the network
});

return hash;
}

/**
* deployContract deploys a contract to the network.
* @param contract - The contract to deploy.
* @returns The hash of the transaction.
* @example
import { WalletClient } from 'niljs';
*
* const client = new WalletClient({
* endpoint: 'http://localhost:8529'
* })
*
* const contract = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const hash = await client.deployContract(contract);
*/
public async deployContract(contract: Uint8Array): Promise<Uint8Array> {
const hash = await this.sendTransaction(contract);

return hash;
}
}

export { WalletClient };
23 changes: 23 additions & 0 deletions src/encoding/serializer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Serializer class to serialize and deserialize data to and from ssz format.
* @example
* import { Serializer } from 'niljs';
*
* const serializer = new Serializer();
* const data = { key: 'value' };
*
* const serializedData = serializer.serialize(data);
* const deserializedData = serializer.deserialize(serializedData);
*/
class Serializer {
public serialize(data: unknown): string {
return JSON.stringify(data);
}

public deserialize(data: string): unknown {
return JSON.parse(data);
}
}

// user should have schema out of the box and be able to provide custom.
export { Serializer };
13 changes: 9 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
export { PublicClient } from "./publicClient.js";
export { WalletClient } from "./walletClient.js";
export { PublicClient } from "./clients/PublicClient.js";
export { WalletClient } from "./clients/WalletClient.js";
export type {
IPublicClientConfig,
IWalletClientConfig,
} from "./types/ClientConfigs.ts";
export { Serializer } from "./encoding/Serializer.js";
export { LocalKeySigner } from "./signers/LocalKeySigner.js";

// what is format of our transaction?
// first, serialize body, than bytes+signature, then we supply ssz as hex.
// first, serialize body of tx
// than sign it
// than serialize signature+serizalized body
// than send it to the network as hex data
// we want to send as a parameter hex data of transaction.
// we want to sign tx before sending it to the network.

// we also need a schema from ssz
// we also need a schema for ssz
Empty file.
52 changes: 52 additions & 0 deletions src/signers/LocalKeySigner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { ILocalKeySignerConfig } from "../types/ILocalKeySignerConfig.js";
import type { ISigner } from "../types/ISigner.js";
import { getPublicKey } from "./getPublicKey.js";

/**
* LocalKeySigner is a class that allows you to sign the data with the private key.
* It is an abstraction of signing the data with the private key.
* It uses the secp256k1 curve implementation by @noble/curves/secp256k1 library under the hood.
* @example
* import { LocalKeySigner } from 'niljs';
*
* const privateKey = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const signer = new LocalKeySigner({ privateKey });
*/
class LocalKeySigner implements ISigner {
private publicKey;

constructor(config: ILocalKeySignerConfig) {
this.publicKey = getPublicKey(config.privateKey);
}

/**
* Signs the message.
* Accepts valid data as an argument and returns signed message.
* @example
* const data = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const signedMessage = signer.signMessage(data);
*/
public signMessage(data: Uint8Array) {
//
}

/**
* Signs the transaction.
* Accepts valid transaction object as an argument and returns signed transaction.
* @example
* const transaction = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const signedTransaction = signer.signTransaction(transaction);
*/
public signTransaction(transaction: Uint8Array) {}

/**
* Returns the public key.
* @example
* const publicKey = signer.getPublicKey();
*/
public getPublicKey() {
return this.publicKey;
}
}

export { LocalKeySigner };
13 changes: 13 additions & 0 deletions src/signers/getPublicKey.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { accounts } from "../../test/mocks/accounts.js";
import { getPublicKey } from "./getPublicKey.js";

test("getPublicKey", async ({ expect }) => {
const account = accounts[0];
const input = account.privateKey;

const expectedOutput = account.publicKey;

const result = getPublicKey(input);

expect(result).toBe(expectedOutput);
});
13 changes: 13 additions & 0 deletions src/signers/getPublicKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { type Hex, bytesToHex } from "@noble/curves/abstract/utils";
import { secp256k1 } from "@noble/curves/secp256k1";
import type { IPrivateKey } from "../types/IPrivateKey.js";

/**
* Returns the public key from the private key using the secp256k1 curve.
*/
const getPublicKey = (privateKey: IPrivateKey): Hex => {
const publicKey = secp256k1.getPublicKey(privateKey.slice(2), false);
return bytesToHex(publicKey);
};

export { getPublicKey };
Loading

0 comments on commit 9191627

Please sign in to comment.