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, noblockhash to front-run.
- Cost:
2 * inco.getEListFee(n, ETypes.Uint256), the range plus the shuffle. It comes from the contract balance. Forward it asmsg.valueor pre-fund the contract to sponsor players. - Secret: the order. Public:
n. List length is always public on Inco.
_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)._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. Theallow grant is the privacy
boundary. Only player can decrypt it. The contract never emits the value.
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._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._verifyValue(card, value, sigs) returns the verified raw value.
Package a batch for the on-chain settle(...):
Adding a new game
contract MyGame is ConfidentialDeck { ... }.- Shuffle with
_newShuffledDeck. Deal with_dealTo(private) or_dealFaceUp(public). Read at settlement with_verifyValue. - Expose the card handles through a view so the frontend can decrypt or reveal them.
- 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
shuffledRangewithdeckFee(n), frommsg.valueor a pre-funded contract. - Never
iforrequireon an encrypted value, and nevere.reveala card before the rules open it.