GithubHelp home page GithubHelp logo

openzeppelin / contracts-wizard Goto Github PK

View Code? Open in Web Editor NEW
233.0 233.0 124.0 3.85 MB

Interactive smart contract generator based on OpenZeppelin Contracts.

Home Page: https://wizard.openzeppelin.com

License: MIT License

JavaScript 2.52% TypeScript 66.53% CSS 3.08% HTML 3.13% Svelte 24.60% Solidity 0.14%

contracts-wizard's Introduction

Solidity NPM Package Cairo NPM Package Netlify Status

Contracts Wizard is a web application to interactively build a contract out of components from OpenZeppelin Contracts. Select the kind of contract that you want, set your parameters and desired features, and the Wizard will generate all of the code necessary. The resulting code is ready to be compiled and deployed, or it can serve as a starting point and customized further with application specific logic.

Development

Install dependencies with yarn install.

packages/core contains the code generation logic for Solidity.

packages/core-cairo contains the code generation logic for Cairo.

packages/ui is the interface built in Svelte. yarn dev spins up a local server to develop the UI.

You'll need to supply your own environment variables if you want to enable Wizard AI Assistant (OPENAI_API_KEY) and/or logging (REDIS_URL, REDIS_TOKEN).

Embedding

To embed Contracts Wizard on your site, first include the script tag:

<script async src="https://wizard.openzeppelin.com/build/embed.js"></script>

Then place <oz-wizard></oz-wizard> in the body where you want Contracts Wizard to load.

Optionally focus on specific tab with the data-tab attribute as in <oz-wizard data-tab="ERC721"></oz-wizard>.

For Cairo, use the data-lang attribute: <oz-wizard data-lang="cairo"></oz-wizard>.

API

The following describes how to use the Contracts Wizard programmatic API in your own applications.

contracts-wizard's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

contracts-wizard's Issues

Redesign

We want to make the site look more like an application and less like a landing page. We also want to feature a more visible link to the Cairo Wizard and other possible web apps we'd build. This is the general direction:

image

Add Cairo support

Add support for Cairo for StarkNet, making use of OpenZeppelin Contracts for Cairo.

  • Implement prototype of contracts and features for first release - ERC20 and ERC721
  • Propose/implement navigation between Solidity and Cairo pages in Wizard
  • Refactor source code
    • Remove duplicated source code and boilerplate in Cairo UI package
    • Remove unused Solidity contract features from Cairo UI code
    • Refactor how contracts are stored internally to be more specific to Cairo
    • Better delineation of internal contract representation vs. printing/formatting
    • Remove Solidity related content from core-cairo package
    • Remove unused Solidity contract features from core-cairo package
  • Fix remaining issues
    • Implement Download option
    • Add external upgrade method when Upgradeability is selected
    • Remove Access Control section since Ownable is the only available option
    • Fix Premint number format
    • Validation for ERC20 decimals input
    • ERC20 decimals initializer arg should not be string
    • ERC721 supportsInterface - change function name
    • Add hyperlinks to Cairo imports
    • Adjust ERC20 and 721 settings field spacing
    • Add additional basic syntax highlighting, e.g. func and end keywords
    • (optional) Better formatting of single vs. multiline imports
    • (optional) Better formatting of single vs. multiline function argument lists
    • Remove _from highlighting
    • Remove URI Storage toggle from ERC721, enable it by default
    • Change _from to from_
    • Validate that decimals is not higher than 2^8 (256)
    • Add URI parameter to mint function
    • Remove setTokenURI?
    • Use safeMint instead of mint?
    • Change TRUE to use from starkware.cairo.common.bool import TRUE
    • Add highlighting to TRUE
    • Change post config to use param for cairo
  • Clean up peripheral text around the Wizard embeds
  • Add style to hyperlinks below Wizard
  • Update post config for Cairo actions
  • Update hover links for help tooltips
  • Change discussion links back to forums
  • (optional) Simplify main html page and add navigation bar for Solidity and Cairo
  • (optional) Add automated tests with StarkNet compiler
  • Add basic cairo-core tests
  • Manual tests with StarkNet compiler
  • Move disclaimer to faq
  • Manual tests with contract output

App preview

Backslack in Windows Instead of Forward Slash on Yarn

While using yarn in Windows, when trying to open the UI, the last line on import is a backslash instead of a forward slash. This causes an issue while trying to compile in yarn.

Not sure if this is an issue as well within Linux, but something worth investigating.

Capture

Use `immutable` for OpenZeppelin AccessControl's Roles Declarations

Access roles marked as constant results in computing the keccak256 operation each time the variable is used because assigned operations for constant variables are re-evaluated every time. Changing the variables to immutable results in computing the hash only once on deployment, leading to gas savings. Some background information can be found here and here.

Wizard bugs out when Quorum is not an Integer in the Governor tab.

See this OZ Forum post and my reply to it. The values in the source code do not change once a decimal value is added to the input for Quorum %, once it bugs out, the fraction Radio button can also be clicked. See picture attached in the Forum reply.

A simple solution to this could be to convert the decimal into a fraction - multiply the number by the number of decimal places it has, pass it as the parameter to GovernorVotesQuorumFraction while overriding the quorumDenominator and multiplying the value by the number of zeroes added to the numerator. This way there would be no need to do input validation on decimals in the form.

Console Log:

print.ts:152 Uncaught (in promise) Error: Number not representable (0.1)
    at tp (print.ts:152:13)
    at Array.map (<anonymous>)
    at print.ts:132:25
    at print.ts:70:21
    at Array.flatMap (<anonymous>)
    at Yu (print.ts:70:8)
    at Xu (print.ts:37:11)
    at Object.e.$$.update (build-generic.ts:31:23)
    at H (index.mjs:1081:12)
    at F (index.mjs:1052:13)
tp @ print.ts:152
(anonymous) @ print.ts:132
(anonymous) @ print.ts:70
Yu @ print.ts:70
Xu @ print.ts:37
e.$$.update @ build-generic.ts:31
H @ index.mjs:1081
F @ index.mjs:1052
Promise.then (async)
Q @ index.mjs:1010
(anonymous) @ index.mjs:1868
(anonymous) @ App.svelte:177
be @ App.svelte:171
(anonymous) @ index.mjs:1866
(anonymous) @ GovernorControls.svelte:109

Bug in ERC-721 Burnable modifier

The ERC-721 _burn function is erroneously applied to the contract only when URI Storage is activated. See screenshots for clarification.

image
image

Allow linking to a particular tab

Support a query parameter in the url ?contracts-wizard-tab=ERC1155 so that the wizard focuses on a particular tab when it loads. Note that this query parameter should be propagated to the iframe when embedded.

Wizard changes for next cairo-contracts release

Breaking changes that affect Wizard:

Release branch: cairo/next

Release checklist (after cairo-contracts is released):

yarn config set version-tag-prefix "@openzeppelin/wizard-cairo@"
yarn config set version-git-message "Publish @openzeppelin/wizard-cairo@%s"
yarn version
git push upstream --tags master
npm publish

Unnecessary inheritance on generated contract

First of all, I'd like to thank OpenZeppelin's team for developing this contract generator. It helped me many times and I'm sure it is very useful for many others developers.

In the generated contract, it seems that we have unnecessary inheritance depending on the choice of the toggles: ERC20Burnable, ERC20Snapshot and ERC20Snapshot inherit ERC20 already, so there is no need to inherit it ERC20 again in the generated contract, right? (The same can be said regarding ERC721 and ERC1155)

However, I am not sure if it is worthy to change the code to avoid the unnecessary inheritance, as it doesn't really make a difference in terms of deployment gas. On the other hand, I saw this unnecessary inheritance being pointed out on some OpenZeppelin audits, so I think it may have pedagogical value (in the sense of teaching developers how to write better code).

Cairo: owner and recipient parameter order not consistent

With Cairo ERC20:

  • Set Premint to 1 and enable Mintable. The constructor parameters appear as: recipient: felt, owner: felt
  • in addition to the above, enable Pausable. The constructor parameters appear as: owner: felt, recipient: felt

This is inconsistent and could cause confusion/incorrect usage.

cairo: erc165 import raises `Unknown identifier 'ERC165_supports_interface'.`

i believe

from openzeppelin.introspection.ERC165 import ERC165_supports_interface
...

@view
func supportsInterface{
        syscall_ptr: felt*,
        pedersen_ptr: HashBuiltin*,
        range_check_ptr
    }(interfaceId: felt) -> (success: felt):
    let (success) = ERC165_supports_interface(interfaceId)
    return (success)
