Working with CLValue
CLValue
is the type used in deploy input arguments. And it can also be returned as a result of a query to the network or a contract call.
A CLValue
comprises three parts:
cl_type
. ACLType
that defines the type of the value stored.bytes
. The value encoded as a byte array.parsed
. A human-readable representation of the value. This part is optional and may not be present in some cases.
As an example, the most simple CLValue representing a boolean true
value is like this:
{
"cl_type":"Bool",
"bytes":"01",
"parsed":true
}
NOTE: Check the KVStorage contract tutorial in this repository to see some examples of converting from and to CLValue
.
CLType
The list of CLType
s is in the table below. Some of the types have equivalent native types in C#
. In these cases we can convert easily between both as described later in this document.
Casper type | C# type | Description |
---|---|---|
Bool |
bool |
Boolean primitive. |
I32 |
int |
Signed 32-bit integer primitive. |
I64 |
long |
Signed 64-bit integer primitive. |
U8 |
byte |
Unsigned 8-bit integer primitive. |
U32 |
uint |
Unsigned 32-bit integer primitive. |
U64 |
ulong |
Unsigned 64-bit integer primitive. |
U128 |
BigInteger |
Unsigned 128-bit integer primitive. |
U256 |
BigInteger |
Unsigned 256-bit integer primitive. |
U512 |
BigInteger |
Unsigned 512-bit integer primitive. |
Unit |
n/a | Singleton value without additional semantics. |
String |
string |
A string. e.g. "Hello, World!". |
Key |
n/a | Global state key. |
URef |
n/a | Unforgeable reference. |
Option |
n/a | Optional value of the given type Option(CLType) . The value None is represented in C# as null . |
List |
List<> |
Variable-length list of values of a single CLType List(CLType) |
ByteArray |
byte[] |
Fixed-length list of bytes. |
Result |
n/a | Co-product of the the given types; one variant meaning success, the other failure. |
Map |
Dictionary<,> |
Key-value association where keys and values have the given types Map(CLType, CLType) |
Tuple1 |
n/a | Single value of the given type Tuple1(CLType ). |
Tuple2 |
n/a | Pair consisting of elements of the given types Tuple2(CLType, CLType) |
Tuple3 |
n/a | Triple consisting of elements of the given types Tuple3(CLType, CLType, CLType) |
Any |
n/a | Indicates the type is not known. |
PublicKey |
n/a | A Public key. |
Working with booleans
To create a CLValue
value with a boolean type write:
var clTrue = CLValue.Bool(true);
var clFalse = CLValue.Bool(false);
However, in many cases you won't need to explicitly create the CLValue
object. For example, to create a NamedArg
, e.g. the input argument for a contract call, you can use the C# type directly:
var inputArg = new NamedArg("value", true);
To convert a CLValue
with a boolean value to bool
, use one of the following:
var b1 = clValue.ToBoolean();
var b2 = (bool)clValue;
Working with numbers
Similarly, numbers can be converted to CLValue
objects explicitly:
var myI32 = CLValue.I32(int.MinValue);
var myI64 = CLValue.I64(long.MaxValue);
var myU8 = CLValue.U8(0x7F);
var myU32 = CLValue.U32(0);
var myU64 = CLValue.U64(ulong.MaxValue);
But, as before, the C# native types can be used instead to create the NamedArgs
objects used as input arguments. Thus, these two lines of code are identical:
var i32Arg = new NamedArg("value", int.MinValue);
var i32Arg = new NamedArg("value", myI32);
When you need to use the value from a CLValue
object, call any of the available .ToXXX()
methods or use an explicit cast:
var num1 = myI32.ToInt32();
var num2 = myI64.ToInt64();
var num3 = myU8.ToByte();
var num4 = myU32.ToUInt32();
var num5 = myU64.ToUInt64();
var num1 = (int)myI32;
var num2 = (long)myI64;
var num3 = (byte)myU8;
var num4 = (uint)myU32;
var num5 = (ulong)myU64;
For numbers with 128, 256 and 512 bits use the BigInteger
class in the System.Numerics
namespace. For instance, $CSPR amounts are indicated with a U512
value containing the number of motes. So, to create a variable with a quantity of 3 $CSPR, you can write:
var cspr3 = CLValue.U512(3_000_000_000);
And, in a NamedArg
object, you would write:
var payment = new NamedArg("payment", new BigInteger(3_000_000_000));
var payment = new NamedArg("payment", cspr3);
Working with strings
string
objects can be converted to CLValue
and viceversa. The same mechanism as with number applies:
var clString = CLValue.String("Hello world!");
var namedArgs = new List<NamedArg>()
{
new NamedArg("name", "Weekday"),
new NamedArg("value", "Monday")
};
string value = clString.ToString();
string value = (string)clValue;
Working with byte arrays
Byte arrays can be encoded into CLValue
s and converted back. The same mechanism applies:
var bytes = new byte[] {0x00, 0x01, 0x02, 0x03};
var clValue = CLValue.ByteArray(bytes);
var arg1 = new NamedArg("value", clValue);
var arg2 = new NamedArg("value", bytes);
var bytes1 = clValue.ToByteArray();
var bytes2 = (byte[]) clValue;
Working with Option
The type Option(CLType)
is either a None
value or a value with type CLType
. Some examples:
var option1 = CLValue.Option(CLValue.String("Hello World!"));
// but also:
var option2 = CLValue.Option("Hello World!");
var option3 = CLValue.Option(int.MinValue);
var option4 = CLValue.Option(publicKey);
To encode None
, indicate the CLType
that is wrapping:
var option4 = CLValue.OptionNone(CLType.String);
Call the methods IsSome()
and IsNone()
to get whether an Option(CLType)
is wrapping a value or not, respectively.
option1.IsSome(); //returns true
option1.IsNone(); //returns false
option4.IsSome(); //returns false
option4.IsNone(); //returns true
To extract the value of an Option(CLType)
use the Some()
method:
if(option1.Some(out string str1))
Console.WriteLine($"option1 = {str1}");
Working with PublicKey
s and URef
s
PublicKey
and URef
objects can be encoded into CLValue
s and converted back. The same mechanism applies:
var publicKey = PublicKey.FromPem("myPublicKey.pem");
var pkClValue = CLValue.PublicKey(publicKey);
var arg1 = new NamedArg("value", pkClValue);
var arg2 = new NamedArg("value", publicKey);
var pk1 = pkClValue.ToPublicKey();
var pk2 = (PublicKey) pkClValue;
var uref = new URef("uref-000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f-007");
var urefClValue = CLValue.URef(uref);
var arg3 = new NamedArg("value", urefClValue);
var arg4 = new NamedArg("value", uref);
var uref2 = urefClValue.ToURef();
var uref3 = (URef) urefClValue;
Working with Key
s
GlobalStateKey
objects can be encoded into CLValue
s and converted back. The same mechanism applies. For instance, with an AccountHashKey
, we can write:
var publicKey = PublicKey.FromPem("myPublicKey.pem");
var accountHash = new AccountHashKey(publicKey);
var accountClValue = CLValue.Key(accountHash);
var arg1 = new NamedArg("value", accountClValue);
var arg2 = new NamedArg("value", accountHash);
Working with List
s
Create a CLValue
with type List
with an array of values from the same type:
var list = CLValue.List(new[]
{CLValue.U8(0x10), CLValue.U8(0x20), CLValue.U8(0x30), CLValue.U8(0x40)});
var namedArgs = new List<NamedArg>()
{
new NamedArg("name", "MyListOfBytes"),
new NamedArg("value", list)
};
And, vice versa, convert a CLValue
with type List
to a C# List with .ToList()
:
var list1 = list.ToList();
Working with Map
s
Create a CLValue
with type Map
with a Dictionary of key-values:
var dict = new Dictionary<CLValue, CLValue>()
{
{CLValue.String("fourteen"), CLValue.Option(CLValue.String("14"))},
{CLValue.String("fifteen"), CLValue.Option(CLValue.String("15"))},
{CLValue.String("sixteen"), CLValue.Option(CLValue.String("16"))},
{CLValue.String("none"), CLValue.OptionNone(CLType.String)},
};
var map = CLValue.Map(dict);
var namedArgs = new List<NamedArg>()
{
new NamedArg("name", "MyMap"),
new NamedArg("value", map)
};
And, vice versa, convert a CLValue
with type Map
to a C# Dictionary with .ToDictionary()
:
var dict1 = map.ToDictionary();