Skip to content

Commit

Permalink
fix: validation and handling of unsafe integers (#3491)
Browse files Browse the repository at this point in the history
* feat: added error condition around number values that are too big

* chore: changeset

* chore: add comment + altered test

* Update .changeset/orange-moles-leave.md

* Update packages/abi-coder/src/encoding/coders/BigNumberCoder.test.ts

Co-authored-by: Daniel Bate <[email protected]>

* chore: improving error message

* chore: fix error messages

---------

Co-authored-by: Daniel Bate <[email protected]>
Co-authored-by: Anderson Arboleya <[email protected]>
  • Loading branch information
3 people authored Jan 2, 2025
1 parent 981b992 commit a7eb9b6
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/orange-moles-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fuel-ts/abi-coder": patch
---

fix: validation and handling of unsafe integers
57 changes: 57 additions & 0 deletions packages/abi-coder/src/encoding/coders/BigNumberCoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,52 @@ describe('BigNumberCoder', () => {
expect(actual).toStrictEqual(expected);
});

it('should encode a u64 [max safe integer]', () => {
const coder = new BigNumberCoder('u64');
const value: number = Number.MAX_SAFE_INTEGER;
const expected = new Uint8Array([0, 31, 255, 255, 255, 255, 255, 255]);

const data = coder.encode(value);

expect(data).toEqual(expected);
});

it('should throw an error when encoding [number more than max safe integer]', async () => {
const coder = new BigNumberCoder('u64');
const value: number = Number.MAX_SAFE_INTEGER + 1;

await expectToThrowFuelError(
() => coder.encode(value),
new FuelError(
ErrorCode.ENCODE_ERROR,
'Invalid u64 type - number value is too large. Number can only safely handle up to 53 bits.'
)
);
});

it('should encode a u64 [very big number - as string]', () => {
const coder = new BigNumberCoder('u64');
const value: string = '76472027892439376';
const expected = new Uint8Array([1, 15, 174, 231, 121, 200, 89, 80]);

const data = coder.encode(value);

expect(data).toEqual(expected);
});

it('should throw an error when encoding [number more than max safe integer]', async () => {
const coder = new BigNumberCoder('u64');
const value: number = 76472027892439376;

await expectToThrowFuelError(
() => coder.encode(value),
new FuelError(
ErrorCode.ENCODE_ERROR,
'Invalid u64 type - number value is too large. Number can only safely handle up to 53 bits.'
)
);
});

it('should decode a u64 number', () => {
const coder = new BigNumberCoder('u64');
const expectedValue = 0;
Expand All @@ -34,6 +80,17 @@ describe('BigNumberCoder', () => {
expect(actualLength).toBe(expectedLength);
});

it('should decode a u64 [very big number]', () => {
const coder = new BigNumberCoder('u64');
const data = new Uint8Array([1, 15, 174, 231, 121, 200, 89, 80]);
const expectedValue = bn('76472027892439376');

const [actualValue, actualLength] = coder.decode(data, 0);

expect(actualValue).toEqualBn(expectedValue);
expect(actualLength).toEqual(8);
});

it('should encode u8 max number', () => {
const coder = new BigNumberCoder('u64');
const expected = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 255]);
Expand Down
10 changes: 10 additions & 0 deletions packages/abi-coder/src/encoding/coders/BigNumberCoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ export class BigNumberCoder extends Coder<BNInput, BN> {
encode(value: BNInput): Uint8Array {
let bytes;

// We throw an error if the value is a number and it's more than the max safe integer
// This is because we can experience some odd behavior with integers more than the max safe integer
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER#description
if (typeof value === 'number' && value > Number.MAX_SAFE_INTEGER) {
throw new FuelError(
ErrorCode.ENCODE_ERROR,
`Invalid ${this.type} type - number value is too large. Number can only safely handle up to 53 bits.`
);
}

try {
bytes = toBytes(value, this.encodedLength);
} catch (error) {
Expand Down

0 comments on commit a7eb9b6

Please sign in to comment.