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

feat: add Bitcoin standard memo encoding example for bitSmiley and unit tests #196

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

ws4charlie
Copy link
Collaborator

@ws4charlie ws4charlie commented Nov 16, 2024

Added the Javascript files that showcase the Bitcoin memo encoding process.

This is a simplified implementation that enables the revertAddress option (bitSmiley needs this option). @fadeev you can refine and formalize the code (my JS skills are limited) to ship the API in whatever style you deem appropriate. Thanks in advance!

  • Added memo.js to provide standard memo encoding function EncodeToBytes
  • Added memo.test.js to unit test the memo encoding. I used command node memo.test.js to run the tests.

Summary by CodeRabbit

  • New Features

    • Introduced a new encoding functionality for blockchain-related operations.
    • Added a comprehensive test suite for memo encoding with multiple encoding formats.
    • Implemented a GitHub Actions workflow for automated testing.
  • Bug Fixes

    • Enhanced validation for memo encoding to prevent unsupported formats and excessive lengths.
  • Documentation

    • Updated testing capabilities with a new script for running tests.
  • Chores

    • Added new development dependencies for improved TypeScript testing support.

Copy link
Contributor

coderabbitai bot commented Nov 16, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

This pull request introduces several changes, including the addition of a new test file (memo.test.js) for memo encoding functionality, updates to the package.json file to enhance testing capabilities, and the introduction of a GitHub Actions workflow (test.yaml) for automated testing. Additionally, a new configuration file for Jest (jest.config.ts) is added to support TypeScript testing. The encoding functionality is encapsulated in a new module (encodeToBytes.ts), which includes classes and enumerations for encoding operations. Finally, the main index file is updated to export the new encoding functionalities.

Changes

File Change Summary
memo.test.js Introduced a test suite for memo encoding with three test functions validating different encoding formats.
package.json Added a test script, updated dependencies, and introduced new development dependencies for TypeScript testing.
.github/workflows/test.yaml Added a new GitHub Actions workflow for automated testing on pull requests.
jest.config.ts Introduced Jest configuration for TypeScript, specifying the test environment and file matching patterns.
packages/client/src/encodeToBytes.ts Added functionality for encoding data into byte arrays with classes and enums for operation types and encoding formats.
packages/client/src/index.ts Updated to export all entities from the encodeToBytes module.
test/memo.test.ts Introduced a new test suite for memo encoding using Jest, validating the encoding logic with expected hexadecimal values.

Suggested reviewers

  • andresaiello
  • GMaiolo

📜 Recent review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 951044d and 0d8fa3e.

