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

chore: remove ethers from abi-coder #2297

Merged
merged 8 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/tough-cows-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@fuel-ts/abi-coder": patch
"@fuel-ts/account": patch
"@fuel-ts/utils": patch
---

chore: remove `ethers` from `abi-coder`
1 change: 0 additions & 1 deletion packages/abi-coder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"@fuel-ts/interfaces": "workspace:*",
"@fuel-ts/math": "workspace:*",
"@fuel-ts/utils": "workspace:*",
"ethers": "^6.7.1",
"type-fest": "^3.1.0"
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { bn } from '@fuel-ts/math';
import { concat } from '@fuel-ts/utils';
import { toUtf8Bytes, toUtf8String } from 'ethers';
import { concat, toUtf8String, toUtf8Bytes } from '@fuel-ts/utils';

import { WORD_SIZE } from '../../../utils/constants';
import type { Uint8ArrayWithDynamicData } from '../../../utils/utilities';
Expand Down
3 changes: 1 addition & 2 deletions packages/abi-coder/src/encoding/coders/v0/StringCoder.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { concat } from '@fuel-ts/utils';
import { toUtf8Bytes, toUtf8String } from 'ethers';
import { concat, toUtf8Bytes, toUtf8String } from '@fuel-ts/utils';

import { Coder } from '../AbstractCoder';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { bn } from '@fuel-ts/math';
import { toUtf8Bytes, toUtf8String } from 'ethers';
import { toUtf8Bytes, toUtf8String } from '@fuel-ts/utils';

import { WORD_SIZE } from '../../../utils/constants';
import { Coder } from '../AbstractCoder';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { bn } from '@fuel-ts/math';
import { toUtf8Bytes, toUtf8String } from 'ethers';
import { toUtf8Bytes, toUtf8String } from '@fuel-ts/utils';

import { WORD_SIZE } from '../../../utils/constants';
import { Coder } from '../AbstractCoder';
Expand Down
2 changes: 1 addition & 1 deletion packages/abi-coder/src/encoding/coders/v1/StringCoder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { toUtf8Bytes, toUtf8String } from 'ethers';
import { toUtf8Bytes, toUtf8String } from '@fuel-ts/utils';

import { Coder } from '../AbstractCoder';

Expand Down
10 changes: 2 additions & 8 deletions packages/account/src/mnemonic/mnemonic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@ import { randomBytes, pbkdf2, computeHmac } from '@fuel-ts/crypto';
import { ErrorCode, FuelError } from '@fuel-ts/errors';
import { sha256 } from '@fuel-ts/hasher';
import type { BytesLike } from '@fuel-ts/interfaces';
import { arrayify, hexlify, concat, dataSlice, encodeBase58 } from '@fuel-ts/utils';
import { arrayify, hexlify, concat, dataSlice, encodeBase58, toUtf8Bytes } from '@fuel-ts/utils';

import { english } from '../wordlists';

import type { MnemonicPhrase } from './utils';
import {
entropyToMnemonicIndices,
getWords,
getPhrase,
mnemonicWordsToEntropy,
toUtf8Bytes,
} from './utils';
import { entropyToMnemonicIndices, getWords, getPhrase, mnemonicWordsToEntropy } from './utils';

//
// Constants
Expand Down
39 changes: 0 additions & 39 deletions packages/account/src/mnemonic/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,6 @@ import { arrayify } from '@fuel-ts/utils';
/* Mnemonic phrase composed by words from the provided wordlist it can be a text or a array of words */
export type MnemonicPhrase = string | Array<string>;

export function toUtf8Bytes(stri: string): Uint8Array {
const str = stri.normalize('NFKD');

const result = [];
for (let i = 0; i < str.length; i += 1) {
const c = str.charCodeAt(i);

if (c < 0x80) {
result.push(c);
} else if (c < 0x800) {
result.push((c >> 6) | 0xc0);
result.push((c & 0x3f) | 0x80);
} else if ((c & 0xfc00) === 0xd800) {
i += 1;
const c2 = str.charCodeAt(i);

if (i >= str.length || (c2 & 0xfc00) !== 0xdc00) {
throw new FuelError(
ErrorCode.INVALID_INPUT_PARAMETERS,
'Invalid UTF-8 in the input string.'
);
}

// Surrogate Pair
const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
result.push((pair >> 18) | 0xf0);
result.push(((pair >> 12) & 0x3f) | 0x80);
result.push(((pair >> 6) & 0x3f) | 0x80);
result.push((pair & 0x3f) | 0x80);
} else {
result.push((c >> 12) | 0xe0);
result.push(((c >> 6) & 0x3f) | 0x80);
result.push((c & 0x3f) | 0x80);
}
}

return Uint8Array.from(result);
}