end

should be

from openzeppelin.introspection.ERC165 import ERC165
...

@view
func supportsInterface{
        syscall_ptr: felt*,
        pedersen_ptr: HashBuiltin*,
        range_check_ptr
    }(interfaceId: felt) -> (success: felt):
    let (success) = ERC165.supports_interface(interfaceId)
    return (success)
end

Update Wizard compatibility

Love to see some Svelte out in the wild!

(current support for ERC20 and ERC721)

should be

(current support for ERC20, ERC721, ERC1155, and Governor)

<p>Select the kind of contract that you want (current support for ERC20 and ERC721), set your parameters and desired features (token name, symbol, premint amount, access control, etc.), and Contracts Wizard will generate all of the code necessary. The resulting code is ready to be compiled and deployed, or it can serve as a starting point and customized further with application specific logic.</p>

Use fixed package version when opening in Remix

Opening in Remix currently opens the source code as is on Remix. This works because of the new npm imports, but will automatically use the latest version on npm.

We should use a fixed package version to make sure the code continues to work in the future.

This should be implemented using the transformImport option in printContract, and the version field from the autogenerated openzeppelin-contracts.json file (see zip.ts for an example of how to use it).

Error in generating upgradeable contracts using npm module

This line https://github.com/OpenZeppelin/contracts-wizard/blob/master/packages/core/src/options.ts#L14 throws error for erc20.print({ ...erc20.defaults, upgradeable: 'uups'})

Error is:

TypeError: path_1.default.parse is not a function
    at upgradeableImport (options.js:17:29)
    at Object.transformImport (options.js:33:1)
    at print.js:16:45
    at Array.map (<anonymous>)
    at printContract (print.js:16:1)
    at Object.printERC20 [as print] (erc20.js:43:1)
    at index.ts:6:40
    at Generator.next (<anonymous>)
    at vendor.0.27.0-dev.1663251417197.js:137866:71
    at new Promise (<anonymous>)

Add global toggle for "Access Control" section

... like the Upgradeability section, and make sure that if it is enabled then the contract is actually inherited. Currently even if Ownable is selected, unless a feature like Mintable makes use of it the resulting contract will not have Ownable and this could be confusing for users.

Update with support for ERC721Votes

  • Add "Votes" option in ERC721 tab
  • Update "ERC20Votes" option in Governor tab to reflect it also works with ERC721Votes (no changes needed in the code, just the label)

Add Royalties for NFTs

Add options for users to be able to integrate royalties on their ERC721 and ERC1155 contracts. This is a suggested set of changes:

  • Include it on the options after selecting ERC721 or ERC1155.
    image
    Populating those fields would inherit from the tokenRoyalty contract and call the setDefaultRoyalty from the constructor.

  • Include this parts on the code:

    • An import for the new module: import "@openzeppelin/contracts/token/tokenERC/extensions/tokenERCRoyalty.sol";
    • An inheritance: contract MyToken is ERC721, AccessControl { We'll use Access control to handle the roles of who can set royalties.
    • This calls to the royalties functions:
    function setTokenRoyalty(
        uint256 tokenId,
        address recipient,
        uint96 fraction
    ) public onlyRole(ROYALTY_SETTER_ROLE) {
        _setTokenRoyalty(tokenId, recipient, fraction);
    }

    function setDefaultRoyalty(address recipient, uint96 fraction) public onlyRole(ROYALTY_SETTER_ROLE) {
        _setDefaultRoyalty(recipient, fraction);
    }
- [ ] This constructor: 
bytes32 public constant ROYALTY_SETTER_ROLE= keccak256("ROYALTY_SETTER_ROLE");
constructor() ERC721("MyToken", "MTK") {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(ROYALTY_SETTER_ROLE, msg.sender);
    }

Take into consideration for the ERC1155, if the user specifies royalties and select ERC1155Supply do not import it btwice into the code, since the royalties contract inherits from this module.

Cairo - Ownable missing owner view

Ownable should have the following function:

@view
func owner{
        syscall_ptr : felt*,
        pedersen_ptr : HashBuiltin*,
        range_check_ptr
    }() -> (owner: felt):
    let (owner: felt) = Ownable.owner()
    return (owner)
end

Set up Tailwind CSS and replace utilities.css

I started this project using custom utility classes but if we want this project to follow this approach it would be better to just use Tailwind which comes with everything out of the box.

Personally I would really favor this, I've come to really enjoy working with Tailwind. Not having to come up with class names and abstractions is by itself worth it in my opinion.

Add Cairo API for a general contract

Related to #110 and #82

Requested for onlydustxyz/generator-starknet#28

Proposed API

New function:

function printGeneral(opts?: GeneralOptions): string

With the following interfaces:

interface GeneralOptions {
  name: string;
  access?: 'ownable' | false;
  upgradeable?: boolean;
  info?: {
    license?: string;
  };
  storageVars?: StorageVariable[];
}

interface StorageVariable {
  name: string;
  type: 'felt' | 'Uint256';
  view?: boolean;
  setInConstructor?: boolean;
}

Open questions

  • Feedback welcome on function or option names
  • Should the storage variables support arguments or multiple values? (this would increase complexity when posing the questions in the user interface (whether console or GUI))

Ownable is not implemented in Wizard. TL;DR the core features like "transfer" require access control by default.

Hi,

Just a quick observation from my experience with the Wizard (which is awesome by the way).

If a user selects the Ownable radio button in the Access Control section, the smart contract source code does not actually implement any ownable functionality. For example, the following code is generated.

Example 1

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
    constructor() ERC20("MyToken", "MTK") {}
}