⛔ Files ignored due to path filters (10)
  • typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.ts is excluded by !typechain-types/**
  • typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.ts is excluded by !typechain-types/**
  • typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.ts is excluded by !typechain-types/**
  • typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts is excluded by !typechain-types/**
  • typechain-types/@openzeppelin/contracts/interfaces/index.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/interfaces/index.ts is excluded by !typechain-types/**
📒 Files selected for processing (1)
  • packages/client/src/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/client/src/index.ts

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@ws4charlie ws4charlie changed the title feat: added Bitcoin standard memo encoding API for bitSmiley and unit tests DON'T Merge: add Bitcoin standard memo encoding example for bitSmiley and unit tests Nov 16, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Outside diff range and nitpick comments (9)
memo.test.js (1)

1-4: Consider modernizing the imports and optimizing Web3 usage

The code could benefit from the following improvements:

  1. Use ES modules (import/export) instead of CommonJS require
  2. Import only the required utility from Web3 instead of the entire library
-var assert = require("assert");
-const { Header, FieldsV0, EncodingFormat, OpCode, EncodeToBytes } = require('./memo');
-const { Web3 } = require('web3');
-const web3 = new Web3();
+import assert from 'assert';
+import { Header, FieldsV0, EncodingFormat, OpCode, EncodeToBytes } from './memo';
+import { bytesToHex } from 'web3-utils';
🧰 Tools
🪛 eslint

[error] 2-2: Replace ·Header,·FieldsV0,·EncodingFormat,·OpCode,·EncodeToBytes·}·=·require('./memo' with ⏎··Header,⏎··FieldsV0,⏎··EncodingFormat,⏎··OpCode,⏎··EncodeToBytes,⏎}·=·require("./memo"

(prettier/prettier)


[error] 3-3: Replace 'web3' with "web3"

(prettier/prettier)

package.json (1)

119-119: Consider the necessity of adding web3.js alongside ethers.js.

The addition of web3.js v4.15.0 alongside ethers.js creates dependency overlap as both libraries serve similar purposes for Ethereum interaction. This could lead to:

  1. Increased bundle size
  2. Inconsistent implementations across the codebase
  3. Additional maintenance overhead

Consider standardizing on one library:

  • If the new memo encoding functionality specifically requires web3.js features, consider migrating other ethers.js code to web3.js
  • If not, consider implementing the memo encoding using ethers.js to maintain consistency

Would you like assistance in evaluating which library better suits your needs or help in refactoring the memo implementation to use ethers.js?

memo.js (7)

34-36: Simplify address validation with web3.utils.isAddress

After updating the import, you can directly use isAddress from web3.utils without relying on external validators.

🧰 Tools
🪛 eslint

[error] 34-34: Replace ········ with ····

(prettier/prettier)


[error] 35-35: Delete ······

(prettier/prettier)


[error] 36-36: Replace ········ with ····

(prettier/prettier)


10-15: Sort keys in the OpCode enum for readability

Reordering the keys in the OpCode enum alphabetically improves readability and adheres to style guidelines.

Apply this diff:

 const OpCode = Object.freeze({
+    Call: 0b0010,
     Deposit: 0b0000,
     DepositAndCall: 0b0001,
-    Call: 0b0010,
     Invalid: 0b0011,
 });

Ensure that reordering does not affect the intended behavior of your code.

🧰 Tools
🪛 GitHub Check: build

[failure] 11-11:
Delete ··


[failure] 12-12:
Delete ··


[failure] 13-13:
Replace ···· with ··


[failure] 13-13:
Expected object keys to be in ascending order. 'Call' should be before 'DepositAndCall'


[failure] 14-14:
Delete ··

🪛 eslint

[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Delete ··

(prettier/prettier)


[error] 13-13: Replace ···· with ··

(prettier/prettier)


[error] 13-13: Expected object keys to be in ascending order. 'Call' should be before 'DepositAndCall'.

(sort-keys-fix/sort-keys-fix)


[error] 14-14: Delete ··

(prettier/prettier)


17-21: Sort keys in the EncodingFormat enum for readability

Similarly, reordering the keys in the EncodingFormat enum enhances readability.

Apply this diff:

 const EncodingFormat = Object.freeze({
     EncodingFmtABI: 0b0000,
-    EncodingFmtCompactShort: 0b0001,
-    EncodingFmtCompactLong: 0b0010,
+    EncodingFmtCompactLong: 0b0010,
+    EncodingFmtCompactShort: 0b0001,
 });
🧰 Tools
🪛 GitHub Check: build

[failure] 18-18:
Delete ··


[failure] 19-19:
Delete ··

🪛 eslint

[error] 18-18: Delete ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 20-20: Expected object keys to be in ascending order. 'EncodingFmtCompactLong' should be before 'EncodingFmtCompactShort'.

(sort-keys-fix/sort-keys-fix)


52-53: Use consistent lowercase in hexadecimal values

For consistency, use lowercase letters in hexadecimal literals.

Apply this diff:

-    headerBytes[1] = (0x00 << 4) | (header.encodingFmt & 0x0F);
-    headerBytes[2] = ((header.opCode & 0x0F) << 4) | 0x00;
+    headerBytes[1] = (0x00 << 4) | (header.encodingFmt & 0x0f);
+    headerBytes[2] = ((header.opCode & 0x0f) << 4) | 0x00;
🧰 Tools
🪛 eslint

[error] 52-52: Replace ····headerBytes[1]·=·(0x00·<<·4)·|·(header.encodingFmt·&·0x0F with ··headerBytes[1]·=·(0x00·<<·4)·|·(header.encodingFmt·&·0x0f

(prettier/prettier)


[error] 53-53: Replace ····headerBytes[2]·=·((header.opCode·&·0x0F with ··headerBytes[2]·=·((header.opCode·&·0x0f

(prettier/prettier)


117-117: Reorder exports in module.exports for consistency

Organizing exported entities alphabetically improves maintainability.

Apply this diff:

-module.exports = { Header, FieldsV0, EncodingFormat, OpCode, EncodeToBytes };
+module.exports = { EncodeToBytes, EncodingFormat, FieldsV0, Header, OpCode };
🧰 Tools
🪛 eslint

[error] 117-117: Expected object keys to be in ascending order. 'FieldsV0' should be before 'Header'.

(sort-keys-fix/sort-keys-fix)


[error] 117-117: Expected object keys to be in ascending order. 'EncodingFormat' should be before 'FieldsV0'.

(sort-keys-fix/sort-keys-fix)


[error] 117-117: Expected object keys to be in ascending order. 'EncodeToBytes' should be before 'OpCode'.

(sort-keys-fix/sort-keys-fix)


1-117: Fix formatting issues as per static analysis

Several formatting inconsistencies were detected. Please run your code through a formatter like Prettier to adhere to style guidelines.

🧰 Tools
🪛 GitHub Check: build

[failure] 1-1:
Replace 'web3' with "web3"


[failure] 4-4:
Replace 'web3-validator' with "web3-validator"


[failure] 7-7:
Replace A with a


[failure] 11-11:
Delete ··


[failure] 12-12:
Delete ··


[failure] 13-13:
Replace ···· with ··


[failure] 13-13:
Expected object keys to be in ascending order. 'Call' should be before 'DepositAndCall'


[failure] 14-14:
Delete ··


[failure] 18-18:
Delete ··


[failure] 19-19:
Delete ··


[warning] 44-44:
Use const or class constructors instead of named functions


[warning] 75-75:
Use const or class constructors instead of named functions


[warning] 83-83:
Use const or class constructors instead of named functions


[warning] 92-92:
Use const or class constructors instead of named functions

🪛 eslint

[error] 1-1: Replace 'web3' with "web3"

(prettier/prettier)


[error] 4-4: Replace 'web3-validator' with "web3-validator"

(prettier/prettier)


[error] 7-7: Replace A with a

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Delete ··

(prettier/prettier)


[error] 13-13: Replace ···· with ··

(prettier/prettier)


[error] 13-13: Expected object keys to be in ascending order. 'Call' should be before 'DepositAndCall'.

(sort-keys-fix/sort-keys-fix)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 18-18: Delete ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 20-20: Expected object keys to be in ascending order. 'EncodingFmtCompactLong' should be before 'EncodingFmtCompactShort'.

(sort-keys-fix/sort-keys-fix)


[error] 25-25: Replace ···· with ··

(prettier/prettier)


[error] 26-26: Delete ····

(prettier/prettier)


[error] 27-27: Delete ····

(prettier/prettier)


[error] 28-28: Replace ···· with ··

(prettier/prettier)


[error] 33-33: Delete ··

(prettier/prettier)


[error] 34-34: Replace ········ with ····

(prettier/prettier)


[error] 35-35: Delete ······

(prettier/prettier)


[error] 36-36: Replace ········ with ····

(prettier/prettier)


[error] 37-37: Delete ····

(prettier/prettier)


[error] 38-38: Replace ········ with ····

(prettier/prettier)


[error] 39-39: Delete ····

(prettier/prettier)


[error] 40-40: Delete ··

(prettier/prettier)


[error] 44-72: Expected a function expression.

(func-style)


[error] 45-45: Delete ··

(prettier/prettier)


[error] 46-46: Replace ········ with ····

(prettier/prettier)


[error] 47-47: Delete ··

(prettier/prettier)


[error] 49-49: Delete ··

(prettier/prettier)


[error] 50-50: Delete ··

(prettier/prettier)


[error] 51-51: Delete ··

(prettier/prettier)


[error] 52-52: Replace ····headerBytes[1]·=·(0x00·<<·4)·|·(header.encodingFmt·&·0x0F with ··headerBytes[1]·=·(0x00·<<·4)·|·(header.encodingFmt·&·0x0f

(prettier/prettier)


[error] 53-53: Replace ····headerBytes[2]·=·((header.opCode·&·0x0F with ··headerBytes[2]·=·((header.opCode·&·0x0f

(prettier/prettier)


[error] 54-54: Delete ··

(prettier/prettier)


[error] 56-56: Delete ··

(prettier/prettier)


[error] 57-57: Replace ···· with ··

(prettier/prettier)


[error] 58-58: Delete ··

(prettier/prettier)


[error] 59-59: Replace ········ with ····

(prettier/prettier)


[error] 60-60: Delete ······

(prettier/prettier)


[error] 61-61: Replace ············ with ······

(prettier/prettier)


[error] 62-62: Delete ····

(prettier/prettier)


[error] 63-63: Replace ········ with ····

(prettier/prettier)


[error] 64-64: Delete ······

(prettier/prettier)


[error] 65-65: Delete ······

(prettier/prettier)


[error] 66-66: Delete ····

(prettier/prettier)


[error] 67-67: Delete ······

(prettier/prettier)


[error] 68-68: Delete ··

(prettier/prettier)


[error] 70-70: Delete ··

(prettier/prettier)


[error] 71-71: Replace ··return·new·Uint8Array(Buffer.concat([Buffer.from(headerBytes),·Buffer.from(encodedFields)]) with return·new·Uint8Array(⏎····Buffer.concat([Buffer.from(headerBytes),·Buffer.from(encodedFields)])⏎··

(prettier/prettier)


[error] 75-80: Expected a function expression.

(func-style)


[error] 76-76: Delete ··

(prettier/prettier)


[error] 77-77: Delete ··

(prettier/prettier)


[error] 78-78: Delete ··

(prettier/prettier)


[error] 79-79: Delete ··

(prettier/prettier)


[error] 83-89: Expected a function expression.

(func-style)


[error] 84-84: Replace ···· with ··

(prettier/prettier)


[error] 85-85: Delete ··

(prettier/prettier)


[error] 86-86: Replace ····const·encodedRevertAddress·=·encodeDataCompact(compactFmt,·new·TextEncoder().encode(fields.revertAddress) with ··const·encodedRevertAddress·=·encodeDataCompact(⏎····compactFmt,⏎····new·TextEncoder().encode(fields.revertAddress)⏎··

(prettier/prettier)


[error] 88-88: Replace ····return·new·Uint8Array(Buffer.concat([encodedReceiver,·encodedPayload,·encodedRevertAddress]) with ··return·new·Uint8Array(⏎····Buffer.concat([encodedReceiver,·encodedPayload,·encodedRevertAddress])⏎··

(prettier/prettier)


[error] 92-115: Expected a function expression.

(func-style)


[error] 93-93: Delete ··

(prettier/prettier)


[error] 94-94: Delete ··

(prettier/prettier)


[error] 96-96: Replace ···· with ··

(prettier/prettier)


[error] 97-97: Replace ········ with ····

(prettier/prettier)


[error] 98-98: Replace ············ with ······

(prettier/prettier)


[error] 99-99: Replace ················throw·new·Error("Data·length·exceeds·255·bytes·for·EncodingFmtCompactShort"); with ········throw·new·Error(⏎··········"Data·length·exceeds·255·bytes·for·EncodingFmtCompactShort"

(prettier/prettier)


[error] 100-100: Replace ····} with );

(prettier/prettier)


[error] 101-101: Insert }⏎

(prettier/prettier)


[error] 102-102: Replace ············ with ······

(prettier/prettier)


[error] 103-103: Delete ····

(prettier/prettier)


[error] 104-104: Replace ············ with ······

(prettier/prettier)


[error] 105-105: Replace ········throw·new·Error("Data·length·exceeds·65535·bytes·for·EncodingFmtCompactLong"); with throw·new·Error(⏎··········"Data·length·exceeds·65535·bytes·for·EncodingFmtCompactLong"

(prettier/prettier)


[error] 106-106: Replace ····} with );

(prettier/prettier)


[error] 107-107: Insert }⏎

(prettier/prettier)


[error] 108-108: Delete ······

(prettier/prettier)


[error] 109-109: Replace ············ with ······

(prettier/prettier)


[error] 110-110: Replace ········ with ····

(prettier/prettier)


[error] 111-111: Delete ······

(prettier/prettier)


[error] 112-112: Delete ··

(prettier/prettier)


[error] 114-114: Delete ··

(prettier/prettier)


[error] 117-117: Expected object keys to be in ascending order. 'FieldsV0' should be before 'Header'.

(sort-keys-fix/sort-keys-fix)


[error] 117-117: Expected object keys to be in ascending order. 'EncodingFormat' should be before 'FieldsV0'.

(sort-keys-fix/sort-keys-fix)


[error] 117-117: Expected object keys to be in ascending order. 'EncodeToBytes' should be before 'OpCode'.

(sort-keys-fix/sort-keys-fix)


45-47: Enhance error messages in EncodeToBytes function

Providing specific error messages can aid in debugging and improve clarity.

Apply this diff:

-        throw new Error("Header and fields are required");
+        if (!header) {
+            throw new Error("Header is required");
+        }
+        if (!fields) {
+            throw new Error("Fields are required");
+        }
🧰 Tools
🪛 eslint

[error] 45-45: Delete ··

(prettier/prettier)


[error] 46-46: Replace ········ with ····

(prettier/prettier)


[error] 47-47: Delete ··

(prettier/prettier)

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 78fa8d7 and 06c81bb.

📒 Files selected for processing (3)
  • memo.js (1 hunks)
  • memo.test.js (1 hunks)
  • package.json (2 hunks)
🧰 Additional context used
🪛 GitHub Check: build
memo.js

[failure] 1-1:
Replace 'web3' with "web3"


[failure] 4-4:
Replace 'web3-validator' with "web3-validator"


[failure] 7-7:
Replace A with a


[failure] 11-11:
Delete ··


[failure] 12-12:
Delete ··


[failure] 13-13:
Replace ···· with ··


[failure] 13-13:
Expected object keys to be in ascending order. 'Call' should be before 'DepositAndCall'


[failure] 14-14:
Delete ··


[failure] 18-18:
Delete ··


[failure] 19-19:
Delete ··


[warning] 44-44:
Use const or class constructors instead of named functions


[warning] 75-75:
Use const or class constructors instead of named functions


[warning] 83-83:
Use const or class constructors instead of named functions


[warning] 92-92:
Use const or class constructors instead of named functions

memo.test.js

[warning] 12-12:
Use const or class constructors instead of named functions


[warning] 40-40:
Use const or class constructors instead of named functions


[warning] 64-64:
Use const or class constructors instead of named functions

🪛 eslint
memo.js

[error] 1-1: Replace 'web3' with "web3"

(prettier/prettier)


[error] 4-4: Replace 'web3-validator' with "web3-validator"

(prettier/prettier)


[error] 7-7: Replace A with a

(prettier/prettier)


[error] 11-11: Delete ··

(prettier/prettier)


[error] 12-12: Delete ··

(prettier/prettier)


[error] 13-13: Replace ···· with ··

(prettier/prettier)


[error] 13-13: Expected object keys to be in ascending order. 'Call' should be before 'DepositAndCall'.

(sort-keys-fix/sort-keys-fix)


[error] 14-14: Delete ··

(prettier/prettier)


[error] 18-18: Delete ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 20-20: Expected object keys to be in ascending order. 'EncodingFmtCompactLong' should be before 'EncodingFmtCompactShort'.

(sort-keys-fix/sort-keys-fix)


[error] 25-25: Replace ···· with ··

(prettier/prettier)


[error] 26-26: Delete ····

(prettier/prettier)


[error] 27-27: Delete ····

(prettier/prettier)


[error] 28-28: Replace ···· with ··

(prettier/prettier)


[error] 33-33: Delete ··

(prettier/prettier)


[error] 34-34: Replace ········ with ····

(prettier/prettier)


[error] 35-35: Delete ······

(prettier/prettier)


[error] 36-36: Replace ········ with ····

(prettier/prettier)


[error] 37-37: Delete ····

(prettier/prettier)


[error] 38-38: Replace ········ with ····

(prettier/prettier)


[error] 39-39: Delete ····

(prettier/prettier)


[error] 40-40: Delete ··

(prettier/prettier)


[error] 44-72: Expected a function expression.

(func-style)


[error] 45-45: Delete ··

(prettier/prettier)


[error] 46-46: Replace ········ with ····

(prettier/prettier)


[error] 47-47: Delete ··

(prettier/prettier)


[error] 49-49: Delete ··

(prettier/prettier)


[error] 50-50: Delete ··

(prettier/prettier)


[error] 51-51: Delete ··

(prettier/prettier)


[error] 52-52: Replace ····headerBytes[1]·=·(0x00·<<·4)·|·(header.encodingFmt·&·0x0F with ··headerBytes[1]·=·(0x00·<<·4)·|·(header.encodingFmt·&·0x0f

(prettier/prettier)


[error] 53-53: Replace ····headerBytes[2]·=·((header.opCode·&·0x0F with ··headerBytes[2]·=·((header.opCode·&·0x0f

(prettier/prettier)


[error] 54-54: Delete ··

(prettier/prettier)


[error] 56-56: Delete ··

(prettier/prettier)


[error] 57-57: Replace ···· with ··

(prettier/prettier)


[error] 58-58: Delete ··

(prettier/prettier)


[error] 59-59: Replace ········ with ····

(prettier/prettier)


[error] 60-60: Delete ······

(prettier/prettier)


[error] 61-61: Replace ············ with ······

(prettier/prettier)


[error] 62-62: Delete ····

(prettier/prettier)


[error] 63-63: Replace ········ with ····

(prettier/prettier)


[error] 64-64: Delete ······

(prettier/prettier)


[error] 65-65: Delete ······

(prettier/prettier)


[error] 66-66: Delete ····

(prettier/prettier)


[error] 67-67: Delete ······

(prettier/prettier)


[error] 68-68: Delete ··

(prettier/prettier)


[error] 70-70: Delete ··

(prettier/prettier)


[error] 71-71: Replace ··return·new·Uint8Array(Buffer.concat([Buffer.from(headerBytes),·Buffer.from(encodedFields)]) with return·new·Uint8Array(⏎····Buffer.concat([Buffer.from(headerBytes),·Buffer.from(encodedFields)])⏎··

(prettier/prettier)


[error] 75-80: Expected a function expression.

(func-style)


[error] 76-76: Delete ··

(prettier/prettier)


[error] 77-77: Delete ··

(prettier/prettier)


[error] 78-78: Delete ··

(prettier/prettier)


[error] 79-79: Delete ··

(prettier/prettier)


[error] 83-89: Expected a function expression.

(func-style)


[error] 84-84: Replace ···· with ··

(prettier/prettier)


[error] 85-85: Delete ··

(prettier/prettier)


[error] 86-86: Replace ····const·encodedRevertAddress·=·encodeDataCompact(compactFmt,·new·TextEncoder().encode(fields.revertAddress) with ··const·encodedRevertAddress·=·encodeDataCompact(⏎····compactFmt,⏎····new·TextEncoder().encode(fields.revertAddress)⏎··

(prettier/prettier)


[error] 88-88: Replace ····return·new·Uint8Array(Buffer.concat([encodedReceiver,·encodedPayload,·encodedRevertAddress]) with ··return·new·Uint8Array(⏎····Buffer.concat([encodedReceiver,·encodedPayload,·encodedRevertAddress])⏎··

(prettier/prettier)


[error] 92-115: Expected a function expression.

(func-style)


[error] 93-93: Delete ··

(prettier/prettier)


[error] 94-94: Delete ··

(prettier/prettier)


[error] 96-96: Replace ···· with ··

(prettier/prettier)


[error] 97-97: Replace ········ with ····

(prettier/prettier)


[error] 98-98: Replace ············ with ······

(prettier/prettier)


[error] 99-99: Replace ················throw·new·Error("Data·length·exceeds·255·bytes·for·EncodingFmtCompactShort"); with ········throw·new·Error(⏎··········"Data·length·exceeds·255·bytes·for·EncodingFmtCompactShort"

(prettier/prettier)


[error] 100-100: Replace ····} with );

(prettier/prettier)


[error] 101-101: Insert }⏎

(prettier/prettier)


[error] 102-102: Replace ············ with ······

(prettier/prettier)


[error] 103-103: Delete ····

(prettier/prettier)


[error] 104-104: Replace ············ with ······

(prettier/prettier)


[error] 105-105: Replace ········throw·new·Error("Data·length·exceeds·65535·bytes·for·EncodingFmtCompactLong"); with throw·new·Error(⏎··········"Data·length·exceeds·65535·bytes·for·EncodingFmtCompactLong"

(prettier/prettier)


[error] 106-106: Replace ····} with );

(prettier/prettier)


[error] 107-107: Insert }⏎

(prettier/prettier)


[error] 108-108: Delete ······

(prettier/prettier)


[error] 109-109: Replace ············ with ······

(prettier/prettier)


[error] 110-110: Replace ········ with ····

(prettier/prettier)


[error] 111-111: Delete ······

(prettier/prettier)


[error] 112-112: Delete ··

(prettier/prettier)


[error] 114-114: Delete ··

(prettier/prettier)


[error] 117-117: Expected object keys to be in ascending order. 'FieldsV0' should be before 'Header'.

(sort-keys-fix/sort-keys-fix)


[error] 117-117: Expected object keys to be in ascending order. 'EncodingFormat' should be before 'FieldsV0'.

(sort-keys-fix/sort-keys-fix)


[error] 117-117: Expected object keys to be in ascending order. 'EncodeToBytes' should be before 'OpCode'.

(sort-keys-fix/sort-keys-fix)

memo.test.js

[error] 2-2: Replace ·Header,·FieldsV0,·EncodingFormat,·OpCode,·EncodeToBytes·}·=·require('./memo' with ⏎··Header,⏎··FieldsV0,⏎··EncodingFormat,⏎··OpCode,⏎··EncodeToBytes,⏎}·=·require("./memo"

(prettier/prettier)


[error] 3-3: Replace 'web3' with "web3"

(prettier/prettier)


[error] 12-37: Expected a function expression.

(func-style)


[error] 13-13: Delete ··

(prettier/prettier)


[error] 14-14: Replace ····const·header·=·new·Header(EncodingFormat.EncodingFmtABI,·OpCode.DepositAndCall with ··const·header·=·new·Header(⏎····EncodingFormat.EncodingFmtABI,⏎····OpCode.DepositAndCall⏎··

(prettier/prettier)


[error] 16-16: Delete ··

(prettier/prettier)


[error] 17-17: Replace ···· with ··

(prettier/prettier)


[error] 19-19: Delete ··

(prettier/prettier)


[error] 20-20: Delete ··

(prettier/prettier)


[error] 21-21: Delete ··

(prettier/prettier)


[error] 23-23: Delete ··

(prettier/prettier)


[error] 24-24: Replace ····const·expectedHex·=·'5a001007' with ··const·expectedHex·=⏎····"5a001007"

(prettier/prettier)


[error] 25-25: Replace ········'000000000000000000000000ea9808f0ac504d1f521b5bbdfc33e6f1953757a7' with ····"000000000000000000000000ea9808f0ac504d1f521b5bbdfc33e6f1953757a7"

(prettier/prettier)


[error] 26-26: Replace ········'0000000000000000000000000000000000000000000000000000000000000060' with ····"0000000000000000000000000000000000000000000000000000000000000060"

(prettier/prettier)


[error] 27-27: Replace ····'00000000000000000000000000000000000000000000000000000000000000a0' with "00000000000000000000000000000000000000000000000000000000000000a0"

(prettier/prettier)


[error] 28-28: Replace ········'0000000000000000000000000000000000000000000000000000000000000009' with ····"0000000000000000000000000000000000000000000000000000000000000009"

(prettier/prettier)


[error] 29-29: Replace ····'61207061796c6f61640000000000000000000000000000000000000000000000' with "61207061796c6f61640000000000000000000000000000000000000000000000"

(prettier/prettier)


[error] 30-30: Replace ········'000000000000000000000000000000000000000000000000000000000000002a' with ····"000000000000000000000000000000000000000000000000000000000000002a"

(prettier/prettier)


[error] 31-31: Replace ········'746231713672756667366d7972787572646e3068353764327168746d397a666d6a77326d7a636d30357100000000000000000000000000000000000000000000' with ····"746231713672756667366d7972787572646e3068353764327168746d397a666d6a77326d7a636d30357100000000000000000000000000000000000000000000"

(prettier/prettier)


[error] 33-33: Delete ··

(prettier/prettier)


[error] 34-34: Replace ··assert.strictEqual(encodedMemoHex,·expectedHex,·'ABI·encoding·failed:·encoded·bytes·do·not·match·expected' with assert.strictEqual(⏎····encodedMemoHex,⏎····expectedHex,⏎····"ABI·encoding·failed:·encoded·bytes·do·not·match·expected"⏎··

(prettier/prettier)


[error] 36-36: Replace ···· with ··

(prettier/prettier)


[error] 40-61: Expected a function expression.

(func-style)


[error] 41-41: Delete ··

(prettier/prettier)


[error] 42-42: Replace ····const·header·=·new·Header(EncodingFormat.EncodingFmtCompactShort,·OpCode.DepositAndCall with ··const·header·=·new·Header(⏎····EncodingFormat.EncodingFmtCompactShort,⏎····OpCode.DepositAndCall⏎··

(prettier/prettier)


[error] 44-44: Delete ··

(prettier/prettier)


[error] 45-45: Delete ··

(prettier/prettier)


[error] 47-47: Delete ··

(prettier/prettier)


[error] 48-48: Replace ···· with ··

(prettier/prettier)


[error] 49-49: Delete ··

(prettier/prettier)


[error] 51-51: Delete ··

(prettier/prettier)


[error] 52-52: Replace ··const·expectedHex·=·'5a011007' with const·expectedHex·=⏎····"5a011007"

(prettier/prettier)


[error] 53-53: Replace ····'ea9808f0ac504d1f521b5bbdfc33e6f1953757a7' with "ea9808f0ac504d1f521b5bbdfc33e6f1953757a7"

(prettier/prettier)


[error] 54-54: Replace ········'0961207061796c6f6164' with ····"0961207061796c6f6164"

(prettier/prettier)


[error] 55-55: Replace ····'2a746231713672756667366d7972787572646e3068353764327168746d397a666d6a77326d7a636d303571' with "2a746231713672756667366d7972787572646e3068353764327168746d397a666d6a77326d7a636d303571"

(prettier/prettier)


[error] 57-57: Delete ··

(prettier/prettier)


[error] 58-58: Replace ··assert.strictEqual(encodedMemoHex,·expectedHex,·'Compact·short·encoding·failed:·encoded·bytes·do·not·match·expected' with assert.strictEqual(⏎····encodedMemoHex,⏎····expectedHex,⏎····"Compact·short·encoding·failed:·encoded·bytes·do·not·match·expected"⏎··

(prettier/prettier)


[error] 60-60: Delete ··

(prettier/prettier)


[error] 64-85: Expected a function expression.

(func-style)


[error] 65-65: Delete ··

(prettier/prettier)


[error] 66-66: Replace ····const·header·=·new·Header(EncodingFormat.EncodingFmtCompactLong,·OpCode.DepositAndCall with ··const·header·=·new·Header(⏎····EncodingFormat.EncodingFmtCompactLong,⏎····OpCode.DepositAndCall⏎··

(prettier/prettier)


[error] 68-68: Delete ··

(prettier/prettier)


[error] 69-69: Replace ···· with ··

(prettier/prettier)


[error] 71-71: Delete ··

(prettier/prettier)


[error] 72-72: Delete ··

(prettier/prettier)


[error] 73-73: Delete ··

(prettier/prettier)


[error] 75-75: Delete ··

(prettier/prettier)


[error] 76-76: Replace ····const·expectedHex·=·'5a021007' with ··const·expectedHex·=⏎····"5a021007"

(prettier/prettier)


[error] 77-77: Replace ········'ea9808f0ac504d1f521b5bbdfc33e6f1953757a7' with ····"ea9808f0ac504d1f521b5bbdfc33e6f1953757a7"

(prettier/prettier)


[error] 78-78: Replace ····'090061207061796c6f6164' with "090061207061796c6f6164"

(prettier/prettier)


[error] 79-79: Replace ····'2a00746231713672756667366d7972787572646e3068353764327168746d397a666d6a77326d7a636d303571' with "2a00746231713672756667366d7972787572646e3068353764327168746d397a666d6a77326d7a636d303571"

(prettier/prettier)


[error] 81-81: Delete ··

(prettier/prettier)


[error] 82-82: Replace ····assert.strictEqual(encodedMemoHex,·expectedHex,·'Compact·long·encoding·failed:·encoded·bytes·do·not·match·expected' with ··assert.strictEqual(⏎····encodedMemoHex,⏎····expectedHex,⏎····"Compact·long·encoding·failed:·encoded·bytes·do·not·match·expected"⏎··

(prettier/prettier)


[error] 84-84: Delete ··

(prettier/prettier)

🔇 Additional comments (3)
package.json (2)

108-108: Verify the impact of allowing minor version updates for ethers.

While allowing minor updates can bring bug fixes, it might also introduce subtle breaking changes. The current ethers v5.4.7 is stable and widely tested.

#!/bin/bash
# Check for known vulnerabilities in ethers v5.4.x versions
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "ethers") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

# List all v5.4.x versions to evaluate the update range
npm view ethers@"^5.4.7" version

108-108: Verify compatibility between ethers.js and web3.js versions.

Since both libraries will be used together in the memo encoding implementation, we should verify their compatibility and any potential conflicts.

Also applies to: 119-119

✅ Verification successful

Let me gather more information about web3.js usage and version to properly verify the compatibility.


Based on the search results, I can see that both ethers.js v5.4.7 and web3.js v4.15.0 are used in the memo encoding implementation (memo.js). Let me verify their specific usage and compatibility:


After analyzing the code and library usage, I can now provide a definitive response about the compatibility:

The libraries are used independently and compatibly in the memo encoding implementation

The code shows clear separation of concerns where each library is used for distinct purposes:

  • web3.js (v4.15.0) is used for basic utilities like hexToBytes and address validation
  • ethers.js (v5.4.7) is used specifically for ABI encoding in the encodeFieldsABI function

There are no overlapping functionalities or potential conflicts between the libraries as they handle different aspects of the implementation. The code is well-structured to use each library's strengths:

  • web3-validator for address validation
  • web3.utils for byte manipulation
  • ethers.utils for ABI encoding
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential conflicts in import statements
rg -g '*.{js,ts}' -A 2 'import.*web3|import.*ethers' 

# Look for files using both libraries together
rg -l 'web3.*ethers|ethers.*web3'

# Check if memo.js uses both libraries
rg -g 'memo.js' 'import.*web3|import.*ethers'

Length of output: 772


Script:

#!/bin/bash
# Check web3.js version in package.json
rg '"web3":\s*"[^"]*"' package.json

# Search for actual usage of both libraries together in code
rg -g '*.{js,ts}' -C 3 'const.*ethers|import.*ethers'
rg -g '*.{js,ts}' -C 3 'const.*[Ww]eb3|import.*[Ww]eb3'

# Look for any memo-related files
fd -g '*memo*.{js,ts}'

Length of output: 139706


Script:

#!/bin/bash
# Check the actual usage of both libraries in memo.js
cat memo.js

# Check if there are any known compatibility issues between these versions
gh api graphql -f query='
{
  repository(owner: "web3", name: "web3.js") {
    releases(first: 1, orderBy: {field: CREATED_AT, direction: DESC}) {
      nodes {
        tagName
        description
      }
    }
  }
}'

Length of output: 6129

memo.js (1)

77-79: Verify the ABI encoding types and order

Ensure that the types and corresponding values in the encodeFieldsABI function match and are in the correct order for ABI encoding.

Consider reviewing and testing the function to confirm correctness.

🧰 Tools
🪛 eslint

[error] 77-77: Delete ··

(prettier/prettier)


[error] 78-78: Delete ··

(prettier/prettier)


[error] 79-79: Delete ··

(prettier/prettier)

memo.test.js Outdated Show resolved Hide resolved
memo.test.js Outdated Show resolved Hide resolved
Comment on lines +87 to +90
// Run the test cases
testMemoAbi();
testMemoCompactShort();
testMemoCompactLong();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Implement proper test runner and reporting

Replace manual test execution with a proper test framework to get better error reporting, test filtering, and CI integration capabilities.

  1. Add test framework configuration:
// jest.config.js
module.exports = {
  testEnvironment: 'node',
  testMatch: ['**/*.test.js'],
  verbose: true
};
  1. Update package.json:
{
  "scripts": {
+   "test": "jest",
+   "test:watch": "jest --watch"
  },
  "devDependencies": {
+   "jest": "^29.0.0"
  }
}

