Agent skill

crane-tokens

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.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/crane-tokens

SKILL.md

Crane Token Components

Crane provides pre-built Diamond Factory Packages (DFPkg) for deploying ERC20, ERC20Permit, and ERC4626 tokens as Diamond proxies.

Token Package Selection

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

Quick Start: Deploy ERC20 with Permit

solidity
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)
    }))
));

Available Packages

ERC20DFPkg

Basic ERC20 token with metadata.

PkgInit (constructor):

solidity
struct PkgInit {
    IFacet erc20Facet;
}

PkgArgs (deployment):

solidity
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

ERC20PermitDFPkg

ERC20 with EIP-2612 permit (gasless approvals).

PkgInit:

solidity
struct PkgInit {
    IFacet erc20Facet;
    IFacet erc5267Facet;   // EIP-5267 domain separator
    IFacet erc2612Facet;   // EIP-2612 permit
}

PkgArgs: Same as ERC20DFPkg

Interfaces: IERC20, IERC20Metadata, IERC20Permit, IERC5267

ERC20PermitMintBurnLockedOwnableDFPkg

Full-featured token with owner-controlled mint/burn and time-locked ownership transfer.

PkgInit:

solidity
struct PkgInit {
    IFacet erc20Facet;
    IFacet erc5267Facet;
    IFacet erc2612Facet;
    IFacet erc20MintBurnOwnableFacet;
    IDiamondPackageCallBackFactory diamondFactory;
}

PkgArgs:

solidity
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:

solidity
function deployToken(
    string memory name,
    string memory symbol,
    uint8 decimals,
    address owner,
    bytes32 optionalSalt
) external returns (address tokenAddress);

Token Component Files

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

Storage Pattern

Tokens use standard Crane Repo pattern:

solidity
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;
}

Testing Tokens

Use the provided TestBase contracts:

solidity
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
    }
}

Additional Resources

Reference Files

For detailed implementation patterns and examples:

  • references/token-packages.md - Complete package comparison and deployment patterns

Didn't find tool you were looking for?

Be as detailed as possible for better results