Note: The following content is a written version of the XDR spec
As of js-soroban-client v0.1.3 and soroban-cli v0.2.1 it's still really funny to work with custom types required for soroban so I will explain to the best of my knowledge how to build a custom Soroban Type in JSON format (but you should probably ask @tdep...)
Note: many of these types actually have helper functions and can be entered
directly using the --arg
command and do not need this extended json notation.
Expand to view table of contents
Most values in the raw transaction are actually packed as a SCVal
so we can
assume this to be our parent class {}
.
A SCVal
is the parent of quite a few different subclasses, as can be seen in
the SCValType
enum [1].
To denote that we are working with SCValue
we prefix the different subtypes
with SCV_
.
On a lower level, SCVal
s are tagged 64-bit values, meaning that they can be
stored as a uint64
but will contain a type identifier by setting certain bits
in said number.
In the JSON format a SCVal
is always a JSON object with a single key<=>value
pair where the key is given by the SCValType
.
A SCV_U63
is the single largest SCVal
we encounter. Of the 64bit available,
it uses 63 bits but can only display positive integers (as denoted by the
u
nsigned prefix).
Most signed 64-bit values in Stellar are actually signed positive values (seq numbers, timestamps, amounts) and thus we can just omit the single bit denoting the sign.
A SCV_U63
will be denoted by having the LSByte_set to xxx0
where x denotes
an arbitrary value.
Warning: This is actually not working (?) my guess it has something to do with u64 vs u63 what ever
The key for an SCV_U63
is u63
.
A valid SCVal
json is thus {"u63":value}
A SCV_U32
is a 32bit unsigned integer, thus only display positive integers (as
denoted by the u
nsigned prefix) from 0-2^32.
A SCV_U32
will be denoted by having the LSByte set to 0001
.
The key for an SCV_U32
is u32
. A valid SCVal
json is thus {"u32":value}
A SCV_I32
is a 32bit signed integer, thus displaying positive as well as
negative integers from -2^31 - (2^31 - 1).
A SCV_I32
will be denoted by having the LSByte set to 0011
.
The key for an SCV_i32
is i32
. A valid SCVal
json is thus {"i32":value}
A SCV_STATIC
an enum type currently consisting of 4 entries (SCS_*
).
SCS_VOID
SCS_TRUE
SCS_FALSE
SCS_LEDGER_KEY_CONTRACT_CODE
A SCV_STATIC
will be denoted by having the LSByte set to 0101
.
<TODO: Add SCS encoding>
The key for an SCV_STATIC
is static
and the value can be any of ['void', 'true', 'false', 'ledgerKeyContractCode']
.
An example for a valid SCVal
json is thus {"static":"false"}
A SCV_OBJECT
is the most powerful type of SCVal
s. It can host different
structs (/objects) and is thus most versatile.
A SCV_OBJECT
or also called SCO
can host the following child objects:
SCO_VEC
SCO_MAP
SCO_U64
SCO_I64
SCO_BYTES
SCO_BIG_INT
SCO_CONTRACT_CODE
SCO_ACCOUNT_ID
This will most probably grow in the future.
The different SCO
s and their json representation is described in more detail
further down.
A SCV_OBJECT
will be denoted by having the LSByte set to 0111
.
The key for a SCV_OBJECT
is object
and it's value the json representation of
its child object (as described further down).
An example would be {"object":{"u64":0}}
A SCV_SYMBOL
is the simplest and most commonly used form of a string
representation. It is e.g. used to define function names in contracts.
A Symbol consists of 0 to 10 characters in the alphabet [0-9a-zA-Z_].
A SCV_Symbol
will be denoted by having the LSByte set to 1001
.
The remaining 60 bits will be split into the 10 different possible characters.
Each character can thus exist in 2^6 = 64
different states. These states were
defined as follows:
- 0x00 - empty space, trim trailing white spaces
- 0x01 -
_
- 0x02 - 0x0B :
0-9
- 0x0C - 0x25 :
A-Z
- 0x26 - 0x3F :
a-z
The key for an SCV_SYMBOL
is symbol
and the value can be a string with
length of 10 or less and only containing the allowed characters.
A valid example is {"symbol": "0123456789a"}
A SCV_BITSET
contains up to 60 arbitrary bits.
A SCV_BITSET
will be denoted by having the LSByte set to 1011
.
The remaining 60 bits denote the given arbitrary bits.
The key for an SCV_BITSET
is bitset
and the value is given as an u64
.
The final value of the 60 bit bitset will be the 60 LSB. (val & 0xf000000000000000
)
<TODO: check>
The SCV_STATUS
describes different errors and return types when interacting
with the soroban environment. At the time of writing, there are 8 different
SCStatusType
s
- SST_OK
- SST_UNKNOWN_ERROR
- SST_HOST_VALUE_ERROR
- SST_HOST_OBJECT_ERROR
- SST_HOST_FUNCTION_ERROR
- SST_HOST_STORAGE_ERROR
- SST_HOST_CONTEXT_ERROR
- SST_VM_ERROR
- SST_CONTRACT_ERROR
A SCV_STATUS
will be denoted by having the LSByte set to 1101
.
The remaining 60 bits consist of MSB 32-bit code
describing in detail a
certain aspect of the remaining 28-bit type
.
More information can be found in the XDR spec.
The Key for an SCV_STATUS
is status
with the value being either a string if
the status does not have further information or map if there are more detailed
information necessary.
Example : {"status":"ok"}
A SCObject
is like a SCValue
a struct type (/object).
At the time of writing, there are 8 different types of SCObject
s:
A SCO_VEC
is the basic array type. It may at most contain 256000
entries.
An entry is of the type SCValue
The key for an SCO_VEC
is vec
.
An example for a SCObject
JSON is {vec":[{"u32":1}]}
if passed up to a
SCValue
this example becomes {"object":{"vec":[{"u32":1}]}}
A SCO_MAP
is an array of at most 256000
SCMapEntry
objects. Each
SCMapEntry
object consists of a SCVal key
and a SCVal val
.
The key for an SCO_MAP
is map
.
An example for a SCObject
JSON is {"map":[{"key": {"symbol": "key"}, "val": {"symbol" : "value"}}]}
.
A SCValue
can then be constructed as seen in SCO_VEC
.
A SCO_U64
is a simple 64-bit unsigned integer value.
The key for an SCO_U64
is u64
.
An example for a SCObject
JSON is {"u64":9999999999999999999}
.
A SCValue
can be then constructed as seen in SCO_VEC
.
A SCO_I64
is a simple 64 bit signed integer value.
The key for an SCO_I64
is i64
.
An example for a SCObject
JSON is
{"i64": -999999999999999999}
.
A SCValue
can be then constructed as seen in SCO_VEC
.
A SCO_BYTES
is a byte array (?) with at most 256000
entries (or bits?)
The key for an SCO_BYTES
is bytes
. The values are given as a hex encoded string.
An example for a SCObject
JSON is
{"bytes": "aabbcc"}
.
A SCValue
can be then constructed as seen in SCO_VEC
.
{"bigInt":"zero"}
{"bigInt":{"positive":"hexValue"}}
{"bigInt":{"negative":"hexValue"}}
TODO: magnitude?!
TODO
{"contractCode": {"wasm":"rawWasmHexEncoded"}}
The SCO_ACCOUNT_ID
object consists of one field named accountId
.
This field contains an object of the type AccountID
i.e. an object consisting
of the single field publicKeyTypeEd25519
. This field contains the raw public
key of a given stellar public key (in hex format).
The key for an SCO_ACCOUNT_ID
is accountId
.
An example for a SCObject
JSON is {"accountId": {"publicKeyTypeEd25519" : "rawPubKeyInHex"}}
.
The raw public key in hex can be reconstructed using different tools such as the
stellar python SDK Keypair.from_public_key("G....").raw_public_key().hex()
.
A SCValue
can be then constructed as seen in SCO_VEC
.
Also Credits to @ElliotFriend
MIT License
Copyright (c) 2022 Kai Berszin
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The JSON example for SCO_MAP is wrong, it should be:
{"map":[{"key": {"symbol": "key"}, "val": {"symbol" : "value"}}]}
(value
key changed toval
)