memo.test.js Outdated Show resolved Hide resolved
memo.js Outdated
}

// Main Encoding Function
function EncodeToBytes(header, fields) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use function expressions for consistency

For consistency with modern JavaScript practices and to adhere to code style guidelines, consider using function expressions or arrow functions instead of function declarations.

Apply this diff to update your functions:

-function EncodeToBytes(header, fields) {
+const EncodeToBytes = (header, fields) => {
-function encodeFieldsABI(fields) {
+const encodeFieldsABI = (fields) => {
-function encodeFieldsCompact(compactFmt, fields) {
+const encodeFieldsCompact = (compactFmt, fields) => {
-function encodeDataCompact(compactFmt, data) {
+const encodeDataCompact = (compactFmt, data) => {

Also applies to: 75-75, 83-83, 92-92

🧰 Tools
🪛 GitHub Check: build

[warning] 44-44:
Use const or class constructors instead of named functions

🪛 eslint

[error] 44-72: Expected a function expression.

(func-style)

memo.js Outdated
@@ -0,0 +1,117 @@
const { Web3, eth } = require('web3');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Correct the Web3 import statement

The eth property is not directly exported from 'web3'. Instead, you should instantiate Web3 and access eth via the instance if needed.

Apply this diff to fix the import:

-const { Web3, eth } = require('web3');
+const Web3 = require('web3');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { Web3, eth } = require('web3');
const Web3 = require('web3');
🧰 Tools
🪛 GitHub Check: build

[failure] 1-1:
Replace 'web3' with "web3"

🪛 eslint

[error] 1-1: Replace 'web3' with "web3"

(prettier/prettier)

memo.js Outdated Show resolved Hide resolved
@fadeev
Copy link
Member

fadeev commented Nov 17, 2024

  • converted to TS
  • use Jest for tests
  • added CI to test on push

@fadeev fadeev changed the title DON'T Merge: add Bitcoin standard memo encoding example for bitSmiley and unit tests feat: add Bitcoin standard memo encoding example for bitSmiley and unit tests Nov 17, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (12)
test/memo.test.ts (1)

13-16: Consider adding address validation and edge cases.

While the test setup is good, consider enhancing it with:

  1. Address validation helpers to ensure valid Ethereum and Bitcoin addresses
  2. Additional test cases for invalid addresses and empty/malformed payloads

Example validation helper:

const isValidEthAddress = (address: string): boolean => 
  web3.utils.isAddress(address);

// Add before test execution
expect(isValidEthAddress(receiver)).toBe(true);
memo.test.js (4)

1-10: Modernize imports and setup

The code uses older Node.js style with var and manual Web3 initialization. Consider modernizing:

  1. Use ES modules instead of CommonJS
  2. Use const instead of var
  3. Move Web3 initialization to a test setup file
-var assert = require("assert");
+import { strict as assert } from 'assert';
-const {
-  Header,
-  FieldsV0,
-  EncodingFormat,
-  OpCode,
-  EncodeToBytes,
-} = require("./memo");
-const { Web3 } = require("web3");
-const web3 = new Web3();
+import { Header, FieldsV0, EncodingFormat, OpCode, EncodeToBytes } from './memo';
+import { web3 } from './test-setup';

12-15: Move test data to a separate fixture file

Test data should be moved to a separate fixture file to improve reusability and maintainability.

+// test-fixtures.js
+export const testData = {
+  receiver: "0xEA9808f0Ac504d1F521B5BbdfC33e6f1953757a7",
+  payload: new TextEncoder().encode("a payload"),
+  revertAddress: "tb1q6rufg6myrxurdn0h57d2qhtm9zfmjw2mzcm05q"
+};

33-41: Improve readability of expected hex values

The concatenated hex strings are hard to read and maintain. Consider using a template function to construct the expected values.

const createExpectedHex = ({ format, receiver, payload, revertAddress }) => {
  const parts = {
    header: format === 'ABI' ? '5a001007' : format === 'CompactShort' ? '5a011007' : '5a021007',
    receiver: format === 'ABI' 
      ? '000000000000000000000000' + receiver.slice(2)
      : receiver.slice(2),
    // ... other parts
  };
  return Object.values(parts).join('');
};

Also applies to: 69-73, 101-105


44-48: Enhance error messages with actual vs expected comparison

The current error messages don't show the difference between actual and expected values, making it harder to debug test failures.

-assert.strictEqual(
-  encodedMemoHex,
-  expectedHex,
-  "ABI encoding failed: encoded bytes do not match expected"
-);
+expect(encodedMemoHex).toEqual(expectedHex);

Also applies to: 76-80, 108-112

packages/client/src/encodeToBytes.ts (7)

99-100: Use ethers.utils.toUtf8Bytes for string encoding.

Instead of using the built-in TextEncoder, use ethers.utils.toUtf8Bytes for better compatibility and consistency.

Apply this diff:

-    new TextEncoder().encode(fields.revertAddress)
+    ethers.utils.toUtf8Bytes(fields.revertAddress)

58-59: Simplify redundant bitwise operations in header construction.

The shifts and bitwise OR with zero are redundant and can be simplified for clarity.

Apply this diff:

-  headerBytes[1] = (0x00 << 4) | (header.encodingFmt & 0x0f);
-  headerBytes[2] = ((header.opCode & 0x0f) << 4) | 0x00;
+  headerBytes[1] = header.encodingFmt & 0x0f;
+  headerBytes[2] = (header.opCode & 0x0f) << 4;

If the shifts are placeholders for future use, consider adding comments to explain their purpose.


119-120: Improve error messages for clarity.

The error message can be made clearer by specifying the actual data length and the limit.

Apply this diff:

-        "Data length exceeds 255 bytes for EncodingFmtCompactShort"
+        `Data length (${dataLen} bytes) exceeds 255 bytes for EncodingFmtCompactShort`

Repeat similar changes for other error messages to provide more context.


40-42: Validate revertAddress if required.

If revertAddress is expected to be a valid address, consider adding validation similar to receiver.

Add validation:

if (!ethers.utils.isAddress(revertAddress)) {
  throw new Error("Invalid revert address");
}

This ensures that both addresses are valid before encoding.


50-53: Handle missing or invalid parameters more gracefully.

Instead of checking for falsy values, consider using more specific validations to provide clearer error messages.

Update the parameter checks:

if (!(header instanceof Header)) {
  throw new Error("Invalid or missing Header object");
}
if (!(fields instanceof FieldsV0)) {
  throw new Error("Invalid or missing FieldsV0 object");
}

137-137: Ensure buffer concatenation is efficient and safe.

When concatenating buffers, consider using Uint8Array directly instead of converting to Buffer objects.

Apply this diff:

-  return Buffer.concat([encodedLength, data]);
+  const result = new Uint8Array(encodedLength.length + data.length);
+  result.set(encodedLength, 0);
+  result.set(data, encodedLength.length);
+  return result;

This avoids unnecessary conversions between Buffer and Uint8Array.


77-79: Simplify the combination of header and fields.

Similar to the previous suggestion, streamline the concatenation to avoid conversions.

Apply this diff:

-  return new Uint8Array(
-    Buffer.concat([Buffer.from(headerBytes), Buffer.from(encodedFields)])
-  );
+  const result = new Uint8Array(headerBytes.length + encodedFields.length);
+  result.set(headerBytes, 0);
+  result.set(encodedFields, headerBytes.length);
+  return result;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 06c81bb and 951044d.

⛔ Files ignored due to path filters (17)
  • typechain-types/@openzeppelin/contracts/index.ts is excluded by !typechain-types/**
  • typechain-types/@openzeppelin/contracts/token/ERC20/ERC20.ts is excluded by !typechain-types/**
  • typechain-types/@openzeppelin/contracts/token/ERC20/IERC20.ts is excluded by !typechain-types/**
  • typechain-types/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.ts is excluded by !typechain-types/**
  • typechain-types/contracts/EthZetaMock.sol/ZetaEthMock.ts is excluded by !typechain-types/**
  • typechain-types/contracts/TestZRC20.ts is excluded by !typechain-types/**
  • typechain-types/contracts/shared/MockZRC20.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/index.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/token/ERC20/ERC20__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/token/ERC20/IERC20__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/EthZetaMock.sol/ZetaEthMock__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/TestZRC20__factory.ts is excluded by !typechain-types/**
  • typechain-types/factories/contracts/shared/MockZRC20__factory.ts is excluded by !typechain-types/**
  • typechain-types/hardhat.d.ts is excluded by !typechain-types/**
  • typechain-types/index.ts is excluded by !typechain-types/**
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (7)
  • .github/workflows/test.yaml (1 hunks)
  • jest.config.ts (1 hunks)
  • memo.test.js (1 hunks)
  • package.json (5 hunks)
  • packages/client/src/encodeToBytes.ts (1 hunks)
  • packages/client/src/index.ts (1 hunks)
  • test/memo.test.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/test.yaml
  • jest.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🧰 Additional context used
🪛 eslint
packages/client/src/index.ts

[error] 1-23: Run autofix to sort these exports!

(simple-import-sort/exports)

🔇 Additional comments (7)
test/memo.test.ts (2)

1-11: LGTM! Clean import structure and Web3 setup.

The imports are well-organized and the Web3 instance is appropriately initialized for utility usage.


1-75: Verify alignment with bitSmiley requirements.

The tests implement Bitcoin memo encoding as required, but we should verify:

  1. If the encoding formats match bitSmiley's requirements
  2. If the revertAddress option is properly tested for bitSmiley's use case
✅ Verification successful

Let me analyze the actual implementation and requirements before making a final determination about the test coverage.


Tests correctly implement memo encoding requirements

The test coverage is comprehensive and correctly aligns with the implementation:

  • All three encoding formats (ABI, CompactShort, CompactLong) are properly tested
  • The revertAddress field is correctly handled in all test cases
  • Test cases match the actual implementation in encodeToBytes.ts
  • The revertAddress usage aligns with the type definitions in types.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for bitSmiley-specific requirements or configurations
rg -l 'bitSmiley|revertAddress' --type ts

# Check for any existing memo encoding implementations
ast-grep --pattern 'function encodeToBytes($$$)'

Length of output: 636


Script:

#!/bin/bash
# Check the implementation of encodeToBytes and its usage
cat packages/client/src/encodeToBytes.ts

# Look for any specific requirements or configurations
rg "revertAddress" -A 5 -B 5 packages/client/src/types.ts

Length of output: 4119

memo.test.js (2)

18-51: Convert to Jest test suite with parameterized tests

The three test functions share similar structure and could be refactored using Jest's parameterized tests for better maintainability.

Also applies to: 54-83, 86-115


117-120: Add test coverage for edge cases and validation

The current test suite only covers happy path scenarios. Additional test cases are needed for:

  1. Payload length limits (255 bytes for CompactShort, 65535 bytes for CompactLong)
  2. Invalid addresses
  3. Empty/null payloads and revert addresses
  4. Error conditions (missing header/fields)
packages/client/src/encodeToBytes.ts (3)

131-131: 🛠️ Refactor suggestion

Confirm endianness in writeUInt16LE.

When writing the length of data, ensure that the endianness matches the expected format in your protocol.

Is writeUInt16LE the correct method for encoding the length in little-endian format? If big-endian is required, use writeUInt16BE instead.

Apply this diff if big-endian format is needed:

-    encodedLength.writeUInt16LE(dataLen);
+    encodedLength.writeUInt16BE(dataLen);

40-42: 🛠️ Refactor suggestion

Use ethers utility for address validation.

Since you're already using ethers, consider using ethers.utils.isAddress for address validation to maintain consistency.

Apply this diff:

-    if (!isAddress(receiver)) {
+    if (!ethers.utils.isAddress(receiver)) {

Likely invalid or redundant comment.


84-87: Verify the alignment of types and values in ABI encoding.

Ensure that the types array aligns correctly with the values provided, especially since fields.payload is a Uint8Array.

Run the following script to check the types:

Ensure that fields.payload is accepted in the ABI encoding as a bytes type.

✅ Verification successful

Let me try to gather more information about the types by examining the code context.


Let me search for the type definition of FieldsV0 to understand the expected types.


Based on the code analysis, I can now provide the final response:

The ABI encoding types are correctly aligned with the field types

The FieldsV0 class shows that:

  • receiver is a string containing an Ethereum address (matches address type)
  • payload is a Uint8Array (matches bytes type, as ethers.js accepts Uint8Array for bytes encoding)
  • revertAddress is a string (matches string type)

Additionally, the test files demonstrate successful encoding with these types, confirming the compatibility.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the types match the values in ABI encoding.

# Expected: types should correspond to the data types of values.

echo "Types: ['address', 'bytes', 'string']"
echo "Values types:"
echo "- Receiver: $(node -e "console.log(typeof '${fields.receiver}')")"
echo "- Payload: $(node -e "console.log('${fields.payload}' instanceof Uint8Array)")"
echo "- Revert Address: $(node -e "console.log(typeof '${fields.revertAddress}')")"

Length of output: 595


Script:

#!/bin/bash
# Search for the type definitions and usage of fields
rg -A 5 -B 5 "fields\." --type ts

# Also look for any interfaces or type definitions related to these fields
ast-grep --pattern 'interface $_ {
  $$$
}'

Length of output: 38443


Script:

#!/bin/bash
# Search for FieldsV0 type/interface definition
ast-grep --pattern 'type FieldsV0 = {
  $$$
}'

# Also search using ripgrep for any FieldsV0 references
rg "FieldsV0" -A 5 -B 5 --type ts

Length of output: 5617

test/memo.test.ts Show resolved Hide resolved
test/memo.test.ts Show resolved Hide resolved
compactFmt: EncodingFormat,
fields: FieldsV0
): Uint8Array => {
const encodedReceiver = Buffer.from(Web3.utils.hexToBytes(fields.receiver));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace Web3.utils.hexToBytes with ethers.utils.arrayify.

To avoid importing Web3 and to keep the library usage consistent, use ethers.utils.arrayify to convert the receiver address to a byte array.

Apply this diff:

-  const encodedReceiver = Buffer.from(Web3.utils.hexToBytes(fields.receiver));
+  const encodedReceiver = ethers.utils.arrayify(fields.receiver);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const encodedReceiver = Buffer.from(Web3.utils.hexToBytes(fields.receiver));
const encodedReceiver = ethers.utils.arrayify(fields.receiver);

packages/client/src/encodeToBytes.ts Show resolved Hide resolved
@fadeev
Copy link
Member

fadeev commented Nov 19, 2024

@andresaiello @zeta-chain/fullstack please, review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants