Skip to content

Commit

Permalink
add deserialization prototypes and give commonjs build cjs extension #1
Browse files Browse the repository at this point in the history
  • Loading branch information
ukorvl committed May 21, 2024
1 parent a31443d commit 888d1b9
Show file tree
Hide file tree
Showing 29 changed files with 314 additions and 182 deletions.
2 changes: 1 addition & 1 deletion .changeset/brave-dancers-end.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"niljs": patch
---

Added methods to serialize transactions and transactions with signatures
Added methods to serialize messages and messages with signatures
5 changes: 5 additions & 0 deletions .changeset/red-poems-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"niljs": patch
---

Rename transaction to message
5 changes: 5 additions & 0 deletions .changeset/wise-shrimps-look.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"niljs": patch
---

Add cjs extension to commonjs build
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ publicClient.getBalance("your_address").then((balance) => {
});
```

The second one is the `WalletClient` class, which is used to interact with the Nil network with a private key. It is used to send transactions to the network.
The second one is the `WalletClient` class, which is used to interact with the Nil network with a private key. It is used to send messages to the network.

```typescript
import { WalletClient } from "niljs";
Expand All @@ -51,7 +51,7 @@ const endpoint = "https://localhost:8259";
const walletClient = new WalletClient({ endpoint });

walletClient
.sendTransaction({
.sendMessage({
from: "your_address",
to: "recipient_address",
amount: 100,
Expand All @@ -61,7 +61,7 @@ walletClient
});
```

Initialize the Signer with the private key of the account you want to use to sign transactions.
Initialize the Signer with the private key of the account you want to use to sign messages.

```typescript
import { Signer } from "niljs";
Expand All @@ -72,7 +72,7 @@ const signer = new Signer({ privateKey });
signer.sign(new Uint8Array(32));
```

You can also sign transactions automatically by passing the Signer instance to the WalletClient.
You can also sign messages automatically by passing the Signer instance to the WalletClient.

```typescript
import { WalletClient } from "niljs";
Expand Down
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
"lineWidth": 80
},
"files": {
"ignore": ["node_modules", "dist"]
"ignore": ["node_modules", "dist", "package.json"]
}
}
17 changes: 13 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
"node": ">=18.0.0"
},
"type": "module",
"main": "dist/niljs.cjs.js",
"main": "dist/niljs.cjs.cjs",
"module": "dist/niljs.esm.js",
"files": ["dist"],
"files": [
"dist"
],
"types": "dist/niljs.d.ts",
"exports": {
".": {
Expand Down Expand Up @@ -65,10 +67,17 @@
"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",
"tiny-invariant": "^1.3.3"
}
},
"keywords": [
"nil",
"blockchain",
"client"
]
}
34 changes: 15 additions & 19 deletions src/clients/PublicClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,47 +63,43 @@ class PublicClient extends BaseClient {
}

