Skip to content

Working with Bytes ​

This guide aims to give a high-level overview of how to work with bytes in the SDK and the structures we expect them to take. For a complete overview of ABI Encoding generally, within the Fuel network, we recommend you see the ABI Encoding documentation.

Core Types ​

We know the sizes of all core types at compile time. They are the building blocks of the more complex types and are the most common types you will encounter.

Unsigned Integer (u8 / u16 / u32 / u64 / u128 / u256) ​

Each type will only contain the number of bits specified in the name. For example, a u8 will contain 8 bits, and a u256 will contain 256 bits and take up the exact property space with no additional padding.

ts
const u8Coder = new NumberCoder('u8');
const encodedU8 = u8Coder.encode(255);
// encodedU8 = new Uint8Array([255]);

const u16Coder = new NumberCoder('u16');
const encodedU16 = u16Coder.encode(255);
// encodedU16 = new Uint8Array([0, 255]);

const u32Coder = new NumberCoder('u32');
const encodedU32 = u32Coder.encode(255);
// encodedU32 = new Uint8Array([0, 0, 0, 255]);

const u64Coder = new BigNumberCoder('u64');
const encodedU64 = u64Coder.encode(255);
// encodedU64 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 255]);

const u256Coder = new BigNumberCoder('u256');
const encodedU256 = u256Coder.encode(255);
// encodedU256 = new Uint8Array([
//     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255
// ]);
See code in context

Boolean ​

A boolean is encoded as a single byte like a u8, its value being either 0 or 1.

ts

const booleanCoder = new BooleanCoder();
const encodedTrue = booleanCoder.encode(true);
// encodedTrue = new Uint8Array([1]);

const encodedFalse = booleanCoder.encode(false);
// encodedFalse = new Uint8Array([0]);
See code in context

Fixed Length String ​

A fixed-length string's size is known at compile time due to the argument declaration of str[n] with n denoting its length. Each character in the string is encoded as a utf-8 bit.

ts

const stringCoder = new StringCoder(5);
const encoded = stringCoder.encode('hello');
See code in context

b256 / b512 ​

These are fixed-length byte arrays, with b256 containing 256 bits and b512 containing 512 bits. You can use them for address and signature formats.

ts

const b256Coder = new B256Coder();
const encodedB256 = b256Coder.encode(hexlify(randomBytes(32)));
// encodedB256 = new Uint8Array(32);

const b512Coder = new B512Coder();
const encodedB512 = b512Coder.encode(hexlify(randomBytes(64)));
// encodedB512 = new Uint8Array(64);
See code in context

Automatically Encoded Types ​

These are the types that will contain nested types and no additional encoding is required other than the encoding of the nested types. This is relevant to arrays, tuples, and structs and enums. The only caveat here, is an enum will also contain a u64 representing the enum case value. options are encoded in the same way as enums.

ts

const tupleCoder = new TupleCoder([new NumberCoder('u8'), new NumberCoder('u16')]);
const encodedTuple = tupleCoder.encode([255, 255]);
// encodedTuple = new Uint8Array([255, 0, 255]);

const structCoder = new StructCoder('struct', {
  a: new NumberCoder('u8'),
  b: new NumberCoder('u16'),
});
const encodedStruct = structCoder.encode({ a: 255, b: 255 });
// encodedStruct = new Uint8Array([255, 0, 255]);

const arrayCoder = new ArrayCoder(new NumberCoder('u8'), 4);
const encodedArray = arrayCoder.encode([255, 0, 255, 0]);
// encodedArray = new Uint8Array([255, 0, 255, 0]);

const enumCoder = new EnumCoder('enum', { a: new NumberCoder('u32') });
const encodedEnum = enumCoder.encode({ a: 255 });
// encodedEnum = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255]);
See code in context

Heap types ​

Heap types are types with a dynamic length that we do not know at compile time. These are Vec, String, and raw_slice. These types are encoded with a u64 representing the length of the data, followed by the data itself.

ts

const vecCoder = new VecCoder(new NumberCoder('u8'));
const encodedVec = vecCoder.encode([255, 0, 255]);
// encodedVec = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 3, 255, 0, 255]);

const stdStringCoder = new StdStringCoder();
const encodedStdString = stdStringCoder.encode('hello');
// encodedStdString = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 5, 104, 101, 108, 108, 111]);

const rawSliceCoder = new RawSliceCoder();
const encodedRawSlice = rawSliceCoder.encode([1, 2, 3, 4]);
// encodedRawSlice = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3, 4]);
See code in context

Full Example ​

Here is the full example of the working with bytes functions:

ts
import { randomBytes } from 'crypto';
import {
  ArrayCoder,
  B256Coder,
  B512Coder,
  BigNumberCoder,
  BooleanCoder,
  EnumCoder,
  NumberCoder,
  RawSliceCoder,
  StdStringCoder,
  StringCoder,
  StructCoder,
  TupleCoder,
  VecCoder,
  hexlify,
} from 'fuels';

const u8Coder = new NumberCoder('u8');
const encodedU8 = u8Coder.encode(255);
// encodedU8 = new Uint8Array([255]);

const u16Coder = new NumberCoder('u16');
const encodedU16 = u16Coder.encode(255);
// encodedU16 = new Uint8Array([0, 255]);

const u32Coder = new NumberCoder('u32');
const encodedU32 = u32Coder.encode(255);
// encodedU32 = new Uint8Array([0, 0, 0, 255]);

