This document lists common problems encountered by CTL users and developers.
Table of Contents
- Bundling-related
- Q:
lib.something
is not a function, why? - Q:
Module parse failed: 'import' and 'export' may appear only with 'sourceType: module'
error? - Q: I see
spago: Error: Remote host not found
, why? - Q: I see
WebAssembly module is included in initial chunk.
error, why? - Q: I see
Cannot use 'import.meta' outside a module
error in the browser, why? - Q: I see
Module not found: Error: Can't resolve 'utf-8-validate'
error when bundling, why?
- Q:
- Common Contract execution problems
- Time-related
- Ecosystem
- Environment-related
- Miscellaneous
This is probably because npm is used directly. This is something users have reported when using npm install
instead of having Nix manage the node dependencies (done automatically with nix develop
, but if you have node_modules
present in the working directory it will shadow the ones from the Nix store).
You can prevent npm
from ever installing to local node_modules
by enabling the packageLockOnly
flag in the shell
argument to purescriptProject
. When enabled, npm i
will always act as if the --package-lock-only
flag has been passed. This is not enabled by default, but we recommend enabling it.
Make sure you've specified "type": "module"
in your project's package.json
.
An error like this one:
spago:
Error: Remote host not found
URL: https://github.com/purescript/package-sets/releases/download/psc-0.14.5-20220224/packages.dhall
means that the CTL overlay hasn't been properly applied. Add ctl.overlays.spago
.
You may be trying to use require
instead of import
in the app entry point, see here.
type="module"
is required in the HTML script import, see here.
Other possible cause may be that you are trying to run a browser-targeted bundle in NodeJS.
You probably forgot to set BROWSER_RUNTIME=1
for the webpack
command, see here.
Most contracts require at least two UTxOs to run (one will be used as a collateral). If you use a wallet with only one UTxO, e.g. a new wallet you just funded from the faucet, you need to send yourself at least 5 Ada to create another UTxO for the collateral.
Another thing to keep in mind is that due to min-ada requirements, the amount of Ada that is required to be consumed by a Tx is higher than the amount that must be spent, because CTL creates change UTxOs. The amount of Ada that should be present on a wallet depends on a number of factors, including the amount and quantity of tokens in the users wallet.
CTL does not consume wallet collateral normally, but it still can happen.
In order to get the collateral UTxO, CTL uses the wallet and then marks the returned UTxO as "locked" internally. But some wallets (e.g. Gero) do not return the collateral the moment it is set, waiting for Tx confirmation first. In case a collateral is set right before the contract is started, CTL can accidentally spend the collateral, because we rely on CTL's own query layer to get a list of available UTxOs without consulting with the wallet in some cases, and the wallet state may lag behind the backend state.
It is impossible to lose the collateral UTxO funds completely, though, because CTL always uses CIP-40 collateral return.
Local cardano-node
lags behind the global network time, so when using time conversion functions (slotToPosixTime
, posixTimeToSlot
, etc.) users should be aware that the node sees time differently from the OS. During normal runs, the lag can be somewhere between 0 and 200 seconds.
To do anything time-related, it's best to rely on local node chain tip time, instead of using Date.now()
as a source of truth. This is often a requirement when using mustValidateIn
, because the node will reject the transaction if it appears too early.
Time/slot conversion functions depend on eraSummaries
Ogmios local state query, that returns era bounds and slotting parameters details, required for proper slot arithmetic. The most common source of the problem is that Ogmios does not return enough epochs into the future. A possible symptom is CannotFindTimeInEraSummaries
in the error message.
Q: I'm getting Uncomputable slot arithmetic; transaction's validity bounds go beyond the foreseeable end of the current era: PastHorizon
Ensure your transaction's validity range does not go over SafeZone
slots of the current era. The reason for this kind of errors is that time-related estimations are slot-based, and future forks may change slot lengths. So there is only a relatively small time window in the future during which it is known that forks cannot occur.
Haskell's aeson
library encodes long integers as JSON numbers, which leads to numeric truncation on decoder side if JS Number
is used. Unfortunately, purescript-argonaut
does not allow to use another type, because the truncation happens during JSON.parse
call. purescript-aeson
is our custom solution that bypasses this limitation by storing numbers as strings. It exposes a very similar API.
We are aware of two error messages that can be show to you if you are using wayland.
You can get something like this if you try to open the e2e browser
cardano-transaction-lib@3.0.0~e2e-browser: Args: [
'-c',
"source ./test/e2e.env && spago run --main Test.Ctl.E2E -a 'e2e-test browser'"
]
cardano-transaction-lib@3.0.0~e2e-browser: Returned: code: 1 signal: null
cardano-transaction-lib@3.0.0~e2e-browser: Failed to exec e2e-browser script
Error: cardano-transaction-lib@3.0.0 e2e-browser: `source ./test/e2e.env && spago run --main Test.Ctl.E2E -a 'e2e-test browser'`
Exit status 1
at EventEmitter.<anonymous> (/nix/store/lrvrir70n3966jybpjqw91smhcwlyn00-nodejs-14.20.0/lib/node_modules/npm/node_modules/npm-lifecycle/index.js:332:16)
at EventEmitter.emit (events.js:400:28)
at ChildProcess.<anonymous> (/nix/store/lrvrir70n3966jybpjqw91smhcwlyn00-nodejs-14.20.0/lib/node_modules/npm/node_modules/npm-lifecycle/lib/spawn.js:55:14)
at ChildProcess.emit (events.js:400:28)
at maybeClose (internal/child_process.js:1088:16)
at Process.ChildProcess._handle.onexit (internal/child_process.js:296:5)
pkgid cardano-transaction-lib@3.0.0
This error message can be found while trying to run `e2e-test-debug`
E2E tests
✗ plutip:http://localhost:4008/?plutip-nami-mock:OneShotMinting:
Error: Failed to launch the browser process!
[76104:76104:1207/234245.704016:ERROR:ozone_platform_x11.cc(238)] Missing X server or $DISPLAY
[76104:76104:1207/234245.704036:ERROR:env.cc(255)] The platform failed to initialize. Exiting.</details>
If you are under wayland you need to add --ozone-platform=wayland
to the arguments for the browser. You can use the --extra-browser-args
argument for this, as in e2e-test browser --extra-browser-args="--ozone-platform=wayland"
or the E2E_EXTRA_BROWSER_ARGS
environment variable.
Use only one ContractEnv
value. They are implicitly created every time runContract
is called, so avoid using this function if you need to run multiple Contract
s.
See here for more info.
Chromium is used in E2E test suite. Chromium is pinned in nix shell by default, because system versions of chromium may be affected by this bug
To disable, set withChromium
to false
in purescriptProject
's shell
argument.
This is because the node hasn't fully synced. The protocol parameter name changed from coinsPerUtxoWord
to coinsPerUtxoByte
in Babbage. CTL only supports the latest era, but Ogmios returns different protocol parameters format depending on current era of a local node.
If the different derivation builders that purescriptProject
gives you out-of-the-box (e.g. runPursTest
, bundlePursProject
, etc...) are not sufficient, you can access the compiled project (all of the original src
argument plus the output
directory that purs
produces) and the generated node_modules
using the compiled
and nodeModules
attributes, respectively. These can be used to write your own derivations without needing to recompile the entire project (that is, the generated output can be shared between all of your Nix components). For example:
{
project = pkgs.purescriptProject { /* snip */ };
# `purescriptProject` returns a number of specialized builders
bundle = project.bundlePursProject { /* snip */ };
# And attributes allowing you to create your own without
# needing to deal with `spago2nix` or recompiling your
# project in different components
specialPackage = pkgs.runCommand "my-special-package"
{
NODE_PATH = "${project.nodeModules}/lib/node_modules";
}
''
cp -r ${project.compiled}/* .
# Do more stuff ...
'';
}