Demo app for the CRAC (Cross-Runtime Atomic Calls) feature of Tezos X: send a message from a Michelson wallet to an EVM smart contract via the CRAC gateway, then read it back.
Successful CRAC calls currently break the EVM node's block decoding. See L2-958 for details.
A reproduction script is provided — see Reproducing the bug below.
| EVM RPC | https://demo.txpark.nomadic-labs.com/rpc |
| Tezos RPC | https://demo.txpark.nomadic-labs.com/rpc/tezlink |
| Blockscout | https://demo.txpark.nomadic-labs.com/ |
| CRAC Gateway (Michelson) | KT18oDJJKXMKhfE1bSuAPGp92pYcwVDiqsPw |
| CRAC Gateway (EVM precompile) | 0xff00000000000000000000000000000000000007 |
| ERC-20 Wrapper | KT18oDJJKXMKhfE1bSuAPGp92pYcwVKvCChb |
The testnet provides pre-funded accounts (no faucet). Documented in the TezosX Onboarding Guide.
| Address | Private key |
|---|---|
0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c |
0x9722f6cc9ff938e63f8ccb74c3daa6b45837e5c5e3835ac08c44c50ab5f39dc0 |
0xB53dc01974176E5dFf2298C5a94343c2585E3c54 |
0x3a6a6ca30c1ef1ce605a63a7a1a4ff4c689f8414ca0838bca29423f0ec280ff5 |
0x9b49c988b5817Be31DfB00F7a5a4671772dCce2B |
0x0eb9bfa77d6cd145cdc0e3d6f902ee1464aeb5f62b02e38f111c9b60cd3adab5 |
| Account | Public key | Private key (seed) |
|---|---|---|
| bootstrap1 | edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav |
edsk3gUfUPyBSfrS9CCgmCiQsTCHGkviBDusMxDJstFtojtc1zcpsh |
| bootstrap2 | edpktzNbDAUjUk697W7gYg2CRuBQjyPxbEg8dLccYYwKSKvkPvjtV9 |
|
| bootstrap3 | edpkuTXkJDGcFd5nh6VvMz8phXxU3Bi7h6hqgywNFi1vZTfQNnS1RV |
|
| bootstrap4 | edpkuFrRoDSEbJYgxRtLx2ps82UdaYc1WwfS9sE11yhauZt5DgCHbU |
|
| bootstrap5 | edpkv8EUUH68jmo3f7Um5PezmfGrRF24gnfLpH3sVNwJnV5bVCxL2n |
Note: The commonly cited bootstrap1 key edsk3gUfUPyBSfrS9CCgmCIQsTCHGkviBDusMxDJstFtojtc1uo2KK7 contains an uppercase I which is invalid in base58. The correct key has a lowercase i (CiQ) and a different suffix (zcpsh).
npm installnpm run compileCompiles contracts/MessageStore.sol with solc and outputs contracts/MessageStore.json.
npm run deploy -- <EVM_PRIVATE_KEY>Example with a bootstrap account:
npm run deploy -- 0x9722f6cc9ff938e63f8ccb74c3daa6b45837e5c5e3835ac08c44c50ab5f39dc0Create a .env file:
VITE_MESSAGE_STORE_ADDRESS=0x...deployed_address...
npm run devOpen http://localhost:5174.
- Connect wallet — Click "Connect Michelson Wallet", approve in Temple
- Send message — Type a message, click "Send" (calls the CRAC Gateway which routes to the EVM contract)
- Read message — Click "Read" to fetch the stored message via
eth_call
Note: Due to the bug described above, sending a message will currently fail with a deserialization error even though the CRAC call itself succeeds at the kernel level.
The script scripts/reproduce-crac-bug.sh demonstrates that successful CRAC calls break the EVM node's block decoding, while reverted calls work fine.
You need an octez-client built from the tezos repo. Standard releases don't know the testnet protocol (PtSeouLo...).
cd ~/git/tezos
eval $(opam env)
make octez-client# Default: looks for octez-client at ~/git/tezos/octez-client
./scripts/reproduce-crac-bug.sh
# Or specify the path:
OCTEZ_CLIENT=/path/to/octez-client ./scripts/reproduce-crac-bug.shIt sends 3 CRAC calls via octez-client to the gateway KT18oDJJKXMKhfE1bSuAPGp92pYcwVDiqsPw:
Test 1 — Default entrypoint (transfer 1 tez to an EVM address)
octez-client transfer 1 from bootstrap1 to KT18oDJJKXMKhfE1bSuAPGp92pYcwVDiqsPw \
--arg '"0x6ce4d79d4E77402e1ef3417Fdda433aA744C6e1c"' --burn-cap 1Result: operation is included in a block, but "Not enough data" deserialization error.
Test 2 — Call entrypoint (store a string on a payable EVM contract)
octez-client transfer 0 from bootstrap1 to KT18oDJJKXMKhfE1bSuAPGp92pYcwVDiqsPw \
--entrypoint call \
--arg 'Pair "0x3af5..." (Pair "store(string)" 0x<abi_encoded_hello>)' --burn-cap 1Result: same "Not enough data" deserialization error.
Test 3 — Control: call with amount to a non-payable contract (reverts)
octez-client transfer 1 from bootstrap1 to KT18oDJJKXMKhfE1bSuAPGp92pYcwVDiqsPw \
--entrypoint call \
--arg 'Pair "0xd774..." (Pair "store(string)" 0x<abi_encoded_hello>)' --burn-cap 1Result: receipt decoded correctly, shows "Cross-runtime call reverted".
Test 1 & 2: "evm_node.dev.tezlink.deserialize_operation" / "Not enough data"
Test 3: "Cross-runtime call reverted" (receipt decoded OK)
Successful CRAC calls produce an internal operation in the receipt. The result tag for this internal operation (0x68) is not handled by SeouLo's operation_data_and_receipt_encoding, causing Data_encoding.Binary.of_bytes to fail with Not_enough_data.
Reverted calls do not produce internal operations, so the receipt is simpler and decodes fine. This is why test 3 works but tests 1 and 2 don't.
See the full analysis in L2-958.
The gateway %call entrypoint expects pair string (pair string bytes):
string: EVM destination address (e.g."0x3af5...")string: method signature (e.g."store(string)")bytes: ABI-encoded parameters (without the 4-byte selector — the kernel computes it from the signature)
Source: enshrined_contracts.rs
See ARCHITECTURE.md for technical design choices.