const u64Coder = new BigNumberCoder('u64');
const encodedU64 = u64Coder.encode(255);
// encodedU64 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 255]);

const u256Coder = new BigNumberCoder('u256');
const encodedU256 = u256Coder.encode(255);
// encodedU256 = new Uint8Array([
//     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255
// ]);

console.assert(
  encodedU8.toString() === new Uint8Array([255]).toString(),
  'Encoded U8 should be equal to 255'
);
console.assert(
  encodedU16.toString() === new Uint8Array([0, 255]).toString(),
  'Encoded U16 should be equal to 255'
);
console.assert(
  encodedU32.toString() === new Uint8Array([0, 0, 0, 255]).toString(),
  'Encoded U32 should be equal to 255'
);
console.assert(
  encodedU64.toString() === new Uint8Array([0, 0, 0, 0, 0, 0, 0, 255]).toString(),
  'Encoded U64 should be equal to 255'
);
console.assert(
  encodedU256.toString() ===
    new Uint8Array([
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      255,
    ]).toString(),
  'Encoded U256 should be equal to 255'
);


const booleanCoder = new BooleanCoder();
const encodedTrue = booleanCoder.encode(true);
// encodedTrue = new Uint8Array([1]);

const encodedFalse = booleanCoder.encode(false);
// encodedFalse = new Uint8Array([0]);

console.assert(
  encodedTrue.toString() === new Uint8Array([1]).toString(),
  'Encoded True should be equal to 1'
);
console.assert(
  encodedFalse.toString() === new Uint8Array([0]).toString(),
  'Encoded False should be equal to 0'
);


const stringCoder = new StringCoder(5);
const encoded = stringCoder.encode('hello');

console.assert(
  encoded.toString() === new Uint8Array([104, 101, 108, 108, 111]).toString(),
  'Encoded should be equal to hello'
);


const b256Coder = new B256Coder();
const encodedB256 = b256Coder.encode(hexlify(randomBytes(32)));
// encodedB256 = new Uint8Array(32);

const b512Coder = new B512Coder();
const encodedB512 = b512Coder.encode(hexlify(randomBytes(64)));
// encodedB512 = new Uint8Array(64);

console.assert(encodedB256.length === 32, 'Encoded B256 should be equal to 32');
console.assert(encodedB512.length === 64, 'Encoded B512 should be equal to 64');


const tupleCoder = new TupleCoder([new NumberCoder('u8'), new NumberCoder('u16')]);
const encodedTuple = tupleCoder.encode([255, 255]);
// encodedTuple = new Uint8Array([255, 0, 255]);

const structCoder = new StructCoder('struct', {
  a: new NumberCoder('u8'),
  b: new NumberCoder('u16'),
});
const encodedStruct = structCoder.encode({ a: 255, b: 255 });
// encodedStruct = new Uint8Array([255, 0, 255]);

const arrayCoder = new ArrayCoder(new NumberCoder('u8'), 4);
const encodedArray = arrayCoder.encode([255, 0, 255, 0]);
// encodedArray = new Uint8Array([255, 0, 255, 0]);

const enumCoder = new EnumCoder('enum', { a: new NumberCoder('u32') });
const encodedEnum = enumCoder.encode({ a: 255 });
// encodedEnum = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255]);

console.assert(
  encodedTuple.toString() === new Uint8Array([255, 0, 255]).toString(),
  'Encoded Tuple should be equal to [255, 0, 255]'
);
console.assert(
  encodedStruct.toString() === new Uint8Array([255, 0, 255]).toString(),
  'Encoded Struct should be equal to [255, 0, 255]'
);
console.assert(
  encodedArray.toString() === new Uint8Array([255, 0, 255, 0]).toString(),
  'Encoded Array should be equal to [255, 0, 255, 0]'
);
console.assert(
  encodedEnum.toString() === new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255]).toString(),
  'Encoded Enum should be equal to [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255]'
);


const vecCoder = new VecCoder(new NumberCoder('u8'));
const encodedVec = vecCoder.encode([255, 0, 255]);
// encodedVec = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 3, 255, 0, 255]);

const stdStringCoder = new StdStringCoder();
const encodedStdString = stdStringCoder.encode('hello');
// encodedStdString = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 5, 104, 101, 108, 108, 111]);

const rawSliceCoder = new RawSliceCoder();
const encodedRawSlice = rawSliceCoder.encode([1, 2, 3, 4]);
// encodedRawSlice = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3, 4]);

console.assert(
  encodedVec.toString() === new Uint8Array([0, 0, 0, 0, 0, 0, 0, 3, 255, 0, 255]).toString(),
  'Encoded Vec should be equal to [0, 0, 0, 0, 0, 0, 0, 3, 255, 0, 255]'
);
console.assert(
  encodedStdString.toString() ===
    new Uint8Array([0, 0, 0, 0, 0, 0, 0, 5, 104, 101, 108, 108, 111]).toString(),
  'Encoded StdString should be equal to [0, 0, 0, 0, 0, 0, 0, 5, 104, 101, 108, 108, 111]'
);
console.assert(
  encodedRawSlice.toString() === new Uint8Array([0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3, 4]).toString(),
  'Encoded RawSlice should be equal to [0, 0, 0, 0, 0, 0, 0, 4, 1, 2, 3, 4]'
);
See code in context