Instead, the code should look more like the following.

Example 2

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {
    constructor() ERC20("MyToken", "MTK") {}
}

If the code from example 1 is deployed anyone can send tokens to anyone and so forth. There is not concept of ownership implemented.

This can be tested by deploying the code from example 1 and then instantiating an ERC20 contract instance using:

  • the contract address from example 1's deployment
  • the ABI from example 2's compile

Querying the owner will return a zero address 0x0...00 and any functions where the onlyOwner modifier should be implemented i.e. transfer will be callable by anyone and still succeed.

Hope this makes sense :)
Thanks

Add a "General" tab

We want to add a tab that is more of a "blank canvas" boilerplate builder so people can choose independent features and build an Ownable + UUPSUpgradeable contract easily that is not necessarily an ERC20 or any of the other options.

Depends on #82 for the access control section to make sense.

Support out of sync version for upgradeable contracts

Sometimes the versioning for @openzeppelin/contracts and @openzeppelin/contracts-upgradeable gets out of sync because we need to release fixes specific for the upgradeable contracts. This is not supported in Wizard currently and we were not able to merge #96 as a result. The specific problem is that the version included in the source code when opening in Remix is taken from the non-upgradeable contracts. We need to be aware of both versions and choose accordingly.

Correct generation of supportsInterface for ERC Tokens using Access Control

When generating ERC tokens using the open zeppelin wizard
erc1155OpenZeppelinWizard
The code generated is as follows

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "[@openzeppelin/contracts/token/ERC1155/ERC1155.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.3/contracts/token/ERC1155/ERC1155.sol)";
import "[@openzeppelin/contracts/access/AccessControl.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.3/contracts/access/AccessControl.sol)";

contract MyToken is ERC1155, AccessControl {
    bytes32 public constant URI_SETTER_ROLE = keccak256("URI_SETTER_ROLE");

    constructor() ERC1155("") {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(URI_SETTER_ROLE, msg.sender);
    }

    function setURI(string memory newuri) public onlyRole(URI_SETTER_ROLE) {
        _setURI(newuri);
    }

    // The following functions are overrides required by Solidity.

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC1155, AccessControl)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}

However the supportsInterface function should be

 function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC1155, AccessControl)
        returns (bool)
    {
        return (ERC1155.supportsInterface(interfaceId) ||
            AccessControl.supportsInterface(interfaceId));
    }

This was discussed here on the open zeppelin forum. Where it was stated

The generated code should be more like this

function supportsInterface(bytes4 interfaceId) public view override(ERC721, AccessControl, ERC2981, IERC165, ERC165) returns (bool) {
        return (
            ERC1155.supportsInterface(interfaceId) || 
            AccessControl.supportsInterface(interfaceId) ||
            ERC2981.supportsInterface(interfaceId) ||
            ERC165.supportsInterface(interfaceId)
        );
    }

package/ui start problem

When run the command npm run dev shows the error:
[!] (plugin at position 2) Error: spawn yarn ENOENT

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.