Contract Class Structure
Restrictions for Simplified Code Checks
Inheritance Rules
- Only one inheritance is allowed from
ContractBase, generated by the contract plugin as a nested type inContractContainer. - Only one inheritance is allowed from
CSharpSmartContract. - Only one inheritance is allowed from
ContractState. - The type inherited from
ContractStateshould be the element type of theCSharpSmartContractgeneric instance type.
If these rules are not followed, code deployment will fail.

Field Usage Limitations
In Contract Implementation Class
- Initial values for non-readonly, non-constant fields are not allowed (for both static and non-static fields). This is because their value will reset to 0 or null after the first execution, losing the initial value.
Allowed:
class MyContract : MyContractBase
{
int test;
static const int test = 2;
}
Not Allowed:
class MyContract : MyContractBase
{
! int test = 2;
}
class MyContract : MyContractBase
{
int test;
public MyContract
{
! test = 2;
}
}
- Only primitive types or the following types are allowed for readonly/constant fields:
Marshaller<T>Method<T, T>MessageParser<T>FieldCodec<T>MapField<T, T>ReadonlyCollection<T>ReadonlyDictionary<T, T>Note: T can only be a primitive type.
In Non-Contract Classes (Classes not inheriting from ContractBase<T>)
- Initial values for non-readonly, non-constant static fields are not allowed. They reset to 0 or null after the first execution, losing the initial value.
Allowed:
class AnyClass
{
static int test;
}
Not Allowed:
class AnyClass
{
! static int test = 2;
}
class AnyClass
{
static int test;
public AnyClass
{
! test = 2;
}
}
- Exception: Fields with FileDescriptor types are allowed due to protobuf-generated code. These fields don’t have a readonly modifier and write access to them is allowed only from the constructor of the declaring type.
Allowed:
public class TestType
{
private static FileDescriptor test;
public class TestType
{
test = ...
}
}
Not Allowed:
public class TestType
{
private static FileDescriptor test;
public TestType
{
test = ...
}
! public void SetFromSomeWhereElse(FileDescriptor input)
! {
! test = input;
! }
}
-
Accessing test fields is restricted to the declaring type’s constructor only.
-
Only the following types are allowed for readonly/constant static fields:
Marshaller<T>Method<T, T>MessageParser<T>FieldCodec<T>MapField<T, T>ReadonlyCollection<T>ReadonlyDictionary<T, T>
Note: T can only be a primitive type.
- Exception: If a type has a readonly field of the same type as itself, it is only allowed if the type has no instance fields (to support LINQ-related generated types).
Allowed:
public class TestType
{
private static readonly TestType test;
private static int i;
}
Not Allowed:
public class TestType
{
private static readonly TestType test;
! private int i;
}
In Contract State
In contract state, only the following types are allowed:
Primitive Types
BoolStateInt32StateUInt32StateInt64StateUInt64StateStringStateBytesStateComplex Types
Complex Types
SingletonState<T>ReadonlyState<T>MappedState<T, T>MappedState<T, T, T>MappedState<T, T, T, T>MappedState<T, T, T, T, T>MethodReference<T, T>ProtobufState<T>ContractReferenceStateStructuredState