.claude/skills/crane-tokens/SKILL.md
This skill should be used when the user asks to "deploy an ERC20 token", "create a token", "implement ERC20", "add permit to token", "mint/burn functionality", "ERC4626 vault", "tokenized vault", "ERC721 NFT", or needs guidance on token standards implementation with Crane's Diamond Factory Packages.
npx skillsauth add cyotee/crane crane-tokensInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Crane provides pre-built Diamond Factory Packages (DFPkg) for deploying ERC20, ERC20Permit, and ERC4626 tokens as Diamond proxies.
| Need | Package | Features |
|------|---------|----------|
| Basic ERC20 | ERC20DFPkg | Transfer, approve, metadata |
| ERC20 + Permit | ERC20PermitDFPkg | + EIP-2612 gasless approvals |
| Full-featured token | ERC20PermitMintBurnLockedOwnableDFPkg | + Mint/burn with owner control |
import {ERC20PermitDFPkg, IERC20PermitDFPkg} from "@crane/contracts/tokens/ERC20/ERC20PermitDFPkg.sol";
import {IERC20} from "@crane/contracts/interfaces/IERC20.sol";
// 1. Deploy facets (typically done once via FactoryService)
IFacet erc20Facet = factory.deployFacet(type(ERC20Facet).creationCode, salt);
IFacet erc5267Facet = factory.deployFacet(type(ERC5267Facet).creationCode, salt);
IFacet erc2612Facet = factory.deployFacet(type(ERC2612Facet).creationCode, salt);
// 2. Deploy package with facet references
ERC20PermitDFPkg pkg = new ERC20PermitDFPkg(IERC20PermitDFPkg.PkgInit({
erc20Facet: erc20Facet,
erc5267Facet: erc5267Facet,
erc2612Facet: erc2612Facet
}));
// 3. Deploy token instance via Diamond factory
IERC20 token = IERC20(diamondFactory.deploy(
pkg,
abi.encode(IERC20PermitDFPkg.PkgArgs({
name: "My Token",
symbol: "MTK",
decimals: 18,
totalSupply: 1_000_000e18,
recipient: msg.sender,
optionalSalt: bytes32(0)
}))
));
Basic ERC20 token with metadata.
PkgInit (constructor):
struct PkgInit {
IFacet erc20Facet;
}
PkgArgs (deployment):
struct PkgArgs {
string name;
string symbol;
uint8 decimals; // Defaults to 18 if 0
uint256 totalSupply; // Initial mint amount
address recipient; // Required if totalSupply > 0
bytes32 optionalSalt;
}
Interfaces: IERC20, IERC20Metadata
ERC20 with EIP-2612 permit (gasless approvals).
PkgInit:
struct PkgInit {
IFacet erc20Facet;
IFacet erc5267Facet; // EIP-5267 domain separator
IFacet erc2612Facet; // EIP-2612 permit
}
PkgArgs: Same as ERC20DFPkg
Interfaces: IERC20, IERC20Metadata, IERC20Permit, IERC5267
Full-featured token with owner-controlled mint/burn and time-locked ownership transfer.
PkgInit:
struct PkgInit {
IFacet erc20Facet;
IFacet erc5267Facet;
IFacet erc2612Facet;
IFacet erc20MintBurnOwnableFacet;
IDiamondPackageCallBackFactory diamondFactory;
}
PkgArgs:
struct PkgArgs {
string name;
string symbol;
uint8 decimals;
address owner; // Initial owner (mint/burn access)
bytes32 optionalSalt;
}
Interfaces: IERC20, IERC20Metadata, IERC20Permit, IERC5267, IERC20MintBurn
Convenience deploy function:
function deployToken(
string memory name,
string memory symbol,
uint8 decimals,
address owner,
bytes32 optionalSalt
) external returns (address tokenAddress);
| File | Purpose |
|------|---------|
| ERC20Repo.sol | Diamond storage for balances, allowances, metadata |
| ERC20Target.sol | Business logic (transfer, approve, etc.) |
| ERC20Facet.sol | Diamond facet exposing IERC20 + IFacet |
| ERC20PermitTarget.sol | Permit extension logic |
| ERC20PermitFacet.sol | Diamond facet for permit |
| ERC20MintBurnOwnableFacet.sol | Mint/burn with onlyOwner modifier |
Tokens use standard Crane Repo pattern:
library ERC20Repo {
bytes32 internal constant STORAGE_SLOT = keccak256("eip.erc.20");
struct Storage {
string name;
string symbol;
uint8 decimals;
uint256 totalSupply;
mapping(address => uint256) balanceOf;
mapping(address => mapping(address => uint256)) allowance;
}
function _initialize(string memory name_, string memory symbol_, uint8 decimals_) internal;
function _mint(address to_, uint256 amount_) internal;
function _burn(address from_, uint256 amount_) internal;
function _transfer(address from_, address to_, uint256 amount_) internal;
}
Use the provided TestBase contracts:
import {TestBase_ERC20} from "@crane/contracts/tokens/ERC20/TestBase_ERC20.sol";
import {TestBase_ERC20Permit} from "@crane/contracts/tokens/ERC20/TestBase_ERC20Permit.sol";
contract MyToken_Test is TestBase_ERC20Permit {
function _deployToken() internal override returns (IERC20Permit) {
// Deploy your token instance
}
}
For detailed implementation patterns and examples:
references/token-packages.md - Complete package comparison and deployment patternsdevelopment
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
documentation
Write to contracts and send transactions. Use when executing state-changing contract functions.
development
HTTP and WebSocket transports for blockchain connectivity. Use when configuring network connections.
data-ai
Read contract data with type-safe ABI. Use when querying smart contract view/pure functions.