CTL environment (ContractEnv type) consists of:
- various settings
- network protocol parameters (fetched once on initialization)
- active Ogmios
WebSocket(optional) - CIP-30 wallet connection (optional)
- internal state used by synchronization primitives
Initialization is a costly operation, and having multiple distinct runtimes may lead to problems with state synchronization and excessive WebSocket use, so it is recommended to use only one runtime at any point in time.
If only one Contract is ever executed, just using runContract is perfectly fine. Otherwise, there are two better approaches:
Bracket pattern in functional programming world is commonly used to safely manage resources. In our case, withContractEnv should be used to initialize and finalize a ContractEnv. runContractEnv should be used to run a Contract within the environment:
withContractEnv :: forall (a :: Type). ContractParams -> (ContractEnv -> Aff a) -> Aff a
runContractInEnv :: forall (a :: Type). ContractEnv -> Contract a -> Aff a
myContract1 :: Contract Uni
myContract2 :: Contract Uni
myRunner :: ContractParams -> Aff Unit
myRunner params = withContractEnv params \env -> do
runContractInEnv env myContract1
runContractInEnv env myContract2Using bracket functions is safe, but is not always convenient, because withContractEnv callback must hold the Aff context until all Contracts exit.
Another approach is using mkContractEnv coupled with runContractInEnv and stopContractEnv.
Here's an example:
mkContractEnv :: ContractParams -> Aff ContractEnv
stopContractEnv :: ContractEnv -> Aff Unit
myContract1 :: Contract Uni
myContract2 :: Contract Uni
myRunner :: ContractParams -> Aff Unit
myRunner params = do
env <- mkContractEnv
void $ try do
runContractInEnv env myContract1
runContractInEnv env myContract2
stopContractEnv envThis approach is less safe in general, and it's fairly easy to hit the max WebSocket connections limit (which is 200 for Firefox) due to a forgotten stopContractEnv call (e.g. due to an exception), not to mention that any websocket that is not closed will force the server to also keep the connection.
This approach, however, is better suited for use when creating custom JavaScript SDKs.