/**
* getBlockTransactionCountByNumber returns the transaction count by the block number.
* getBlockMessageCountByNumber returns the message count by the block number.
* @param number - The block number.
* @returns The transaction count.
* @returns The message count.
* @example
import { PublicClient } from 'niljs';
*
* const client = new PublicClient({
* endpoint: 'http://127.0.0.1:8529'
* })
*
* const count = await client.getBlockTransactionCountByNumber(1);
* const count = await client.getBlockMessageCountByNumber(1);
*/
public async getBlockTransactionCountByNumber(
number: number,
): Promise<number> {
public async getBlockMessageCountByNumber(number: number): Promise<number> {
const res = await this.rpcClient.request({
method: "eth_getBlockTransactionCountByNumber",
method: "eth_getBlockMessageCountByNumber",
params: [number],
});

return res.result;
}

/**
* getBlockTransactionCountByHash returns the transaction count by the block hash.
* getBlockMessageCountByHash returns the message count by the block hash.
* @param hash - The block hash.
* @returns The transaction count.
* @returns The message count.
* @example
import { PublicClient } from 'niljs';
*
* const client = new PublicClient({
* endpoint: 'http://127.0.0.1:8529'
* })
*
* const count = await client.getBlockTransactionCountByHash(Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
* const count = await client.getBlockMessageCountByHash(Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
*/
public async getBlockTransactionCountByHash(
hash: Uint8Array,
): Promise<number> {
public async getBlockMessageCountByHash(hash: Uint8Array): Promise<number> {
const res = await this.rpcClient.request({
method: "eth_getBlockTransactionCountByHash",
method: "eth_getBlockMessageCountByHash",
params: [hash],
});

Expand Down Expand Up @@ -137,25 +133,25 @@ class PublicClient extends BaseClient {
}

/**
* getTransactionCount returns the transaction count of the address.
* getMessageCount returns the message count of the address.
* @param address - The address.
* @param blockNumberOrHash - The block number or hash.
* @returns The transaction count.
* @returns The message count.
* @example
import { PublicClient } from 'niljs';
*
* const client = new PublicClient({
* endpoint: 'http://127.0.0.1:8529'
* })
*
* const count = await client.getTransactionCount(Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), 'latest');
* const count = await client.getMessageCount(Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), 'latest');
*/
public async getTransactionCount(
public async getMessageCount(
address: Uint8Array,
blockNumberOrHash: string,
): Promise<number> {
const res = await this.rpcClient.request({
method: "eth_getTransactionCount",
method: "eth_getMessageCount",
params: [address, blockNumberOrHash],
});

Expand Down
92 changes: 56 additions & 36 deletions src/clients/WalletClient.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import invariant from "tiny-invariant";
import { signedTransactionToSsz, transactionToSsz } from "../encoding/toSsz.js";
import { messageToSsz, signedMessageToSsz } from "../encoding/toSsz.js";
import type { ISigner } from "../signers/index.js";
import type { ITransaction } from "../types/ITransaction.js";
import { assertIsValidTransaction } from "../utils/assert.js";
import type { IMessage } from "../types/IMessage.js";
import { assertIsValidMessage } from "../utils/assert.js";
import { BaseClient } from "./BaseClient.js";
import type { IWalletClientConfig } from "./types/ClientConfigs.js";
import type { ISendTransactionOptions } from "./types/ISendTransactionOptions.js";
import type { ISendMessageOptions } from "./types/ISendMessageOptions.js";
import type { ISignMessageOptions } from "./types/ISignMessageOptions.js";

/**
* Wallet client is a class that allows you to interact with the network via JSON-RPC api.
Expand All @@ -27,68 +28,84 @@ class WalletClient extends BaseClient {
}

/**
* sendTransaction sends a transaction to the network.
* @param transaction - The transaction to send. It can be a raw transaction or a base transaction object.
* If the transaction is a raw transaction, it will be signed with the signer, that is passed in the constructor.
* @returns The hash of the transaction.
* sendMessage sends a message to the network.
* @param message - The message to send. It can be a raw message or a base message object.
* If the message is a raw message, it will be signed with the signer, that is passed in the constructor.
* @param options - The options to send a message.
* @returns The hash of the message.
* @example
* import { WalletClient } from 'niljs';
*
* const client = new WalletClient({
* endpoint: 'http://127.0.0.1:8529'
* })
*
* const transaction = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const hash = await client.sendTransaction(transaction);
* const message = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const hash = await client.sendMessage(message);
*/
public async sendTransaction(
transaction: ITransaction,
{ shouldValidate = true } = {} as ISendTransactionOptions,
public async sendMessage(
message: IMessage,
{ shouldValidate = true } = {} as ISendMessageOptions,
): Promise<Uint8Array> {
shouldValidate && assertIsValidTransaction(transaction);
shouldValidate && assertIsValidMessage(message);

const signedMessage = this.signMessage(message, {
shouldValidate: false,
});

return await this.sendRawMessage(signedMessage);
}

/**
* signMessage signs a message with the signer.
* @param message - The message to sign.
* @param options - The options to sign a message.
* @returns The signed message as Uint8Array.
*/
public signMessage(
message: IMessage,
{ shouldValidate = true } = {} as ISignMessageOptions,
): Uint8Array {
shouldValidate && assertIsValidMessage(message);

invariant(
this.signer !== undefined,
"Signer is required to sign a transaction. Please provide a signer in the constructor or use sendRawTransaction method.",
"Signer is required to sign a message. Please provide a signer in the constructor or use sendRawMessage method.",
);

const serializedTransaction = transactionToSsz(transaction);
const serializedMessage = messageToSsz(message);

invariant(
serializedTransaction !== undefined,
"Serialized transaction is required to sign a transaction.",
serializedMessage !== undefined,
"Serialized message is required to sign a message.",
);

const signature = this.signer.sign(serializedTransaction);
const signature = this.signer.sign(serializedMessage);

const signedTransaction = signedTransactionToSsz({
...transaction,
return signedMessageToSsz({
...message,
...signature,
});

return await this.sendRawTransaction(signedTransaction);
}

/**
* sendRawTransaction sends a raw transaction to the network.
* @param transaction - The transaction to send.
* @returns The hash of the transaction.
* sendRawMessage sends a raw message to the network.
* @param message - The message to send.
* @returns The hash of the message.
* @example
* import { WalletClient } from 'niljs';
*
* const client = new WalletClient({
* endpoint: 'http://127.0.0.1:8529'
* })
*
* const transaction = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const hash = await client.sendRawTransaction(transaction);
* const message = Uint8Array.from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
* const hash = await client.sendRawMessage(message);
*/
public async sendRawTransaction(
transaction: Uint8Array,
): Promise<Uint8Array> {
public async sendRawMessage(message: Uint8Array): Promise<Uint8Array> {
const res = await this.rpcClient.request({
method: "eth_sendRawTransaction",
params: [transaction],
method: "eth_sendRawMessage",
params: [message],
});

return res.hash;
Expand All @@ -97,7 +114,7 @@ class WalletClient extends BaseClient {
/**
* deployContract deploys a contract to the network.
* @param contract - The contract to deploy.
* @returns The hash of the transaction.
* @returns The hash of the message.
* @example
import { WalletClient } from 'niljs';
*
Expand All @@ -109,10 +126,13 @@ class WalletClient extends BaseClient {
* const hash = await client.deployContract(contract);
*/
public async deployContract(contract: Uint8Array): Promise<Uint8Array> {
const hash = await this.sendRawTransaction(contract);
const hash = await this.sendRawMessage(contract);
// there will be a method to get receipt by hash
// receipt - result of smart conract calling
// we should wait to receipts to be sure that transaction is included in the block
// we should wait to receipts to be sure that message is included in the block

// ! compiling smart contract to the bytecode shall not be included in this library
// it can be done by hardhat
return hash;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/clients/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from "./WalletClient.js";
export * from "./PublicClient.js";
export * from "./types/ClientConfigs.js";
export * from "./types/ISendTransactionOptions.js";
export * from "./types/ISendMessageOptions.js";
2 changes: 1 addition & 1 deletion src/clients/types/ClientConfigs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type IPublicClientConfig = IClientBaseConfig;

type IWalletClientConfig = IClientBaseConfig & {
/**
* The instance of signer is used to sign transactions and messages.
* The instance of signer is used to sign messages and messages.
* If not included in the config, messages should be signed before passing to the client.
* @example
* import { Signer } from 'niljs';
Expand Down
14 changes: 14 additions & 0 deletions src/clients/types/ISendMessageOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Options for sending a message.
*/
type ISendMessageOptions = {
/**
* If true, the message will be validated before sending.
* If the message is invalid, an error will be thrown.
* If false, the message will not be validated before sending.
* @default true
*/
shouldValidate?: boolean;
};

export type { ISendMessageOptions };
14 changes: 0 additions & 14 deletions src/clients/types/ISendTransactionOptions.ts

This file was deleted.

Loading

0 comments on commit 888d1b9

Please sign in to comment.