Skip to main content
ConfidentialDeck is the base contract you inherit. It wraps the five confidential moves every hidden-card game needs. Everything else in your game is plain Solidity. The raw e.* calls are shown next to each move so you know what runs. Reach for the kit call to get all of them at once. Setup, once per file:

1. Shuffle a deck

One Inco op produces the values 1 to n in a secret permutation. No per-card RNG, no bias, no blockhash to front-run.
  • Cost: 2 * inco.getEListFee(n, ETypes.Uint256), the range plus the shuffle. It comes from the contract balance. Forward it as msg.value or pre-fund the contract to sponsor players.
  • Secret: the order. Public: n. List length is always public on Inco.
The kit call _newShuffledDeck(n) does exactly this and resets the draw pointer.

2. Draw the next card

Reading a card returns an opaque handle. It does not reveal the value. Disclosure is a separate, deliberate step (moves 3 and 4).
The kit call _draw() returns the next card and advances a public pointer. It also calls allowThis() for you, which is load-bearing: getEuint256 alone gives only this-tx access, so a card you store and reveal in a later tx would otherwise be lost.

3. Deal a card only its owner can see

Use this for a private hand or a secret role. The allow grant is the privacy boundary. Only player can decrypt it. The contract never emits the value.
Secret from everyone except player. A grant is one-way and cannot be revoked, so never allow a hand to the wrong address. That is a one-line leak. The kit call _dealTo(player) draws and does both grants. The owner peeks their card from the frontend, signing once:

4. Put a card face-up

Use this for a board card or a dice roll. It makes the value publicly decryptable forever. This is irreversible, so reveal only what the rules force open, at the latest safe moment.
The kit call _revealCard(card) does this, or _dealFaceUp() draws and reveals in one call. Anyone reads a revealed card from the frontend, no wallet needed:

5. Settle on a revealed card

At settlement the contract needs the plaintext value on-chain. The frontend brings a covalidator-signed attestation. The contract verifies it against the stored handle, so a signed value for any other card cannot be substituted.
The kit call _verifyValue(card, value, sigs) returns the verified raw value. Package a batch for the on-chain settle(...):

Adding a new game

  1. contract MyGame is ConfidentialDeck { ... }.
  2. Shuffle with _newShuffledDeck. Deal with _dealTo (private) or _dealFaceUp (public). Read at settlement with _verifyValue.
  3. Expose the card handles through a view so the frontend can decrypt or reveal them.
  4. Add an Ignition module, a deploy script, and a frontend page. Copy the closest example.

The three rules that break every new Inco project

  • Call allowThis() on every stored handle. A handle you cannot re-access is lost forever.
  • Pay the fee for shuffledRange with deckFee(n), from msg.value or a pre-funded contract.
  • Never if or require on an encrypted value, and never e.reveal a card before the rules open it.