lightning について
lightningは、Inco Lightningを使ってEVMチェーン上の機密Solidityコントラクトを開発するためのエージェントスキルです。暗号化型、アクセス制御、手数料、フロントエンドでの暗号化・復号、検証を扱い、TEE方式とFHEを区別します。
主な機能
- 01暗号化Solidity型と操作のガイド
- 02アクセス制御と手数料処理
- 03フロントエンドの暗号化・復号フロー
- 04アテステーション検証とデプロイテスト
- 05コントラクトテンプレートと実行例
活用シーン
- 01EVM上で機密スマートコントラクトを構築
- 02既存の機密コントラクトにフロントエンドを接続
- 03情報を隠すゲームを開発
- 04デプロイ前に権限と手数料処理を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ inco-fhevm/ skills --skill lightningインストール後、Claude Code で/lightningを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
docs/troubleshooting.mdexamples/attestation-flow.tsbasic-encrypt-decrypt.tsconfidential-token-interaction.tssession-key-decrypt.tsreferences/deployment-testing.mdelist-reference.mdjs-sdk-reference.mdsolidity-reference.mdreferences/games/archetypes.mdchoosing-your-approach.mdfrontend.mdoverview.mdpatterns.mdsettlement-and-math.mdscripts/ConfidentialToken.solConfidentialWithAttestation.solincoHelper.tsscripts/games/hangman/IncoHangMan.solscripts/games/mines/Mines.solMinesFactory.solMinesMath.sol詳細
Inco EVM 開発
EVM チェーン上で機密性の高いスマートコントラクトを構築します。Inco は、TEE ベースの機密コンピューティングを使用して、基盤となるブロックチェーンを変更することなく、暗号化データ型、演算、プログラム可能なアクセス制御を Solidity に追加します。このスキルでは、EVM(Inco Lightning) 上の Inco を扱います。Inco の Solana/SVM 系統は対象外です。
重要:Inco は FHE(完全準同型暗号)ではありません。TEE(信頼実行環境)ベースです。ユーザーに Inco を FHE と説明しないでください。 開発者向け API では「暗号化」という用語(euint256、ebool)を使いますが、基盤となる暗号化方式は TEE での暗号化/復号であり、準同型暗号ではありません。
重大:新しいプロジェクトで必ず問題になる3つのルール
- 暗号化ハンドルを保存した後は、必ず
allowThis()を呼び出してください。そうしないと、コントラクトはそのハンドルへのアクセスを永久に失います newEuint256/newEbool/newEaddressの呼び出しごと、またはbytes calldataの暗号文を消費する箇所では、必ずmsg.value >= inco.getFee()で手数料を支払ってください- 暗号化された条件に
if/elseを使わないでください。代わりにcondition.select(ifTrue, ifFalse)を使用してください
危険信号 — こう考えてしまったら作業を止めてください:
| 考え | 実際には |
|---|---|
「仕上げの段階で allowThis() を追加しよう」 | トランザクションが確定すると、アクセスは永久に失われます。暗号化データを保存するたび、その次の行に追加してください。 |
「この暗号化された条件は単純だから、if/else で問題ない」 | ebool はハンドルであり、bool ではありません。それに基づく分岐は壊れたコードです。例外なく .select() を使ってください。 |
| 「手数料の処理は後回しでよい」 | 暗号文の取り込みと rand/shuffle の呼び出しは、すべて資金不足でリバートします。関数を書く前に、ユーザー負担かコントラクト負担かを決めてください。 |
| 「この小さなコントラクトには検証チェックリストは大げさだ」 | 小さなコントラクトでもハンドルを失います。デプロイの前に必ずチェックリストを実行してください。 |
アーキテクチャ(30秒でわかる概要)
Frontend (@inco/lightning-js) Smart Contract (@inco/lightning) Covalidator (TEE)
───────────────────────────── ─────────────────────────────── ──────────────────
zap.encrypt(value) ──────────> newEuint256(bytes, sender)
e.add / e.sub / e.select / ...
e.allow(handle, user)
zap.attestedDecrypt(handle) <──────────────────────────────────── decrypt + sign
submit attestation on-chain -> incoVerifier().isValidAttestation()
クイックスタート
1. プロジェクトをスキャフォールドする
npx create-inco-app my-app --chain evm --framework hardhat --wallet rainbowkit --yes
2. 最小限の Solidity コントラクト
import {euint256, ebool, e, inco} from "@inco/lightning/src/Lib.sol";
contract MyConfidentialContract {
using e for *;
mapping(address => euint256) public balanceOf;
function deposit(bytes memory encryptedAmount) external payable {
require(msg.value >= inco.getFee(), "Fee not paid");
euint256 amount = encryptedAmount.newEuint256(msg.sender);
euint256 newBal = balanceOf[msg.sender].add(amount);
balanceOf[msg.sender] = newBal;
newBal.allow(msg.sender); // User can decrypt
newBal.allowThis(); // CRITICAL: contract retains access
}
}
3. フロントエンドでの暗号化と復号
import { Lightning } from "@inco/lightning-js/lite";
import { handleTypes } from "@inco/lightning-js";
const zap = await Lightning.baseSepoliaTestnet(); // Base Sepolia (chain 84532)
// Encrypt
const ct = await zap.encrypt(100n, {
accountAddress: userAddress,
dappAddress: contractAddress,
handleType: handleTypes.euint256,
});
// Send to contract (with fee as msg.value)
writeContract({ address: contractAddr, abi, functionName: "deposit", args: [ct], value: fee });
// Decrypt (retry if covalidator hasn't processed yet)
const results = await zap.attestedDecrypt(walletClient, [handle]);
const plaintext = results[0].plaintext.value;
利用方法を選択する
create-inco-app の --template は、このスキルの3つの利用方法に対応しています。必要な部分だけを読み込んでください。
- 完全な dApp(
--template monorepo、デフォルト)— 上記のクイックスタートから始め、必要に応じてリファレンスを参照します。 - コントラクトのみ(
--template contracts)— 暗号化型、allow/allowThis、手数料処理、.select(暗号化された条件にif/elseは使用しない)を扱います。Foundry/Hardhat と IncoTest で作成し、ユニットテストを実施します。→ solidity-reference.md、deployment-testing.md、scripts/ConfidentialToken.sol。 - フロントエンドのみ(
--template frontend。デプロイ済みの機密コントラクトと連携する場合)— 所有していない可能性のあるコントラクトに対して、暗号化/復号を行います。→ 既存のコントラクトとの連携(js-sdk-reference.md)、examples/basic-encrypt-decrypt.ts、scripts/incoHelper.ts。
機密性の高いゲームを構築しますか?
隠された情報を扱うゲーム(カジノ/プロバブリー・フェア、カード、ボード、封印入札、ソーシャル・ディダクション、フォグ・オブ・ウォー、単語/コード当て)を設計していますか?このページの基本 API は引き続き適用されますが、まず references/games/overview.md をご覧ください。意思決定ツリー(何が秘密で、いつ公開されるか)、アーキタイプのカタログ、複数のゲームに共通する手法、2 つの精算モデル、フロントエンドのループを掲載しています。タスクに必要なゲームのリファレンスだけを読み込んでください。
デッキ型のゲーム(カードの手札、隠された役割、ランダムなドロー)を構築しますか? ConfidentialDeck template が最も手早く始められます。1 つのベースコントラクト上に、実装例として完成した 4 つのゲーム(War、Blackjack、Raffle、Mafia)、AI に概要を伝える AGENTS.md、ライブデモが含まれています。対応するのはこのデッキ型のゲームだけです。対応範囲と、それ以外の場合の進め方については、ゲームジャム:デッキ型のゲームをすばやく構築するをご覧ください。
コーディング前に設計してください(必須): 意思決定ツリーに答えるまで、Solidity を絶対に書かないでください。何が秘密で、誰から隠され、いつ公開されるのかを決める必要があります。これらに答える前に書いたコードは、誤ったプライバシー境界を埋め込んでしまい、書き直すことになります。「ゲームは単純だから、作りながら設計すればいい」という考えは危険信号です。単純なゲームでも、イベントログ、公開状態、公開タイミングから情報が漏れることがあります。
コアコンセプト
暗号化型
euint256、ebool、eaddress は、すべてオフチェーンの暗号化データを指す bytes32 ハンドルです。
演算
using e for *; を使う場合、同じ処理を 2 通りの書き方で呼び出せます。
// Style 1: variable.operation(other) - method syntax on the encrypted variable
euint256 sum = a.add(b);
ebool isGreater = a.ge(b);
euint256 result = condition.select(ifTrue, ifFalse);
// Style 2: e.operation(a, b) - static call via the `e` library
euint256 sum = e.add(a, b);
ebool isGreater = e.ge(a, b);
euint256 result = e.select(condition, ifTrue, ifFalse);
どちらも同じ処理です。文脈に応じて読みやすい方を使ってください。
静的専用の演算(呼び出し元となる変数がない演算):
e.rand() // Random euint256
e.randBounded(n) // Random euint256 in [0, n)
e.asEuint256(42) // Plaintext -> encrypted handle
e.asEbool(true) // Plaintext -> encrypted handle
e.asEaddress(addr) // Plaintext -> encrypted handle
利用可能な演算:
数学:add、sub、mul、div、rem、and、or、xor、shr、shl
比較:eq、ne、ge、gt、le、lt、min、max、not
制御:select(ifTrue, ifFalse)(第 1 引数は条件が true の場合の値です)。暗号化された条件で if/else を使うことは絶対に避けてください。
重大:アクセス制御
newValue.allow(userAddress); // User can decrypt
newValue.allowThis(); // Contract can use in future txs
allowThis() を忘れると、コントラクトはそのハンドルへのアクセスを永久に失います。
手数料の支払い
newEuint256/newEbool/newEaddress の呼び出し(および rand/randBounded/shuffle)ごとに inco.getFee() が課金され、コントラクトの残高から支払われます。ユーザーに支払わせる場合は(payable と require(msg.value >= inco.getFee()))、またはコントラクトに事前入金してスポンサーする場合は(呼び出し元はガスレスになります)。詳しくは手数料の支払いをご覧ください。
アテステーションの検証
require(inco.incoVerifier().isValidDecryptionAttestation(decryption, signatures), "Invalid");
require(euint256.unwrap(myHandle) == decryption.handle, "Handle mismatch"); // ALWAYS check
重大:検証チェックリスト
Inco コントラクトをデプロイする前に、以下を確認してください。
- 暗号化された状態を更新する箇所で、すべて
.allowThis()を呼び出している - ユーザーに見せる値すべてに
.allow(userAddress)を呼び出している - 暗号化されたバイト列を受け取るすべての関数が、手数料チェック付きの
payableになっている - 暗号化された条件に対して
if/elseやrequireを使っていない(.select()を使用する) - コントラクトで
using e for *;を宣言している - フロントエンドで正しい
accountAddressとdappAddressを使って暗号化している - アテステーションの送信時に、ハンドルがオンチェーンのものと一致することを検証している
詳細なリファレンス
- Solidity API:すべての型、演算、アクセス制御、アテステーションのパターンについては、solidity-reference.mdをご覧ください
- JS SDK:暗号化、復号、アテステーション付き計算、セッションキー、wagmi フックについては、js-sdk-reference.mdをご覧ください
- デプロイとテスト:Foundry/Hardhat のセットアップ、Docker ローカルノード、テストネットへのデプロイ、IncoTest チートコードについては、deployment-testing.mdをご覧ください
- EList:暗号化された動的リスト(v1 でコアの
@inco/lightningに統合)については、elist-reference.mdをご覧ください - 機密性の高いゲーム:ゲーム設計レイヤーについては、まず references/games/overview.mdをご覧ください
すぐに使えるテンプレート
- scripts/ConfidentialToken.sol - ミント、転送、承認、transferFrom を備えた完全なコンフィデンシャル ERC20
- scripts/ConfidentialWithAttestation.sol - 3 種類すべてのアテステーションパターン(復号、公開、計算)
- scripts/incoHelper.ts - フロントエンドユーティリティ:暗号化、リトライ付き復号、手数料の取得、アテステーションのフォーマット
- scripts/games/mines/ - コンフィデンシャル・マインズ(モデル A の賭け)— 暗号化された盤面のシャッフル、sticky accumulator、オンチェーンのアテステーションによる決済、ファクトリーの資金プール/負債。監査済みのリファレンス(
Mines.sol+MinesMath.sol+MinesFactory.sol) - scripts/games/hangman/IncoHangMan.sol - コンフィデンシャル・ハングマン(モデル B の単語当て)— パックされた単語、
e.eqによる一致判定、プレイヤーごとのプライベートな復号、クライアント側の決済。POC — ヘッダーの注意事項を参照してください
実行可能なサンプル
- examples/basic-encrypt-decrypt.ts - 基本的なフロー:SDK の初期化、暗号化、コントラクトへの送信、リトライ付き復号
- examples/confidential-token-interaction.ts - 暗号化トークンを使ったミント、転送、承認、transferFrom
- examples/attestation-flow.ts - 3 種類すべてのアテステーションパターンをエンドツーエンドで実行(復号、公開、計算)
- examples/session-key-decrypt.ts - ポップアップなしでの復号と委任に使うセッションキー
トラブルシューティング
よくある問題と解決策:docs/troubleshooting.md 対象:手数料エラー、allowThis の不足、covalidator のタイムアウト、ハンドルのフォーマット、Docker の問題、Foundry のテストに関する注意点。
よくあるパターン
マルチプレクサー(サイレントな失敗)
ebool canTransfer = balanceOf[sender].ge(amount);
euint256 transferred = canTransfer.select(amount, e.asEuint256(0));
// Transfers 0 instead of reverting - hides the failure reason
デュアル関数(EOA + コントラクト)
// EOA: encrypted bytes input (requires fee)
function transfer(address to, bytes memory input) external payable { ... }
// Contract: existing handle (requires isAllowed check)
function transfer(address to, euint256 value) public { ... }
暗号化・計算・復号の完全なフロー
- フロントエンド:
zap.encrypt(value)-> 暗号文のバイト列 - コントラクト:
newEuint256(bytes, sender)-> ハンドルを取得し、続けて暗号化操作を実行 - コントラクト:
e.allow(result, user)-> 復号アクセスを許可 - フロントエンド:
zap.attestedDecrypt(walletClient, [handle])-> 平文 + 署名 - (任意)フロントエンド:検証のため、オンチェーンでアテステーションを送信
主な依存関係
| パッケージ | バージョン | 用途 |
|---|---|---|
@inco/lightning | latest (v1+) | Solidity ライブラリ — @latest をインストール |
@inco/lightning-js | latest (v1+) | JavaScript SDK(@inco/js から名称変更)— @latest をインストール |
| Solidity | 0.8.30 | コンパイラのバージョン(0.8.29+ をサポート) |
| EVM | cancun | 対象 EVM バージョン |