Skip to main content

Primitive Types

Primitive types are the building blocks of MultiversX smart contract data.

Value Creation Methods

There are three ways to create any type value:

// Method 1: Static factory - Type.create(value)
final u64_1 = U64Type.create(1000);

// Method 2: Direct constructor - ValueClass(value)
final u64_2 = U64Value(BigInt.from(1000));

// Method 3: Via type singleton - Type.type.createValue(value)
final u64_3 = U64Type.type.createValue(1000);

Unsigned Integers

Fixed-Size Unsigned

// U8: 0 to 255 (takes int)
final u8 = U8Type.create(255);
print(u8.nativeValue); // 255

// U16: 0 to 65,535 (takes int)
final u16 = U16Type.create(65535);

// U32: 0 to 4,294,967,295 (takes int)
final u32 = U32Type.create(4294967295);

// U64: 0 to 18,446,744,073,709,551,615 (takes int or BigInt)
final u64 = U64Type.create(BigInt.parse('18446744073709551615'));
final u64_small = U64Type.create(1000); // int also works

All Three Creation Methods

// U32 example - all equivalent
final u32_1 = U32Type.create(1000); // Static factory
final u32_2 = U32Value(1000); // Direct constructor
final u32_3 = U32Type.type.createValue(1000); // Via type singleton

// U64 example - all equivalent
final u64_1 = U64Type.create(BigInt.from(500)); // Static factory
final u64_2 = U64Value(BigInt.from(500)); // Direct constructor
final u64_3 = U64Type.type.createValue(BigInt.from(500)); // Via type singleton

BigUInt (Arbitrary Precision)

For values larger than U64, use BigUInt:

// Accepts int or BigInt
final small = BigUIntType.create(42); // int works
final large = BigUIntType.create(
BigInt.parse('999999999999999999999999999999999999999')
);

// Common use: token amounts (18 decimals)
final oneEgld = BigUIntType.create(
BigInt.parse('1000000000000000000') // 10^18
);

// Direct constructor requires BigInt
final value = BigUIntValue(BigInt.from(100));

Signed Integers

Fixed-Size Signed

// I8: -128 to 127 (takes int)
final i8 = I8Type.create(-128);
print(i8.nativeValue); // -128

// I16: -32,768 to 32,767 (takes int)
final i16 = I16Type.create(-32768);

// I32: -2,147,483,648 to 2,147,483,647 (takes int)
final i32 = I32Type.create(-2147483648);

// I64: full 64-bit signed range (takes int or BigInt)
final i64_small = I64Type.create(1000000); // int works
final i64_large = I64Type.create(BigInt.parse('-5000000000000')); // BigInt for large

BigInt (Arbitrary Precision Signed)

// Accepts int or BigInt
final small = BigIntType.create(-42); // int works
final large = BigIntType.create(
BigInt.parse('-999999999999999999999999999999')
);

// Direct constructor requires BigInt
final value = BigIntValue(BigInt.from(-100));

Boolean

// Using static factory
final trueVal = BooleanType.create(true);
print(trueVal.nativeValue); // true

// Using direct constructor
final falseVal = BooleanValue(false);
print(falseVal.nativeValue); // false

// Via type singleton
final boolVal = BooleanType.type.createValue(true);

Strings

ManagedBuffer strings (UTF-8 encoded):

// Static factory
final str = StringType.create('Hello, MultiversX!');
print(str.nativeValue); // 'Hello, MultiversX!'

// Direct constructor
final str2 = StringValue('Direct string');

// Via type singleton
final str3 = StringType.type.createValue('Via type');

Bytes

Raw byte arrays:

// From list of ints
final bytes = BytesType.create([0x48, 0x65, 0x6c, 0x6c, 0x6f]);
print(bytes.nativeValue); // [72, 101, 108, 108, 111]

// Direct constructor
final bytes2 = BytesValue([1, 2, 3, 4]);

// From UTF-8 string
final bytes3 = BytesValue.fromUTF8('Hello');

// From hex string
final bytes4 = BytesValue.fromHex('48656c6c6f');

// Convert back
print(bytes3.toUTF8()); // 'Hello'
print(bytes4.toHex()); // '48656C6C6F'

Type Ranges Reference

TypeMinMaxBytes
U802551
U16065,5352
U3204,294,967,2954
U640~1.8 × 10^198
BigUInt0UnlimitedVariable
I8-1281271
I16-32,76832,7672
I32-2.1 × 10^92.1 × 10^94
I64-9.2 × 10^189.2 × 10^188
BigIntUnlimitedUnlimitedVariable

Complete Example

import 'package:abidock_mvx/abidock_mvx.dart';

void main() {
// === Unsigned integers (U8/U16/U32 take int) ===
final u8 = U8Type.create(255);
final u16 = U16Type.create(65535);
final u32 = U32Type.create(4294967295);

// U64 accepts int or BigInt
final u64_small = U64Type.create(1000000);
final u64_large = U64Type.create(BigInt.parse('18446744073709551615'));

// BigUInt accepts int or BigInt
final oneEgld = BigUIntType.create(BigInt.parse('1000000000000000000'));

// === Signed integers (I8/I16/I32 take int) ===
final i8 = I8Type.create(-128);
final i16 = I16Type.create(-32768);
final i32 = I32Type.create(-2147483648);

// I64 accepts int or BigInt
final i64 = I64Type.create(BigInt.parse('-9223372036854775808'));

// === Three creation methods ===
// Method 1: Static factory
final val1 = U32Type.create(100);

// Method 2: Direct constructor
final val2 = U32Value(200);

// Method 3: Via type singleton
final val3 = U32Type.type.createValue(300);

// === Other primitives ===
final boolVal = BooleanType.create(true);
final strVal = StringType.create('Hello');
final bytesVal = BytesType.create([1, 2, 3]);

print('U32: ${val1.nativeValue}, ${val2.nativeValue}, ${val3.nativeValue}');
}

Best Practices

Choose the Right Type
  • Use fixed-size types (U32, U64) when values fit - more efficient
  • Use BigUInt for token amounts (they use 18 decimals)
  • Use BigInt only when negative arbitrary precision is needed
Overflow

Fixed-size types will throw if values exceed their range:

// This will throw ArgumentError
// final u8 = U8Type.create(256); // Max is 255!

// Use appropriate type
final u16 = U16Type.create(256); // OK - fits in U16
Type Parameter Reference
TypeParameter TypeNotes
U8, U16, U32intNative Dart int
I8, I16, I32intNative Dart int
U64, I64int or BigIntAuto-converts int to BigInt
BigUInt, BigIntint or BigIntAuto-converts int to BigInt

Next Steps