Skip to main content

Type Definitions

We allow nesting of container types, but it is not possible to specify these types directly because the type name syntax only allows you to specify a single container type.

There is a simple solution to this problem. You can add a typedefs section to the schema definition file, where you can define a single type name for a container type. That way you can easily create containers that contain such container types. The schema tool will automatically generate the in-between proxy types necessary to make this work.

To keep it at the betting smart contract from the previous section, imagine you want to keep track of all betting rounds. Since a betting round contains an array of all bets in a round, if it weren't for typedefs you could not define it easily.

Instead, now you add the following to your schema definition file:

typedefs:
BettingRound: Bet[] // one round of bets
state:
rounds: BettingRound[] // keep track of all betting rounds

The schema tool will generate the following code in typedefs.xx for the BettingRound type:

import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes"

type ArrayOfImmutableBet struct {
proxy wasmtypes.Proxy
}

func (a ArrayOfImmutableBet) Length() uint32 {
return a.proxy.Length()
}

func (a ArrayOfImmutableBet) GetBet(index uint32) ImmutableBet {
return ImmutableBet{proxy: a.proxy.Index(index)}
}

type ImmutableBettingRound = ArrayOfImmutableBet

type ArrayOfMutableBet struct {
proxy wasmtypes.Proxy
}

func (a ArrayOfMutableBet) AppendBet() MutableBet {
return MutableBet{proxy: a.proxy.Append()}
}

func (a ArrayOfMutableBet) Clear() {
a.proxy.ClearArray()
}

func (a ArrayOfMutableBet) Length() uint32 {
return a.proxy.Length()
}

func (a ArrayOfMutableBet) GetBet(index uint32) MutableBet {
return MutableBet{proxy: a.proxy.Index(index)}
}

type MutableBettingRound = ArrayOfMutableBet

Note how ImmutableBettingRound and MutableBettingRound type aliases are created for the types ArrayOfImmutableBet and ArrayOfMutableBet. These are subsequently used in the state definition that is generated in state.xx:

package betting

import "github.com/iotaledger/wasp/packages/wasmvm/wasmlib/go/wasmlib/wasmtypes"

type ArrayOfImmutableBettingRound struct {
proxy wasmtypes.Proxy
}

func (a ArrayOfImmutableBettingRound) Length() uint32 {
return a.proxy.Length()
}

func (a ArrayOfImmutableBettingRound) GetBettingRound(index uint32) ImmutableBettingRound {
return ImmutableBettingRound{proxy: a.proxy.Index(index)}
}

type ImmutableBettingState struct {
proxy wasmtypes.Proxy
}

// all bets that were made in this round
func (s ImmutableBettingState) Bets() ArrayOfImmutableBet {
return ArrayOfImmutableBet{proxy: s.proxy.Root(StateBets)}
}

// current owner of this smart contract
func (s ImmutableBettingState) Owner() wasmtypes.ScImmutableAgentID {
return wasmtypes.NewScImmutableAgentID(s.proxy.Root(StateOwner))
}

func (s ImmutableBettingState) Rounds() ArrayOfImmutableBettingRound {
return ArrayOfImmutableBettingRound{proxy: s.proxy.Root(StateRounds)}
}

type ArrayOfMutableBettingRound struct {
proxy wasmtypes.Proxy
}

func (a ArrayOfMutableBettingRound) AppendBettingRound() MutableBettingRound {
return MutableBettingRound{proxy: a.proxy.Append()}
}

func (a ArrayOfMutableBettingRound) Clear() {
a.proxy.ClearArray()
}

func (a ArrayOfMutableBettingRound) Length() uint32 {
return a.proxy.Length()
}

func (a ArrayOfMutableBettingRound) GetBettingRound(index uint32) MutableBettingRound {
return MutableBettingRound{proxy: a.proxy.Index(index)}
}

type MutableBettingState struct {
proxy wasmtypes.Proxy
}

func (s MutableBettingState) AsImmutable() ImmutableBettingState {
return ImmutableBettingState(s)
}

// all bets that were made in this round
func (s MutableBettingState) Bets() ArrayOfMutableBet {
return ArrayOfMutableBet{proxy: s.proxy.Root(StateBets)}
}

// current owner of this smart contract
func (s MutableBettingState) Owner() wasmtypes.ScMutableAgentID {
return wasmtypes.NewScMutableAgentID(s.proxy.Root(StateOwner))
}

func (s MutableBettingState) Rounds() ArrayOfMutableBettingRound {
return ArrayOfMutableBettingRound{proxy: s.proxy.Root(StateRounds)}
}

Notice how the rounds() member function returns a proxy to an array of BettingRound. Which in turn is an array of Bet. So, the desired result has been achieved. And every access step along the way only allows you to take the path laid out which is checked at compile-time.

In the next section we will explore how the schema tool generates a proxy interface for mutable states.