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 encoding / decoding for bytes[CompactBytesArray] #261

Merged
merged 10 commits into from
Jan 24, 2023
47 changes: 47 additions & 0 deletions src/lib/encoder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ describe('encoder', () => {
encodedValue:
'0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001337000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000054ef',
},
{
valueType: 'bytes[CompactBytesArray]',
decodedValue: [
'0xaabb',
'0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe',
CJ42 marked this conversation as resolved.
Show resolved Hide resolved
'0xbeefbeefbeefbeefbeef',
],
encodedValue:
'0x0002aabb0020cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe000abeefbeefbeefbeefbeef',
},
{
valueType: 'bytes[CompactBytesArray]',
decodedValue: [
// 512 bytes long value
'0xcafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe',
// 500 bytes long
'0xbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef',
CJ42 marked this conversation as resolved.
Show resolved Hide resolved
],
encodedValue:
'0x0200cafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafecafe01f4beefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeefbeef',
CJ42 marked this conversation as resolved.
Show resolved Hide resolved
},
];

testCases.forEach((testCase) => {
Expand Down Expand Up @@ -148,6 +169,32 @@ describe('encoder', () => {
() => true,
);
});

it('should throw when trying to decode a `bytes[CompactBytesArray]` with an invalid length byte', async () => {
expect(() => {
decodeValueType('bytes[CompactBytesArray]', '0x0005cafe');
}).to.throw("Couldn't decode bytes[CompactBytesArray]");
});

it('should throw when trying to encode a array that contains non hex string as `bytes[CompactBytesArray]`', async () => {
expect(() => {
encodeValueType('bytes[CompactBytesArray]', [
'some random string',
'another random strings',
'0xaabbccdd',
]);
}).to.throw("Couldn't encode, value at index 0 is not hex");
});

it('should throw when trying to encode a `bytes[CompactBytesArray]` with a bytes length bigger than 65_535', async () => {
expect(() => {
encodeValueType('bytes[CompactBytesArray]', [
'0x' + 'ab'.repeat(66_0000),
]);
}).to.throw(
"Couldn't encode bytes[CompactBytesArray], value at index 0 exceeds 65_535 bytes",
);
});
});

describe('valueContent', () => {
Expand Down
48 changes: 48 additions & 0 deletions src/lib/encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,54 @@ const valueTypeEncodingMap = {
encode: (value: string[]) => abiCoder.encodeParameter('bytes[]', value),
decode: (value: string) => abiCoder.decodeParameter('bytes[]', value),
},
'bytes[CompactBytesArray]': {
encode: (value: string[]) => encodeCompactBytesArray(value),
decode: (value: string) => decodeCompactBytesArray(value),
},
};

const encodeCompactBytesArray = (values: string[]): string => {
let compactBytesArray = '0x';
for (let i = 0; i < values.length; i++) {
if (!isHex(values[i]))
throw new Error(`Couldn't encode, value at index ${i} is not hex`);

if (values[i].length > 65_535 * 2 + 2)
throw new Error(
`Couldn't encode bytes[CompactBytesArray], value at index ${i} exceeds 65_535 bytes`,
);

const numberOfBytes = (values[i].length - 2) / 2;
let hexNumber = padLeft(numberToHex(numberOfBytes), 4);

compactBytesArray += hexNumber.substring(2) + values[i].substring(2);
}

return compactBytesArray;
};

const decodeCompactBytesArray = (compactBytesArray: string): string[] => {
if (!isHex(compactBytesArray))
CJ42 marked this conversation as resolved.
Show resolved Hide resolved
throw new Error("Couldn't decode, value is not hex");

let pointer: number = 2;
let encodedValues: string[] = [];
while (pointer < compactBytesArray.length) {
const length = hexToNumber(
'0x' + compactBytesArray.substring(pointer, pointer + 4),
);
encodedValues.push(
'0x' +
compactBytesArray.substring(pointer + 4, pointer + 2 * (length + 2)),
);

pointer += 2 * (length + 2);
}

if (pointer > compactBytesArray.length)
throw new Error("Couldn't decode bytes[CompactBytesArray]");

return encodedValues;
};

// Use enum for type bellow
Expand Down