UNPKG

superfuse-wizard

Version:

Interactive smart contract generator based on Superchain 's interoperability standard.

253 lines (195 loc) 6.8 kB
import type { Contract, BaseFunction} from './contract'; import { ContractBuilder } from './contract'; import { withCommonDefaults, defaults as commonDefaults } from "../shared/option-erc20-votes"; import type { SharedERC20VotesOptions } from "../shared/option-erc20-votes"; import { printContract } from "./print"; import { setInfo } from "./set-info"; import type { ClockMode} from './set-clock-mode'; import { clockModeDefault, setClockMode } from './set-clock-mode'; import { supportsInterface } from './common-functions'; import { defineFunctions } from '../utils/define-functions'; export function isAccessControlRequired(opts: Partial<SharedERC20VotesOptions>): boolean { return opts.upgradeable === 'uups'; } function withDefaults(opts: SharedERC20VotesOptions): Required<SharedERC20VotesOptions> { return { ...opts, ...withCommonDefaults(opts), burnable: opts.burnable ?? commonDefaults.burnable, pausable: opts.pausable ?? commonDefaults.pausable, premint: opts.premint || commonDefaults.premint, mintable: opts.mintable ?? commonDefaults.mintable, permit: opts.permit ?? commonDefaults.permit, votes: opts.votes ?? commonDefaults.votes, flashmint: opts.flashmint ?? commonDefaults.flashmint, }; } export function printERC20Votes(opts: SharedERC20VotesOptions = commonDefaults): string { return printContract(buildERC20Votes(opts)); } export function buildERC20Votes(opts: SharedERC20VotesOptions): Contract { const allOpts = withDefaults(opts); // to do add interface const c = new ContractBuilder(allOpts.contractName); const { access, upgradeable, contractInfo } = allOpts; addBase(c); setCrosschain(c); // if (allOpts.burnable) { // addBurnable(c); // } // if (allOpts.pausable) { // addPausableExtension(c, access); // } // if (allOpts.premint) { // addPremint(c, allOpts.premint); // } // if (allOpts.mintable) { // addMintable(c, access); // } // Note: Votes requires Permit if (allOpts.permit || allOpts.votes) { addPermit(c); } if (allOpts.votes) { const clockMode = allOpts.votes === true ? clockModeDefault : allOpts.votes; addVotes(c, clockMode); } // if (allOpts.flashmint) { // addFlashMint(c); // } // setAccessControl(c, access); // setUpgradeable(c, upgradeable, access); setInfo(c, contractInfo); return c; } function addBase(c: ContractBuilder) { // function addBase(c: ContractBuilder, name: string, symbol: string) { const IERC20 = { name: 'IERC20', path: '@openzeppelin-v0.5.0.2/token/ERC20/IERC20.sol', }; c.addImportOnly(IERC20); const ERC20 = { name: 'ERC20', path: '@openzeppelin-v0.5.0.2/token/ERC20/ERC20.sol', }; c.addParent( ERC20, [{ lit: '_name' }, { lit: '_symbol' }], ); c.addConstructorArgument({ type: { name: 'string memory', transpiled: false, }, name: '_name', }); c.addConstructorArgument({ type: { name: 'string memory', transpiled: false, }, name: '_symbol', }); c.addOverride(ERC20, functions._update); } function setCrosschain(c: ContractBuilder) { const Predeploys = { name: 'Predeploys', path: '@superfuse-core/libraries/Predeploys.sol', }; c.addImportOnly(Predeploys); const Unauthorized = { name: 'Unauthorized', path: '@superfuse-core//libraries/errors/CommonErrors.sol', }; c.addImportOnly(Unauthorized); const IERC7802 = { name: 'IERC7802', path: '@superfuse-core/interfaces/L2/IERC7802.sol', }; c.addParent(IERC7802); const IERC165 = { name: 'IERC165', path: '@superfuse-core/interfaces/L2/IERC7802.sol', }; c.addImportOnly(IERC165); // crosschainMint c.addFunctionCode(`// Only the "SuperchainTokenBridge" has permissions to mint tokens during crosschain transfers. if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized(); // Mint tokens to the "_to" account's balance. _mint(_to, _amount); // Emit the CrosschainMint event included on IERC7802 for tracking token mints associated with cross chain transfers. emit CrosschainMint(_to, _amount, msg.sender);`, functions.crosschainMint); // crosschainBurn c.addFunctionCode(`// Only the "SuperchainTokenBridge" has permissions to burn tokens during crosschain transfers. if (msg.sender != Predeploys.SUPERCHAIN_TOKEN_BRIDGE) revert Unauthorized(); // Burn the tokens from the "_from" account's balance. _burn(_from, _amount); // Emit the CrosschainBurn event included on IERC7802 for tracking token burns associated with cross chain transfers. emit CrosschainBurn(_from, _amount, msg.sender);`, functions.crosschainBurn); // supportsInterface c.addFunctionCode(`return _interfaceId == type(IERC7802).interfaceId || _interfaceId == type(IERC20).interfaceId || _interfaceId == type(IERC165).interfaceId;`, supportsInterface); } // export const premintPattern = /^(\d*)(?:\.(\d+))?(?:e(\d+))?$/; function addPermit(c: ContractBuilder) { // function addPermit(c: ContractBuilder, name: string) { const ERC20Permit = { name: 'ERC20Permit', path: '@openzeppelin-v0.5.0.2/token/ERC20/extensions/ERC20Permit.sol', }; c.addParent(ERC20Permit, [{ lit: '_name' }]); c.addOverride(ERC20Permit, functions.nonces); } function addVotes(c: ContractBuilder, clockMode: ClockMode) { if (!c.parents.some(p => p.contract.name === 'ERC20Permit')) { throw new Error('Missing ERC20Permit requirement for ERC20Votes'); } const ERC20Votes = { name: 'ERC20Votes', path: '@openzeppelin-v0.5.0.2/token/ERC20/extensions/ERC20Votes.sol', }; c.addParent(ERC20Votes); c.addOverride(ERC20Votes, functions._update); c.addImportOnly({ name: 'Nonces', path: '@openzeppelin-v0.5.0.2/utils/Nonces.sol', }); c.addOverride({ name: 'Nonces', }, functions.nonces); setClockMode(c, ERC20Votes, clockMode); } const functions = defineFunctions({ crosschainMint: { kind: 'external' as const, args: [ { name: '_to', type: 'address' }, { name: '_amount', type: 'uint256' }, ], }, crosschainBurn: { kind: 'external' as const, args: [ { name: '_from', type: 'address' }, { name: '_amount', type: 'uint256' }, ], }, nonces: { kind: 'public' as const, args: [ { name: 'owner', type: 'address' }, ], returns: ['uint256'], mutability: 'view' as const, }, _update: { kind: 'internal' as const, args: [ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'value', type: 'uint256' }, ], }, });