diff --git a/.changeset/chilly-bags-battle.md b/.changeset/chilly-bags-battle.md new file mode 100644 index 00000000..c57358bf --- /dev/null +++ b/.changeset/chilly-bags-battle.md @@ -0,0 +1,5 @@ +--- +"niljs": patch +--- + +Add commitlint config in typescript diff --git a/.changeset/sharp-owls-behave.md b/.changeset/sharp-owls-behave.md new file mode 100644 index 00000000..065dfcdf --- /dev/null +++ b/.changeset/sharp-owls-behave.md @@ -0,0 +1,5 @@ +--- +"niljs": patch +--- + +Add IReceipt and ILog interfaces diff --git a/.commitlintrc b/.commitlintrc deleted file mode 100644 index 577ab65b..00000000 --- a/.commitlintrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": ["@commitlint/config-conventional"], - "rules": { - "body-max-line-length": [0, "always", 100], - "footer-max-line-length": [0, "always", 100], - "footer-leading-blank": [0, "always", 100], - "references-empty": [2, "never"], - "type-empty": [0, "never"], - "subject-empty": [0, "never"] - } -} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c4c0698a..43265ce6 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -31,25 +31,25 @@ jobs: title: "Version Packages" commit: "version packages" - # publish: - # name: Publish - # needs: version-pull-request - # runs-on: ubuntu-latest - # permissions: - # contents: write - # id-token: write - # steps: - # - name: Clone repository - # uses: actions/checkout@v4 - # - name: Install dependencies - # uses: ./.github/actions/install-dependencies - # with: - # node_version: 20 - # - name: Publish to NPM - # uses: changesets/action@v1 - # with: - # createGithubReleases: true - # publish: "npm run changeset:publish" - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + publish: + name: Publish + needs: version-pull-request + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + steps: + - name: Clone repository + uses: actions/checkout@v4 + - name: Install dependencies + uses: ./.github/actions/install-dependencies + with: + node_version: 20 + - name: Publish to NPM + uses: changesets/action@v1 + with: + createGithubReleases: true + publish: "npm run changeset:publish" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/commitlint.config.ts b/commitlint.config.ts new file mode 100644 index 00000000..04fb3e98 --- /dev/null +++ b/commitlint.config.ts @@ -0,0 +1,17 @@ +import type { UserConfig } from "@commitlint/types"; + +const config = { + extends: ["@commitlint/config-conventional"], + rules: { + "body-max-line-length": [0, "always", 100], + "footer-max-line-length": [0, "always", 100], + "footer-leading-blank": [0, "always"], + "references-empty": [2, "never"], + "type-empty": [0, "never"], + "subject-empty": [0, "never"], + }, + ignores: [(message) => message.includes("version packages")], + defaultIgnores: false, +} satisfies UserConfig; + +export default config; diff --git a/src/clients/WalletClient.ts b/src/clients/WalletClient.ts index 4833ddc5..90c5409e 100644 --- a/src/clients/WalletClient.ts +++ b/src/clients/WalletClient.ts @@ -2,6 +2,7 @@ import invariant from "tiny-invariant"; import { messageToSsz, signedMessageToSsz } from "../encoding/toSsz.js"; import type { ISigner } from "../signers/index.js"; import type { IMessage } from "../types/IMessage.js"; +import type { IReceipt } from "../types/IReceipt.js"; import { assertIsValidMessage } from "../utils/assert.js"; import { BaseClient } from "./BaseClient.js"; import type { IWalletClientConfig } from "./types/ClientConfigs.js"; @@ -29,8 +30,7 @@ class WalletClient extends BaseClient { /** * 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 message - The message to send. It will be signed with the signer. * @param options - The options to send a message. * @returns The hash of the message. * @example @@ -127,12 +127,20 @@ class WalletClient extends BaseClient { */ public async deployContract(contract: Uint8Array): Promise { 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 message is included in the block + // there will be a method to get receipt by hash, but it is not implemented yet + // it will use kinda polling to get receipt asap + // mocking it for now: + const receipt: Partial = { + success: true, + }; // ! compiling smart contract to the bytecode shall not be included in this library // it can be done by hardhat + invariant( + receipt.success, + "Contract deployment failed. Please check the contract bytecode.", + ); + return hash; } } diff --git a/src/encoding/fromHex.ts b/src/encoding/fromHex.ts index 5ad81873..370346e5 100644 --- a/src/encoding/fromHex.ts +++ b/src/encoding/fromHex.ts @@ -2,6 +2,7 @@ import { type Hex, hexToBytes as hexToBytesNoble, } from "@noble/curves/abstract/utils"; +import { addHexPrefix } from "../index.js"; /** * Convert a hex string to bytes. @@ -42,4 +43,17 @@ const hexToString = (hex: Hex): string => { return Buffer.from(hex, "hex").toString("utf-8"); }; -export { hexToBytes, hexToNumber, hexToString }; +/** + * Convert a hex string to a bigint. + * @param hex - The hex string to convert to a bigint. + * @returns The bigint representation of the input. + */ +const hexToBigInt = (hex: Hex): bigint => { + if (typeof hex !== "string") { + return hexToBigInt(hex.toString()); + } + + return BigInt(addHexPrefix(hex)); +}; + +export { hexToBytes, hexToNumber, hexToString, hexToBigInt }; diff --git a/src/signers/LocalKeySigner.ts b/src/signers/LocalKeySigner.ts index 721a14e3..0ff58957 100644 --- a/src/signers/LocalKeySigner.ts +++ b/src/signers/LocalKeySigner.ts @@ -1,7 +1,7 @@ import { secp256k1 } from "@noble/curves/secp256k1"; import { toHex } from "../encoding/toHex.js"; import { assertIsHexString, assertIsValidPrivateKey } from "../utils/assert.js"; -import { getPublicKey } from "./getPublicKey.js"; +import { getPublicKey } from "./publicKey.js"; import type { ILocalKeySignerConfig } from "./types/ILocalKeySignerConfig.js"; import type { ISignature } from "./types/ISignature.js"; import type { ISigner } from "./types/ISigner.js"; diff --git a/src/signers/generatePrivateKey.ts b/src/signers/generatePrivateKey.ts deleted file mode 100644 index a0bbdcf6..00000000 --- a/src/signers/generatePrivateKey.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { Hex } from "@noble/curves/abstract/utils"; -import { secp256k1 } from "@noble/curves/secp256k1"; -import { toHex } from "../index.js"; - -/** - * Generate a new private key. - * @returns Hex - Private key - * @example - * const privateKey = generatePrivateKey(); - */ -const generatePrivateKey = (): Hex => toHex(secp256k1.utils.randomPrivateKey()); - -export { generatePrivateKey }; diff --git a/src/signers/getPublicKey.ts b/src/signers/getPublicKey.ts deleted file mode 100644 index 8c373225..00000000 --- a/src/signers/getPublicKey.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { type Hex, bytesToHex } from "@noble/curves/abstract/utils"; -import { secp256k1 } from "@noble/curves/secp256k1"; -import { addHexPrefix, removeHexPrefix } from "../index.js"; -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(removeHexPrefix(privateKey), false); - return addHexPrefix(bytesToHex(publicKey)); -}; - -export { getPublicKey }; diff --git a/src/signers/index.ts b/src/signers/index.ts index 7787b47b..1c7774bd 100644 --- a/src/signers/index.ts +++ b/src/signers/index.ts @@ -1,8 +1,7 @@ export * from "./LocalKeySigner.js"; -export * from "./verifySignature.js"; -export * from "./getPublicKey.js"; +export * from "./verifyMessage.js"; +export * from "./publicKey.js"; export * from "./types/ILocalKeySignerConfig.js"; export * from "./types/IPrivateKey.js"; export * from "./types/ISigner.js"; export * from "./types/ISignature.js"; -export * from "./generatePrivateKey.js"; diff --git a/src/signers/getPublicKey.test.ts b/src/signers/publicKey.test.ts similarity index 85% rename from src/signers/getPublicKey.test.ts rename to src/signers/publicKey.test.ts index f6c2fe6b..951e9e51 100644 --- a/src/signers/getPublicKey.test.ts +++ b/src/signers/publicKey.test.ts @@ -1,5 +1,5 @@ import { accounts } from "../../test/mocks/accounts.js"; -import { getPublicKey } from "./getPublicKey.js"; +import { getPublicKey } from "./publicKey.js"; test("getPublicKey", async ({ expect }) => { const account = accounts[0]; diff --git a/src/signers/publicKey.ts b/src/signers/publicKey.ts new file mode 100644 index 00000000..3387d2ad --- /dev/null +++ b/src/signers/publicKey.ts @@ -0,0 +1,34 @@ +import { type Hex, bytesToHex } from "@noble/curves/abstract/utils"; +import { secp256k1 } from "@noble/curves/secp256k1"; +import { + type ISignature, + addHexPrefix, + removeHexPrefix, + toHex, +} from "../index.js"; +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(removeHexPrefix(privateKey), false); + return addHexPrefix(bytesToHex(publicKey)); +}; + +/** + * Generate a new private key. + * @returns Hex - Private key + * @example + * const privateKey = generatePrivateKey(); + */ +const generatePrivateKey = (): Hex => toHex(secp256k1.utils.randomPrivateKey()); + +const recoverPublicKey = ( + messageHash: Hex | Uint8Array, + signature: ISignature, +) => { + // +}; + +export { getPublicKey, generatePrivateKey, recoverPublicKey }; diff --git a/src/signers/generatePrivateKey.test.ts b/src/signers/verifyMessage.test.ts similarity index 100% rename from src/signers/generatePrivateKey.test.ts rename to src/signers/verifyMessage.test.ts diff --git a/src/signers/verifyMessage.ts b/src/signers/verifyMessage.ts new file mode 100644 index 00000000..7102f446 --- /dev/null +++ b/src/signers/verifyMessage.ts @@ -0,0 +1,10 @@ +import type { Hex } from "@noble/curves/abstract/utils"; +import type { ISignature } from "./index.js"; + +const verifyMessage = async ( + signature: ISignature, + messageHash: Uint8Array, + fullPublicKey: Hex, +) => { + // +}; diff --git a/src/signers/verifySignature.test.ts b/src/signers/verifySignature.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/signers/verifySignature.ts b/src/signers/verifySignature.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/types/ILog.ts b/src/types/ILog.ts new file mode 100644 index 00000000..b9772248 --- /dev/null +++ b/src/types/ILog.ts @@ -0,0 +1,11 @@ +/** + * Log interface. + */ +type ILog = { + address: string; + topics: string[]; + data: string; + blockNumber: bigint; +}; + +export type { ILog }; diff --git a/src/types/IReceipt.ts b/src/types/IReceipt.ts new file mode 100644 index 00000000..4c761e77 --- /dev/null +++ b/src/types/IReceipt.ts @@ -0,0 +1,18 @@ +import type { ILog } from "./ILog.js"; + +/** + * Receipt interface. + */ +type IReceipt = { + success: boolean; + gasUsed: number; + bloom: string; + logs: ILog[]; + msgHash: string; + contractAddress: string; + blockHash: string; + blockNumber: bigint; + msgIndex: bigint; +}; + +export type { IReceipt }; diff --git a/src/types/index.ts b/src/types/index.ts index 7f85463c..741521d6 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,6 +1,5 @@ -export * from "../clients/types/ClientConfigs.js"; export * from "./IMessage.js"; -export * from "../signers/types/ISigner.js"; -export * from "../signers/types/IPrivateKey.js"; export * from "./IBlock.js"; -export * from "../signers/types/ILocalKeySignerConfig.js"; +export * from "./ISignedMessage.js"; +export * from "./IReceipt.js"; +export * from "./ILog.js"; diff --git a/src/utils/assert.ts b/src/utils/assert.ts index e4d34faf..15d4ff10 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -76,9 +76,22 @@ const assertIsValidMessage = (message: IMessage) => { ); }; +/** + * Checks if the address is valid. If the address is valid, it returns nothing. + * @param address - The address to check. + * @param message - The message to throw if the address is invalid. + */ +const assertIsAddress = (address: string, message?: string): void => { + invariant( + isAddress(address), + message ?? `Expected a valid address but got ${address}`, + ); +}; + export { assertIsBuffer, assertIsHexString, assertIsValidPrivateKey, assertIsValidMessage, + assertIsAddress, };