Skip to main content

eth-to-sol

Translate Ethereum/Solidity contracts and EVM mental models to production-grade Solana programs. Use for EVM-to-SVM account model, PDA, SPL Token, CPI, Solana security, transaction/fee/commitment, and Anchor migration guidance.

インストールへ移動

ソース情報

リポジトリ
solana-foundation/eth-to-sol-skill
ソースの最終更新活動
2026年6月19日 14:39
検出された SKILL.md の言語
英語
スター
2
フォーク
1

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
eth-to-sol
description
Translate Ethereum/Solidity contracts and EVM mental models to production-grade Solana programs. Use for EVM-to-SVM account model, PDA, SPL Token, CPI, Solana security, transaction/fee/commitment, and Anchor migration guidance.
# eth-to-sol Translate Ethereum/Solidity contracts to production-grade Solana programs. The goal is not a 1:1 port — it is Solana-native code plus a teaching artifact that makes every decision legible to a developer who knows Solidity well and Solana barely. This skill ships standalone from any app that invokes it. Keep outputs scoped to programs, accounts, transactions, and developer-facing API integration. Do not produce UI artifacts such as React components, screens, CSS, app copy, or visual design guidance. ## Two-pass protocol (hard rule) Every translation produces two outputs in sequence. Do not collapse them. 1. **Pass 1 — Faithful port.** A semantically identical Anchor program. No restructuring, no SPL CPI substitutions, no parallelism rework. It exists so the refactor's value is legible. Mark obviously un-Solana patterns with `// SMELL:` comments rather than fixing them. 2. **Pass 2 — Solana-native refactor.** Restructured for Solana primitives: SPL programs via CPI, per-entity PDAs, parallelism-friendly account layout, explicit rent/sizing, compute-budget awareness, program splitting where warranted. Production-ready. If a contract is trivially served by an existing Solana program (e.g. a vanilla ERC-20), the optimized version will be drastically smaller than the naive port. That is the lesson. ## Output contract For an input named `foo`, produce exactly these artifacts: | File | Contents | |---|---| | `01-original.<ext>` | The input (Solidity, Vyper, etc.). Already present; do not rewrite. | | `02-naive-port.rs` | Pass 1. Compiles. Inline `// SMELL:` markers on antipatterns. | | `03-optimized.rs` | Pass 2. Production-ready, fully commented at non-obvious sites. | | `04-diff.md` | Structured diff. **Group sections by theme** (State model / Parallelism / Security / CPI & program reuse / Compute & rent / Idioms) — mirror the explanation log. Each section: short header, before/after snippets, `file:line` references to the two `.rs` files. | | `05-explanation.md` | The explanation log. One entry per change in `04-diff.md`, grouped by theme. Schema below. | When the optimized version meaningfully changes non-program integration (typically: SPL Token replaces a custom token surface, balance/aggregate lookups move off the program, or transaction/account lists change), append a `## Client/API integration notes` section at the bottom of `05-explanation.md`. Keep it to account derivation, required accounts, ATA creation, transaction construction, SDK call shape, and migration scoping. Do not include UI components, screens, styling, or app-specific copy. If the integration shift is minor, fold it into a relevant entry's Tradeoff instead. `05-explanation.md` is the teaching surface. Treat it as a first-class deliverable, not a comment block. ## Read first Before producing any translation, internalize the EVM → SVM mental shift in `translation/mental-model.md`. The one-line summary: *on Ethereum the contract knows where its state lives; on Solana the caller brings it.* Every translation rule below is a consequence — if a step ever feels wrong, return to that file. ## Decision tree — which sub-files to load Default-load: `translation/mental-model.md`, `translation/type-mapping.md`, `translation/pattern-mapping.md`, `security/arithmetic.md`, `security/account-validation.md`, `security/pda-canonicalization.md`. The default loads are non-negotiable. The mental-model file frames every other decision; arithmetic, account validation, and PDA canonicalization are the three security classes that bite *every* ported contract. | Source contains | Also load | |---|---| | ERC-20 / fungible token | `translation/stdlib-mapping.md`, `optimization/account-model.md`, `security/cpi-safety.md` | | ERC-20 with `_update` / `_beforeTokenTransfer` override (fee-on-transfer, blacklist, paused-transfer, rebasing) | `translation/stdlib-mapping.md` (Token-2022 section); target Token-2022 with the matching extension (transfer fee, transfer hook, default account state, interest-bearing). Do **not** target classic SPL — the semantics cannot be expressed. | | ERC-721 / ERC-1155 / NFT | `translation/stdlib-mapping.md`, `optimization/account-model.md`, `optimization/pdas.md` | | `mapping(...)` storage | `optimization/account-model.md`, `optimization/pdas.md`, `optimization/parallelism.md` | | Ownable / AccessControl / roles | `translation/stdlib-mapping.md`, `security/signer-checks.md` | | Custom modifiers | `translation/pattern-mapping.md`, `security/signer-checks.md` | | External calls / interfaces | `security/cpi-safety.md`, `security/reentrancy.md`, `optimization/program-splitting.md` | | Heavy arithmetic / fixed-point | `security/arithmetic.md` (also default-loaded) | | Hot-write global state (counters, `totalSupply`) | `optimization/parallelism.md`, `optimization/account-model.md` | | Dynamic-sized state (arrays, mappings of unknown size) | `optimization/rent-and-size.md`, `optimization/account-model.md` | | Multi-contract system | `optimization/program-splitting.md`, `security/cpi-safety.md` | | Anything writing state after an external call | `security/reentrancy.md`, `security/cpi-safety.md` | | Compute-pressured paths (multi-CPI swaps, loops in hot path, >300 expected CU per call) | `optimization/compute-budget.md` | | Multiple account types owned by the program (type-confusion risk surface) | `security/account-validation.md` (also default-loaded) | | Any PDA the program will sign for | `security/pda-canonicalization.md` (also default-loaded), `optimization/pdas.md` | | Protocol takes a user-supplied token Mint as configuration (vault, AMM, lending market) | `security/reentrancy.md`, `security/account-validation.md`, `security/cpi-safety.md` | | Vault/AMM/4626-shaped protocol (share/asset conversion math, deposit + withdraw + redeem semantics) | `security/arithmetic.md` (rounding-direction discipline), `optimization/account-model.md` (read aggregates from SPL Token), `optimization/parallelism.md` (read-only vault pattern) | | Time-delta math (`now - last_update`, accumulator periods) | `security/arithmetic.md` (clock-skew + negative-delta-cast pitfall) | | Large account graph, payment batch, swap route, many recipients, or transaction-size concern | `optimization/transactions-and-commitment.md`, `optimization/compute-budget.md` | | Priority fees, local fee markets, compute limit, recent blockhash, retry/expiry, or landing strategy | `optimization/transactions-and-commitment.md`, `optimization/compute-budget.md` | | Settlement, irreversible off-chain action, indexer correctness, or commitment-level choice | `optimization/transactions-and-commitment.md` | | Client SDK/tooling/testing migration asks (`@solana/kit`, `web3.js`, Anchor client, LiteSVM, Bankrun, local validator) | `optimization/transactions-and-commitment.md` | Always load every security/* file relevant to the constructs present. Security is non-negotiable. ## Module 1B source alignment This skill tracks Solana Enterprise Training Module 1B, "From EVM to SVM": https://github.com/solana-foundation/solana-enterprise-training/tree/main/module-1b-from-evm-to-svm Use the module as source alignment, not as shipped course UI. The skill should reference the engineering concepts below and avoid slides, quizzes, UI, or app-specific teaching surfaces. | Module 1B topic | Skill coverage | |---|---| | Purpose, prerequisites, and learning objectives | This `SKILL.md` assumes a Solidity-fluent reader with baseline Solana awareness and scopes outputs to translation artifacts, not course delivery. | | Mental-model shift: "you bring the state" | `translation/mental-model.md` | | Account model translation: storage slots, mappings, PDAs, explicit signers, upgrades, IDL/logs/time | `translation/mental-model.md`, `translation/type-mapping.md`, `translation/pattern-mapping.md`, `optimization/account-model.md`, `optimization/pdas.md` | | ERC-20 vs SPL Token: Mint, Token Account, ATA, allowances/delegates, decimals, token-account creation | `translation/stdlib-mapping.md`, `optimization/account-model.md`, `security/cpi-safety.md` | | Composability: EVM `call` vs Solana CPI and account-graph propagation | `translation/mental-model.md`, `security/cpi-safety.md`, `optimization/program-splitting.md` | | Reentrancy as a structural property and the replacement failure modes | `security/reentrancy.md`, `security/cpi-safety.md`, `security/account-validation.md` | | Solana program security checklist: ownership, signer checks, substitution, discriminators, arithmetic, CPI authority, safe close, rent | `security/account-validation.md`, `security/signer-checks.md`, `security/pda-canonicalization.md`, `security/arithmetic.md`, `security/cpi-safety.md`, `optimization/rent-and-size.md` | | Transactions in practice: recent blockhash, expiry, versioned transactions, ALTs, compute budget, priority fees, local fee markets | `optimization/transactions-and-commitment.md`, `optimization/compute-budget.md`, `optimization/parallelism.md` | | Commitment levels for settlement and indexing | `optimization/transactions-and-commitment.md` | | Developer workflow: `@solana/kit`, legacy `web3.js`, Anchor client, LiteSVM, Bankrun, local validator | `optimization/transactions-and-commitment.md` | | Cumulative EVM/SVM reference | `translation/mental-model.md` plus the referenced translation, optimization, and security files | | Quiz and slides | Do not ship; those are course surfaces, not skill runtime material. | | Additional resources | Keep external: Solana Cookbook, Anchor Book, Neodyme Common Pitfalls, Sec3 audit checklist, Solana Program Examples, Helius priority-fee guide, and official Solana fee docs. | ## Pre-flight checklist (gate on the optimized version) Every item must hold before emitting `03-optimized.rs`. If one fails, fix and re-check. - [ ] Every arithmetic op is `checked_*` — or has an inline justification for `saturating_*` / `wrapping_*`. No bare `+ - * /` on user-controlled values. - [ ] Every `Account<'info, T>` either uses Anchor's typed checks or includes explicit owner + discriminator validation. No `AccountInfo` smuggled through without checks. - [ ] Every signer-required path uses `Signer<'info>` or a manual `is_signer` check. No "the client won't call it without a signer" reasoning. - [ ] Every PDA derivation either uses `seeds = [...], bump = stored_bump` (preferred — saves ~1.5k CU per call) or bare `seeds = [...], bump,` (acceptable when CU is not pressured; both forms enforce canonicalization via Anchor's `find_program_address` check). The cached form is strongly preferred — all reference examples use it. Do **not** use `bump = <user_input>` — that's the actual canonicalization vulnerability. - [ ] CPIs use `CpiContext::new` or `CpiContext::new_with_signer`. The program arg is a `Pubkey` (use `ctx.accounts.<program>.key()`) — Anchor 1.0+ removed the `AccountInfo` form. No hand-rolled `invoke`/`invoke_signed` with manually assembled `AccountInfo` arrays unless raw Solana is justified. - [ ] No path mutates state after a CPI to an untrusted program without re-reading and re-validating. (See `security/reentrancy.md` for why account locking is necessary but not sufficient.) - [ ] Account sizing is explicit: `space = 8 + <sum>`; the 8 is the Anchor discriminator. Variable-size fields have hard caps. - [ ] Errors use `#[error_code]`. No `ProgramError::Custom(n)` literals, no `msg!`-then-fail. - [ ] No PDA shares a write lock with high-frequency unrelated state. Per-entity PDAs over global counters where the protocol allows. - [ ] If the contract emits events that SPL programs already emit (Transfer for SPL Token), prefer not duplicating them. - [ ] Re-init protection: PDAs that should only init once use `init` (not `init_if_needed`) and have unique seeds. ## Tooling — Solana Developer MCP `rust_autofixer` If your environment exposes the Solana Developer MCP (`https://mcp.solana.com/mcp`), the `rust_autofixer` tool is part of the workflow — not optional. **When to call it:** every time you have produced or modified Anchor or Pinocchio Rust that you intend to ship. That includes `02-naive-port.rs` and `03-optimized.rs`, and any in-flight fix you apply after a failed `cargo check`. **How to call it:** pass the full Rust source. Specify the framework (`auto`, `anchor`, or `pinocchio`) if the caller hasn't already. **The loop:** 1. Call `rust_autofixer` on the current Rust. 2. Apply every suggested fix (they are mechanical, structured, and safe). 3. Call `rust_autofixer` again. 4. Repeat until `require_another_tool_call_after_fixing` is `false`. Only emit the artifact once the loop terminates. This is in addition to — not a replacement for — the pre-flight checklist above; the autofixer catches the structural-safety class of bug, the checklist catches design/idiom issues. **Do not use any other Solana MCP tool** (`list_sections`, `read_section`, `search`, etc.) for this workflow. Stay scoped to `rust_autofixer`. ## Explanation log opener Before the first `## Theme` heading, the explanation log opens with a short prose preamble. The preamble must, in this order: 1. **One paragraph: what the program does in EVM-developer terms.** State the protocol the way you'd state it to a Solidity dev who's never seen the contract — "a one-shot ERC-20 crowdfund: supporters deposit tokens before a deadline; if the goal is met the creator claims the pot, otherwise supporters refund." Don't lead with what the example *teaches*; lead with what the program *does*. 2. **One paragraph: the Solana shape it ports to.** What the program looks like on Solana at the same height of abstraction — "On Solana, the same protocol becomes one PDA per supporter plus a singleton fundraiser account; SPL Token handles the actual token movement via CPIs." Still no per-line / per-symbol detail. Any optional context that follows (vocabulary list, reference-implementation link, etc.) comes after these two paragraphs, not before. ## Explanation log schema Each entry is exactly five fields. Keep them tight — one to four sentences each. ``` ### <short title> - **Title rules.** When the change has a Solidity counterpart (most state-model / security / idiom entries), frame the title as `Solidity-side → Solana-side` — e.g. `mapping(address => uint256) ledger → per-supporter PDA`, not `Vec<Contribution> → per-supporter PDA`. A Solidity-fluent reader of `03-optimized.rs` has not opened the naive port; titles that name naive-port Rust types (`Vec<X>`, `iter_mut().find(...)`, etc.) read as gibberish to them. When the change is Solana-only hygiene (no Solidity counterpart — bump caching, PDA seed consolidation, account-size optimizations), use a plain descriptive title without the arrow. - **What:** the concrete change as a diff between the naive port and the optimized port. Reference the diff section or `file:line` in the .rs files. This is the LOW-LEVEL diff view; cite specific identifiers, function names, line numbers. Written for someone reviewing the diff side-by-side. - **Annotation:** a self-contained explanation of THIS code (the optimized version) for a Solidity-fluent reader who is looking only at the optimized file and has never seen the naive port. State what the optimized code does at this point, why a Solidity developer's mental model has to shift here, and — when meaningful — what a naive translation would have done and why this shape is preferable. Do NOT cite the naive port by filename or reference any line outside the optimized file. Two to four sentences. - **Why:** the platform-level reasoning, structured as a two-sided contrast for a Solidity-fluent reader. Lead the first sentence(s) with **"On Ethereum, ..."** and describe the EVM/Solidity paradigm the developer is bringing with them. Then lead the next sentence(s) with **"On Solana, ..."** and describe the paradigm that diverges. Keep it HIGH-LEVEL — platform mechanics, mental model, what serializes / what doesn't, who owns what, what the runtime guarantees. Save the per-line / per-symbol detail for `What:` and `Annotation:`. Avoid backtick code fragments here unless absolutely necessary. - **Benefit:** what is gained. Be specific: CU saved, parallelism unlocked, security class avoided, code deleted. - **Tradeoff:** what is given up. If nothing meaningful, say so and justify briefly. ``` `What` is the "code review" view of the diff; `Annotation` is the "reader of the final code" view. They cover different audiences — both are needed because the final code is shipped on its own, but the diff is also part of the artifact set. Group entries under thematic headers: `## State model`, `## Parallelism`, `## Security`, `## CPI & program reuse`, `## Compute & rent`, `## Idioms`. ## Explanation style — write for a Solidity-fluent reader who has never seen Solana The reader knows Solidity well. They know financial systems. They have **not** internalized PDAs, the account model, SPL Token, rent, CPI, or Anchor's constraint vocabulary. The explanation log is where they bridge — every entry must land for that reader. ### Rules 1. **First-use translation, always inline.** The first time any Solana-specific term appears in a given explanation log, give a short EVM analog in parentheses or em-dashes. Don't assume a glossary; weave it into the prose. After first use, the term is fair game. Required glossing on first use (non-exhaustive): - **PDA** — "PDA (Program-Derived Address — a deterministic account address derived from seeds the program controls; analog of a Solidity storage slot keyed by `(address, mapping)` — but each PDA is its own account, not a slot inside the program)" - **SPL Token** — "SPL Token (the shared on-chain token program every fungible token reuses on Solana — instead of each ERC-20 deploying its own contract, every token is just configuration on this one program)" - **CPI** — "CPI (cross-program invocation — Solana's version of one contract `call`-ing another, but every account the callee will touch must already be in the caller's transaction)" - **rent** — "rent (a refundable SOL deposit every account pays to live on-chain; ~0.001 SOL per KB of account data, returned in full when the account is closed)"
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る