openzeppelin / contracts-wizard Goto Github PK
View Code? Open in Web Editor NEWInteractive smart contract generator based on OpenZeppelin Contracts.
Home Page: https://wizard.openzeppelin.com
License: MIT License
Interactive smart contract generator based on OpenZeppelin Contracts.
Home Page: https://wizard.openzeppelin.com
License: MIT License
Requested for onlydustxyz/generator-starknet#28
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;
}
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:
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
When run the command npm run dev shows the error:
[!] (plugin at position 2) Error: spawn yarn ENOENT
Inherit Multicall
for adding batch function calls.
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>)
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.
There is a setURI
onlyOwner
(or role) function by default that can't be removed. We don't have an option for owner-less ERC1155.
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
When hovering over tooltips, the URLs should point to content under https://docs.openzeppelin.com/contracts-cairo/
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
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.
Add roles-based access control, pending OpenZeppelin/cairo-contracts#249
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
Add support for Cairo for StarkNet, making use of OpenZeppelin Contracts for Cairo.
core-cairo
packagecore-cairo
packagefunc
and end
keywords_from
highlighting_from
to from_
setTokenURI
?safeMint
instead of mint
?TRUE
to use from starkware.cairo.common.bool import TRUE
TRUE
cairo-core
testsWhen selecting ERC20 with Votes and Upgradeability, the initializer should call __ERC20Votes_init()
as a best practice.
The new release (v0.25.0) of Remix IDE added support for UUPS upgradeable contracts (see ethereum/remix-project#2260 for the specific commit).
Thus, the warning tooltip introduced in #63 can be removed if the UUPS option is selected.
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).
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).
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)
With Cairo ERC20:
recipient: felt, owner: felt
owner: felt, recipient: felt
This is inconsistent and could cause confusion/incorrect usage.
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.
Populating those fields would inherit from the tokenRoyalty contract and call the setDefaultRoyalty from the constructor.
Include this parts on the code:
import "@openzeppelin/contracts/token/tokenERC/extensions/tokenERCRoyalty.sol";
contract MyToken is ERC721, AccessControl {
We'll use Access control to handle the roles of who can set royalties. 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.
This is an area where the Wizard can add a ton of value. Particularly around initializers.
Currently ownership and roles are assigned to msg.sender
, which is a problem for factory contracts. We can have a toggle to use a constructor parameter instead.
Governor with UUPS currently uses onlyOwner
for the _authorizeUpgrade
function. Instead, change this to onlyGovernance
.
Add burnFrom
similar to the function in Solidity's ERC20Burnable extension.
Solidity equivalent of #127
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.
... 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.
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.
The user may not be aware that upgradeable contracts have to be deployed behind a proxy, and deploying with Remix may produce unexpected results. Example support request.
When generating ERC tokens using the open zeppelin wizard
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)
);
}
There are extra spaces (an empty line and unnecessary indents) before // SPDX-License-Identifier
This started occurring after this commit e1495b3 and appears to be caused by an updated dependency.
Contracts 4.6.0 introduced reinitializers, so Wizard should change the upgradeable implementation's constructor to use
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
as per the note in https://docs.openzeppelin.com/contracts/4.x/api/proxy#Initializable
In Cairo 0.10 the syntax will change from Python-like to curly braces.
See Syntax Changes section on this document.
We have to synchronize this with the relevant release of OpenZeppelin Contracts for Cairo. OpenZeppelin/cairo-contracts#403
This will come in about a couple of weeks.
Breaking changes that affect Wizard:
Release branch: cairo/next
Release checklist (after cairo-contracts is released):
contractsVersion
string in https://github.com/OpenZeppelin/contracts-wizard/blob/cairo/next/packages/core-cairo/src/utils/version.ts to the latest released version number of cairo-contractscairo/next
to master
@openzeppelin/wizard-cairo
to npm from packages/core-cairo
packages/core-cairo/CHANGELOG.md
0.4.0
since it's a breaking change), tag, and publish, e.g: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
This will probably help a lot of users when they go on to verify their contracts, since the version of Solidity is clear from the source.
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.
The button should briefly flash a check mark or something similar to give feedback that code was successfully copied.
Add ERC777 token with
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.