// Returns a byte with the LSB bits set
function getLowerMask(bits: number): number {
return (1 << bits) - 1;
Expand Down
2 changes: 2 additions & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ export * from './utils/defaultSnapshotConfigs';
export * from './utils/isDefined';
export * from './utils/base58';
export * from './utils/dataSlice';
export * from './utils/toUtf8Bytes';
export * from './utils/toUtf8String';
44 changes: 44 additions & 0 deletions packages/utils/src/utils/toUtf8Bytes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { FuelError, ErrorCode } from '@fuel-ts/errors';

import { toUtf8Bytes } from './toUtf8Bytes';

/**
* @group node
* @group browser
*/
describe('toUtf8Bytes', () => {
it('should convert a simple ASCII string to UTF-8 bytes', () => {
const input = 'Hello, world!';
const expectedOutput = new Uint8Array([
72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33,
]);
expect(toUtf8Bytes(input)).toEqual(expectedOutput);
});

it('should convert a string with non-ASCII characters to UTF-8 bytes', () => {
const input = 'Héllö, wórld!';
const expectedOutput = new Uint8Array([
72, 195, 169, 108, 108, 195, 182, 44, 32, 119, 195, 179, 114, 108, 100, 33,
]);
expect(toUtf8Bytes(input)).toEqual(expectedOutput);
});

it('should handle surrogate pairs correctly', () => {
const input = '😀';
const expectedOutput = new Uint8Array([240, 159, 152, 128]);
expect(toUtf8Bytes(input)).toEqual(expectedOutput);
});

it('should throw an error for invalid surrogate pairs', () => {
const input = '\uD800';
expect(() => toUtf8Bytes(input)).toThrowError(
new FuelError(ErrorCode.INVALID_INPUT_PARAMETERS, 'Invalid UTF-8 in the input string.')
);
});

it('should normalize the input string', () => {
const input = 'e\u0301';
const expectedOutput = new Uint8Array([195, 169]);
expect(toUtf8Bytes(input)).toEqual(expectedOutput);
});
});
53 changes: 53 additions & 0 deletions packages/utils/src/utils/toUtf8Bytes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { FuelError, ErrorCode } from '@fuel-ts/errors';

/**
* Returns the UTF-8 byte representation of str.
*
* If form is disabled, the string is not normalized.
* @param stri - the string to convert to UTF-8 bytes.
* @param form - whether to normalize the string.
* @returns - the UTF-8 byte representation of str.
*/
export function toUtf8Bytes(stri: string, form = true): Uint8Array {
let str = stri;

if (form) {
str = stri.normalize('NFC');
}

const result: Array<number> = [];

for (let i = 0; i < str.length; i += 1) {
const c = str.charCodeAt(i);

if (c < 0x80) {
result.push(c);
} else if (c < 0x800) {
result.push((c >> 6) | 0xc0);
result.push((c & 0x3f) | 0x80);
} else if ((c & 0xfc00) === 0xd800) {
i += 1;
const c2 = str.charCodeAt(i);

if (i >= str.length || (c2 & 0xfc00) !== 0xdc00) {
throw new FuelError(
ErrorCode.INVALID_INPUT_PARAMETERS,
'Invalid UTF-8 in the input string.'
);
}

// Surrogate Pair
const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
result.push((pair >> 18) | 0xf0);
result.push(((pair >> 12) & 0x3f) | 0x80);
result.push(((pair >> 6) & 0x3f) | 0x80);
result.push((pair & 0x3f) | 0x80);
} else {
result.push((c >> 12) | 0xe0);
result.push(((c >> 6) & 0x3f) | 0x80);
result.push((c & 0x3f) | 0x80);
}
}

return new Uint8Array(result);
}
47 changes: 47 additions & 0 deletions packages/utils/src/utils/toUtf8String.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { toUtf8String } from './toUtf8String';

/**
* @group node
* @group browser
*/
describe('toUtf8String', () => {
it('should convert valid UTF-8 bytes to a string', () => {
const bytes = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
expect(toUtf8String(bytes)).toEqual('Hello World');
});

it('should handle multi-byte characters', () => {
const bytes = new Uint8Array([0xe2, 0x82, 0xac]); // '€' symbol
expect(toUtf8String(bytes)).toEqual('€');
});

it('should handle invalid continuation bytes', () => {
const bytes = new Uint8Array([0xc2, 0x61]); // Invalid continuation byte
expect(toUtf8String(bytes)).toEqual('');
});

it('should handle overlong sequences', () => {
const bytes = new Uint8Array([0xc0, 0xaf]); // Overlong sequence
expect(toUtf8String(bytes)).toEqual('');
});

it('should handle out-of-range code points', () => {
const bytes = new Uint8Array([0xf4, 0x90, 0x80, 0x80]); // Out-of-range code point
expect(toUtf8String(bytes)).toEqual('');
});

it('should handle UTF-16 surrogate code points', () => {
const bytes = new Uint8Array([0xed, 0xa0, 0x80]); // UTF-16 surrogate code point
expect(toUtf8String(bytes)).toEqual('');
});

it('should handle missing continuation bytes', () => {
const bytes = new Uint8Array([0xe2, 0x82]); // Missing continuation byte
expect(toUtf8String(bytes)).toEqual('');
});

it('should handle overrun bytes', () => {
const bytes = new Uint8Array([0xe2]); // Overrun byte
expect(toUtf8String(bytes)).toEqual('');
});
});