diff --git a/README.md b/README.md index f2c2a843f..c3257711c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ Contracts Wizard is a web application to interactively build a contract out of c ## Development -`packages/core` contains the code generation logic. +`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. @@ -22,4 +24,8 @@ Then place `` in the body where you want Contracts Wizard Optionally focus on specific tab with the `data-tab` attribute as in ``. -For Cairo, use the `data-lang` attribute: ``. \ No newline at end of file +For Cairo, use the `data-lang` attribute: ``. + +## API + +See [API documentation](docs/API.md) for provided APIs. \ No newline at end of file diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 000000000..45a3dccf6 --- /dev/null +++ b/docs/API.md @@ -0,0 +1,41 @@ +# API + +The following describes how to use the Contracts Wizard programmatic API in your own applications. + +## Cairo + +### Installation + +`npm install @openzeppelin/wizard-cairo` + +### Functions + +#### `printERC20` +```js +function printERC20(opts?: ERC20Options): string +``` +Returns a string representation of an ERC20 contract generated using the provided options. If `opts` is not provided, uses [`erc20defaults`](#erc20defaults). + +#### `printERC721` +```js +function printERC721(opts?: ERC721Options): string +``` +Returns a string representation of an ERC721 contract generated using the provided options. If `opts` is not provided, uses [`erc721defaults`](#erc721defaults). + +### Defaults + +#### `erc20defaults` +```js +const erc20defaults: Required +``` +The default options that are used for [`printERC20`](#printerc20). + +#### `erc721defaults` +```js +const erc721defaults: Required +``` +The default options that are used for [`printERC721`](#printerc721). + +## Solidity + +Contracts Wizard API for Solidity is not available yet. Please reach out to us on [issue #129](https://github.com/OpenZeppelin/contracts-wizard/issues/129) if you would be interested in it. diff --git a/packages/core-cairo/CHANGELOG.md b/packages/core-cairo/CHANGELOG.md new file mode 100644 index 000000000..a0c40d8b8 --- /dev/null +++ b/packages/core-cairo/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## Unreleased + +- Initial API for Cairo. ([#127](https://github.com/OpenZeppelin/contracts-wizard/pull/127)) diff --git a/packages/core-cairo/package.json b/packages/core-cairo/package.json index dc3200880..753ebb947 100644 --- a/packages/core-cairo/package.json +++ b/packages/core-cairo/package.json @@ -1,9 +1,9 @@ { - "name": "core-cairo", - "version": "0.0.1", + "name": "@openzeppelin/wizard-cairo", + "version": "0.1.0", "description": "A boilerplate generator to get started with OpenZeppelin Contracts for Cairo", "license": "MIT", - "repository": "github:OpenZeppelin/wizard", + "repository": "github:OpenZeppelin/contracts-wizard", "main": "dist/index.js", "ts:main": "src/index.ts", "files": [ diff --git a/packages/core-cairo/src/common-options.ts b/packages/core-cairo/src/common-options.ts index 5cca69d08..f46a76196 100644 --- a/packages/core-cairo/src/common-options.ts +++ b/packages/core-cairo/src/common-options.ts @@ -1,8 +1,15 @@ import type { Argument } from "./contract"; import type { Access } from "./set-access-control"; import type { Info } from "./set-info"; +import { defaults as infoDefaults } from "./set-info"; import type { Upgradeable } from "./set-upgradeable"; +export const defaults: Required = { + access: 'ownable', + upgradeable: false, + info: infoDefaults, +} as const; + export interface CommonOptions { access?: Access; upgradeable?: Upgradeable; @@ -11,9 +18,9 @@ export interface CommonOptions { export function withCommonDefaults(opts: CommonOptions): Required { return { - access: opts.access ?? 'ownable', - upgradeable: opts.upgradeable ?? false, - info: opts.info ?? {}, + access: opts.access ?? defaults.access, + upgradeable: opts.upgradeable ?? defaults.upgradeable, + info: opts.info ?? defaults.info, }; } diff --git a/packages/core-cairo/src/erc20.test.ts b/packages/core-cairo/src/erc20.test.ts index c91c1fd8d..17425ea68 100644 --- a/packages/core-cairo/src/erc20.test.ts +++ b/packages/core-cairo/src/erc20.test.ts @@ -3,6 +3,8 @@ import test from 'ava'; import { buildERC20, ERC20Options } from './erc20'; import { printContract } from './print'; +import { printERC20, erc20defaults } from '.'; + function testERC20(title: string, opts: Partial) { test(title, t => { const c = buildERC20({ @@ -14,6 +16,12 @@ function testERC20(title: string, opts: Partial) { }); } +function testERC20API(title: string, opts?: ERC20Options) { + test(title, t => { + t.snapshot(printERC20(opts)); + }); +} + testERC20('basic erc20', {}); testERC20('erc20 burnable', { @@ -43,18 +51,30 @@ testERC20('erc20 mintable', { access: 'ownable', }); -testERC20('erc20 full upgradeable transparent', { +testERC20('erc20 full upgradeable', { premint: '2000', + decimals: '9', burnable: true, mintable: true, pausable: true, upgradeable: true, }); -testERC20('erc20 full upgradeable uups', { +testERC20API('erc20 API default'); + +testERC20API('erc20 API basic', { name: 'CustomToken', symbol: 'CTK' }); + +testERC20API('erc20 API full upgradeable', { + name: 'CustomToken', + symbol: 'CTK', premint: '2000', + decimals: '9', burnable: true, mintable: true, pausable: true, upgradeable: true, }); + +test('erc20 API assert defaults', async t => { + t.is(printERC20(erc20defaults), printERC20()); +}); \ No newline at end of file diff --git a/packages/core-cairo/src/erc20.test.ts.md b/packages/core-cairo/src/erc20.test.ts.md index efd6bb036..635de8e4b 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -1239,7 +1239,7 @@ Generated by [AVA](https://avajs.dev). end␊ ` -## erc20 full upgradeable transparent +## erc20 full upgradeable > Snapshot 1 @@ -1290,11 +1290,11 @@ Generated by [AVA](https://avajs.dev). pedersen_ptr: HashBuiltin*,␊ range_check_ptr␊ }(owner: felt, recipient: felt, proxy_admin: felt):␊ - ERC20_initializer('MyToken', 'MTK', 18)␊ + ERC20_initializer('MyToken', 'MTK', 9)␊ Ownable_initializer(owner)␊ Proxy_initializer(proxy_admin)␊ ␊ - ERC20_mint(recipient, Uint256(2000000000000000000000, 0))␊ + ERC20_mint(recipient, Uint256(2000000000000, 0))␊ return ()␊ end␊ ␊ @@ -1488,7 +1488,319 @@ Generated by [AVA](https://avajs.dev). end␊ ` -## erc20 full upgradeable uups +## erc20 API default + +> Snapshot 1 + + `# SPDX-License-Identifier: MIT␊ + ␊ + %lang starknet␊ + ␊ + from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + from starkware.cairo.common.uint256 import Uint256␊ + from starkware.cairo.common.bool import TRUE␊ + ␊ + from openzeppelin.token.erc20.library import (␊ + ERC20_name,␊ + ERC20_symbol,␊ + ERC20_totalSupply,␊ + ERC20_decimals,␊ + ERC20_balanceOf,␊ + ERC20_allowance,␊ + ERC20_transfer,␊ + ERC20_transferFrom,␊ + ERC20_approve,␊ + ERC20_increaseAllowance,␊ + ERC20_decreaseAllowance,␊ + ERC20_initializer,␊ + )␊ + ␊ + @constructor␊ + func constructor{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }():␊ + ERC20_initializer('MyToken', 'MTK', 18)␊ + return ()␊ + end␊ + ␊ + #␊ + # Getters␊ + #␊ + ␊ + @view␊ + func name{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (name: felt):␊ + let (name) = ERC20_name()␊ + return (name)␊ + end␊ + ␊ + @view␊ + func symbol{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (symbol: felt):␊ + let (symbol) = ERC20_symbol()␊ + return (symbol)␊ + end␊ + ␊ + @view␊ + func totalSupply{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (totalSupply: Uint256):␊ + let (totalSupply) = ERC20_totalSupply()␊ + return (totalSupply)␊ + end␊ + ␊ + @view␊ + func decimals{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (decimals: felt):␊ + let (decimals) = ERC20_decimals()␊ + return (decimals)␊ + end␊ + ␊ + @view␊ + func balanceOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(account: felt) -> (balance: Uint256):␊ + let (balance) = ERC20_balanceOf(account)␊ + return (balance)␊ + end␊ + ␊ + @view␊ + func allowance{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt, spender: felt) -> (remaining: Uint256):␊ + let (remaining) = ERC20_allowance(owner, spender)␊ + return (remaining)␊ + end␊ + ␊ + #␊ + # Externals␊ + #␊ + ␊ + @external␊ + func transfer{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(recipient: felt, amount: Uint256) -> (success: felt):␊ + ERC20_transfer(recipient, amount)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func transferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(sender: felt, recipient: felt, amount: Uint256) -> (success: felt):␊ + ERC20_transferFrom(sender, recipient, amount)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func approve{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(spender: felt, amount: Uint256) -> (success: felt):␊ + ERC20_approve(spender, amount)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func increaseAllowance{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(spender: felt, added_value: Uint256) -> (success: felt):␊ + ERC20_increaseAllowance(spender, added_value)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func decreaseAllowance{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(spender: felt, subtracted_value: Uint256) -> (success: felt):␊ + ERC20_decreaseAllowance(spender, subtracted_value)␊ + return (TRUE)␊ + end␊ + ` + +## erc20 API basic + +> Snapshot 1 + + `# SPDX-License-Identifier: MIT␊ + ␊ + %lang starknet␊ + ␊ + from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + from starkware.cairo.common.uint256 import Uint256␊ + from starkware.cairo.common.bool import TRUE␊ + ␊ + from openzeppelin.token.erc20.library import (␊ + ERC20_name,␊ + ERC20_symbol,␊ + ERC20_totalSupply,␊ + ERC20_decimals,␊ + ERC20_balanceOf,␊ + ERC20_allowance,␊ + ERC20_transfer,␊ + ERC20_transferFrom,␊ + ERC20_approve,␊ + ERC20_increaseAllowance,␊ + ERC20_decreaseAllowance,␊ + ERC20_initializer,␊ + )␊ + ␊ + @constructor␊ + func constructor{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }():␊ + ERC20_initializer('CustomToken', 'CTK', 18)␊ + return ()␊ + end␊ + ␊ + #␊ + # Getters␊ + #␊ + ␊ + @view␊ + func name{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (name: felt):␊ + let (name) = ERC20_name()␊ + return (name)␊ + end␊ + ␊ + @view␊ + func symbol{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (symbol: felt):␊ + let (symbol) = ERC20_symbol()␊ + return (symbol)␊ + end␊ + ␊ + @view␊ + func totalSupply{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (totalSupply: Uint256):␊ + let (totalSupply) = ERC20_totalSupply()␊ + return (totalSupply)␊ + end␊ + ␊ + @view␊ + func decimals{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (decimals: felt):␊ + let (decimals) = ERC20_decimals()␊ + return (decimals)␊ + end␊ + ␊ + @view␊ + func balanceOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(account: felt) -> (balance: Uint256):␊ + let (balance) = ERC20_balanceOf(account)␊ + return (balance)␊ + end␊ + ␊ + @view␊ + func allowance{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt, spender: felt) -> (remaining: Uint256):␊ + let (remaining) = ERC20_allowance(owner, spender)␊ + return (remaining)␊ + end␊ + ␊ + #␊ + # Externals␊ + #␊ + ␊ + @external␊ + func transfer{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(recipient: felt, amount: Uint256) -> (success: felt):␊ + ERC20_transfer(recipient, amount)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func transferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(sender: felt, recipient: felt, amount: Uint256) -> (success: felt):␊ + ERC20_transferFrom(sender, recipient, amount)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func approve{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(spender: felt, amount: Uint256) -> (success: felt):␊ + ERC20_approve(spender, amount)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func increaseAllowance{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(spender: felt, added_value: Uint256) -> (success: felt):␊ + ERC20_increaseAllowance(spender, added_value)␊ + return (TRUE)␊ + end␊ + ␊ + @external␊ + func decreaseAllowance{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(spender: felt, subtracted_value: Uint256) -> (success: felt):␊ + ERC20_decreaseAllowance(spender, subtracted_value)␊ + return (TRUE)␊ + end␊ + ` + +## erc20 API full upgradeable > Snapshot 1 @@ -1539,11 +1851,11 @@ Generated by [AVA](https://avajs.dev). pedersen_ptr: HashBuiltin*,␊ range_check_ptr␊ }(owner: felt, recipient: felt, proxy_admin: felt):␊ - ERC20_initializer('MyToken', 'MTK', 18)␊ + ERC20_initializer('CustomToken', 'CTK', 9)␊ Ownable_initializer(owner)␊ Proxy_initializer(proxy_admin)␊ ␊ - ERC20_mint(recipient, Uint256(2000000000000000000000, 0))␊ + ERC20_mint(recipient, Uint256(2000000000000, 0))␊ return ()␊ end␊ ␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 0dd03a891..10f662123 100644 Binary files a/packages/core-cairo/src/erc20.test.ts.snap and b/packages/core-cairo/src/erc20.test.ts.snap differ diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index dfad166b4..dd9c3bff4 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -8,15 +8,26 @@ import { setInfo } from './set-info'; import { OptionsError } from './error'; import BN from 'bn.js'; import { defineModules } from './utils/define-modules'; +import { defaults as commonDefaults } from './common-options'; +import { printContract } from './print'; -export const defaults = { +export const defaults: Required = { + name: 'MyToken', + symbol: 'MTK', burnable: false, pausable: false, premint: '0', - mintable: false, decimals: '18', + mintable: false, + access: commonDefaults.access, + upgradeable: commonDefaults.upgradeable, + info: commonDefaults.info } as const; +export function printERC20(opts: ERC20Options = defaults): string { + return printContract(buildERC20(opts)); +} + export interface ERC20Options extends CommonOptions { name: string; symbol: string; diff --git a/packages/core-cairo/src/erc721.test.ts b/packages/core-cairo/src/erc721.test.ts index 35f7ed6cb..481ff40c6 100644 --- a/packages/core-cairo/src/erc721.test.ts +++ b/packages/core-cairo/src/erc721.test.ts @@ -3,6 +3,8 @@ import test from 'ava'; import { buildERC721, ERC721Options } from './erc721'; import { printContract } from './print'; +import { printERC721, erc721defaults } from '.'; + function testERC721(title: string, opts: Partial) { test(title, t => { const c = buildERC721({ @@ -14,6 +16,12 @@ function testERC721(title: string, opts: Partial) { }); } +function testERC721API(title: string, opts?: ERC721Options) { + test(title, t => { + t.snapshot(printERC721(opts)); + }); +} + testERC721('basic', {}); testERC721('burnable', { @@ -34,3 +42,20 @@ testERC721('full upgradeable', { burnable: true, upgradeable: true, }); + +testERC721API('API default'); + +testERC721API('API basic', { name: 'CustomToken', symbol: 'CTK' }); + +testERC721API('API full upgradeable', { + name: 'CustomToken', + symbol: 'CTK', + burnable: true, + mintable: true, + pausable: true, + upgradeable: true, +}); + +test('API assert defaults', async t => { + t.is(printERC721(erc721defaults), printERC721()); +}); \ No newline at end of file diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index 567bc6db0..e3219f110 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -1005,3 +1005,594 @@ Generated by [AVA](https://avajs.dev). return ()␊ end␊ ` + +## API default + +> Snapshot 1 + + `# SPDX-License-Identifier: MIT␊ + ␊ + %lang starknet␊ + ␊ + from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + from starkware.cairo.common.uint256 import Uint256␊ + ␊ + from openzeppelin.token.erc721.library import (␊ + ERC721_name,␊ + ERC721_symbol,␊ + ERC721_balanceOf,␊ + ERC721_ownerOf,␊ + ERC721_getApproved,␊ + ERC721_isApprovedForAll,␊ + ERC721_tokenURI,␊ + ERC721_approve,␊ + ERC721_setApprovalForAll,␊ + ERC721_transferFrom,␊ + ERC721_safeTransferFrom,␊ + ERC721_initializer,␊ + )␊ + from openzeppelin.introspection.ERC165 import ERC165_supports_interface␊ + ␊ + @constructor␊ + func constructor{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }():␊ + ERC721_initializer('MyToken', 'MTK')␊ + return ()␊ + end␊ + ␊ + #␊ + # Getters␊ + #␊ + ␊ + @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␊ + ␊ + @view␊ + func name{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (name: felt):␊ + let (name) = ERC721_name()␊ + return (name)␊ + end␊ + ␊ + @view␊ + func symbol{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (symbol: felt):␊ + let (symbol) = ERC721_symbol()␊ + return (symbol)␊ + end␊ + ␊ + @view␊ + func balanceOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt) -> (balance: Uint256):␊ + let (balance) = ERC721_balanceOf(owner)␊ + return (balance)␊ + end␊ + ␊ + @view␊ + func ownerOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(token_id: Uint256) -> (owner: felt):␊ + let (owner) = ERC721_ownerOf(token_id)␊ + return (owner)␊ + end␊ + ␊ + @view␊ + func getApproved{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(token_id: Uint256) -> (approved: felt):␊ + let (approved) = ERC721_getApproved(token_id)␊ + return (approved)␊ + end␊ + ␊ + @view␊ + func isApprovedForAll{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt, operator: felt) -> (isApproved: felt):␊ + let (isApproved) = ERC721_isApprovedForAll(owner, operator)␊ + return (isApproved)␊ + end␊ + ␊ + @view␊ + func tokenURI{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(tokenId: Uint256) -> (tokenURI: felt):␊ + let (tokenURI) = ERC721_tokenURI(tokenId)␊ + return (tokenURI)␊ + end␊ + ␊ + #␊ + # Externals␊ + #␊ + ␊ + @external␊ + func approve{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(to: felt, tokenId: Uint256):␊ + ERC721_approve(to, tokenId)␊ + return ()␊ + end␊ + ␊ + @external␊ + func setApprovalForAll{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(operator: felt, approved: felt):␊ + ERC721_setApprovalForAll(operator, approved)␊ + return ()␊ + end␊ + ␊ + @external␊ + func transferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(from_: felt, to: felt, tokenId: Uint256):␊ + ERC721_transferFrom(from_, to, tokenId)␊ + return ()␊ + end␊ + ␊ + @external␊ + func safeTransferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*):␊ + ERC721_safeTransferFrom(from_, to, tokenId, data_len, data)␊ + return ()␊ + end␊ + ` + +## API basic + +> Snapshot 1 + + `# SPDX-License-Identifier: MIT␊ + ␊ + %lang starknet␊ + ␊ + from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + from starkware.cairo.common.uint256 import Uint256␊ + ␊ + from openzeppelin.token.erc721.library import (␊ + ERC721_name,␊ + ERC721_symbol,␊ + ERC721_balanceOf,␊ + ERC721_ownerOf,␊ + ERC721_getApproved,␊ + ERC721_isApprovedForAll,␊ + ERC721_tokenURI,␊ + ERC721_approve,␊ + ERC721_setApprovalForAll,␊ + ERC721_transferFrom,␊ + ERC721_safeTransferFrom,␊ + ERC721_initializer,␊ + )␊ + from openzeppelin.introspection.ERC165 import ERC165_supports_interface␊ + ␊ + @constructor␊ + func constructor{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }():␊ + ERC721_initializer('CustomToken', 'CTK')␊ + return ()␊ + end␊ + ␊ + #␊ + # Getters␊ + #␊ + ␊ + @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␊ + ␊ + @view␊ + func name{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (name: felt):␊ + let (name) = ERC721_name()␊ + return (name)␊ + end␊ + ␊ + @view␊ + func symbol{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (symbol: felt):␊ + let (symbol) = ERC721_symbol()␊ + return (symbol)␊ + end␊ + ␊ + @view␊ + func balanceOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt) -> (balance: Uint256):␊ + let (balance) = ERC721_balanceOf(owner)␊ + return (balance)␊ + end␊ + ␊ + @view␊ + func ownerOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(token_id: Uint256) -> (owner: felt):␊ + let (owner) = ERC721_ownerOf(token_id)␊ + return (owner)␊ + end␊ + ␊ + @view␊ + func getApproved{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(token_id: Uint256) -> (approved: felt):␊ + let (approved) = ERC721_getApproved(token_id)␊ + return (approved)␊ + end␊ + ␊ + @view␊ + func isApprovedForAll{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt, operator: felt) -> (isApproved: felt):␊ + let (isApproved) = ERC721_isApprovedForAll(owner, operator)␊ + return (isApproved)␊ + end␊ + ␊ + @view␊ + func tokenURI{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(tokenId: Uint256) -> (tokenURI: felt):␊ + let (tokenURI) = ERC721_tokenURI(tokenId)␊ + return (tokenURI)␊ + end␊ + ␊ + #␊ + # Externals␊ + #␊ + ␊ + @external␊ + func approve{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(to: felt, tokenId: Uint256):␊ + ERC721_approve(to, tokenId)␊ + return ()␊ + end␊ + ␊ + @external␊ + func setApprovalForAll{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(operator: felt, approved: felt):␊ + ERC721_setApprovalForAll(operator, approved)␊ + return ()␊ + end␊ + ␊ + @external␊ + func transferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(from_: felt, to: felt, tokenId: Uint256):␊ + ERC721_transferFrom(from_, to, tokenId)␊ + return ()␊ + end␊ + ␊ + @external␊ + func safeTransferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*):␊ + ERC721_safeTransferFrom(from_, to, tokenId, data_len, data)␊ + return ()␊ + end␊ + ` + +## API full upgradeable + +> Snapshot 1 + + `# SPDX-License-Identifier: MIT␊ + ␊ + %lang starknet␊ + ␊ + from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + from starkware.cairo.common.uint256 import Uint256␊ + ␊ + from openzeppelin.token.erc721.library import (␊ + ERC721_name,␊ + ERC721_symbol,␊ + ERC721_balanceOf,␊ + ERC721_ownerOf,␊ + ERC721_getApproved,␊ + ERC721_isApprovedForAll,␊ + ERC721_tokenURI,␊ + ERC721_approve,␊ + ERC721_setApprovalForAll,␊ + ERC721_transferFrom,␊ + ERC721_safeTransferFrom,␊ + ERC721_burn,␊ + ERC721_safeMint,␊ + ERC721_initializer,␊ + ERC721_only_token_owner,␊ + ERC721_setTokenURI,␊ + )␊ + from openzeppelin.introspection.ERC165 import ERC165_supports_interface␊ + from openzeppelin.security.pausable import (␊ + Pausable_paused,␊ + Pausable_pause,␊ + Pausable_unpause,␊ + Pausable_when_not_paused,␊ + )␊ + from openzeppelin.access.ownable import (␊ + Ownable_initializer,␊ + Ownable_only_owner,␊ + )␊ + from openzeppelin.upgrades.library import (␊ + Proxy_initializer,␊ + Proxy_only_admin,␊ + Proxy_set_implementation,␊ + )␊ + ␊ + @external␊ + func initializer{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt, proxy_admin: felt):␊ + ERC721_initializer('CustomToken', 'CTK')␊ + Ownable_initializer(owner)␊ + Proxy_initializer(proxy_admin)␊ + return ()␊ + end␊ + ␊ + #␊ + # Getters␊ + #␊ + ␊ + @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␊ + ␊ + @view␊ + func name{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (name: felt):␊ + let (name) = ERC721_name()␊ + return (name)␊ + end␊ + ␊ + @view␊ + func symbol{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (symbol: felt):␊ + let (symbol) = ERC721_symbol()␊ + return (symbol)␊ + end␊ + ␊ + @view␊ + func balanceOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt) -> (balance: Uint256):␊ + let (balance) = ERC721_balanceOf(owner)␊ + return (balance)␊ + end␊ + ␊ + @view␊ + func ownerOf{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(token_id: Uint256) -> (owner: felt):␊ + let (owner) = ERC721_ownerOf(token_id)␊ + return (owner)␊ + end␊ + ␊ + @view␊ + func getApproved{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(token_id: Uint256) -> (approved: felt):␊ + let (approved) = ERC721_getApproved(token_id)␊ + return (approved)␊ + end␊ + ␊ + @view␊ + func isApprovedForAll{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(owner: felt, operator: felt) -> (isApproved: felt):␊ + let (isApproved) = ERC721_isApprovedForAll(owner, operator)␊ + return (isApproved)␊ + end␊ + ␊ + @view␊ + func tokenURI{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(tokenId: Uint256) -> (tokenURI: felt):␊ + let (tokenURI) = ERC721_tokenURI(tokenId)␊ + return (tokenURI)␊ + end␊ + ␊ + @view␊ + func paused{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }() -> (paused: felt):␊ + let (paused) = Pausable_paused.read()␊ + return (paused)␊ + end␊ + ␊ + #␊ + # Externals␊ + #␊ + ␊ + @external␊ + func approve{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(to: felt, tokenId: Uint256):␊ + Pausable_when_not_paused()␊ + ERC721_approve(to, tokenId)␊ + return ()␊ + end␊ + ␊ + @external␊ + func setApprovalForAll{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(operator: felt, approved: felt):␊ + Pausable_when_not_paused()␊ + ERC721_setApprovalForAll(operator, approved)␊ + return ()␊ + end␊ + ␊ + @external␊ + func transferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(from_: felt, to: felt, tokenId: Uint256):␊ + Pausable_when_not_paused()␊ + ERC721_transferFrom(from_, to, tokenId)␊ + return ()␊ + end␊ + ␊ + @external␊ + func safeTransferFrom{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*):␊ + Pausable_when_not_paused()␊ + ERC721_safeTransferFrom(from_, to, tokenId, data_len, data)␊ + return ()␊ + end␊ + ␊ + @external␊ + func pause{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }():␊ + Ownable_only_owner()␊ + Pausable_pause()␊ + return ()␊ + end␊ + ␊ + @external␊ + func unpause{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }():␊ + Ownable_only_owner()␊ + Pausable_unpause()␊ + return ()␊ + end␊ + ␊ + @external␊ + func burn{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(tokenId: Uint256):␊ + Pausable_when_not_paused()␊ + ERC721_only_token_owner(tokenId)␊ + ERC721_burn(tokenId)␊ + return ()␊ + end␊ + ␊ + @external␊ + func safeMint{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(to: felt, tokenId: Uint256, data_len: felt, data: felt*, tokenURI: felt):␊ + Pausable_when_not_paused()␊ + Ownable_only_owner()␊ + ERC721_safeMint(to, tokenId, data_len, data)␊ + ERC721_setTokenURI(tokenId, tokenURI)␊ + return ()␊ + end␊ + ␊ + @external␊ + func upgrade{␊ + syscall_ptr: felt*,␊ + pedersen_ptr: HashBuiltin*,␊ + range_check_ptr␊ + }(new_implementation: felt) -> ():␊ + Proxy_only_admin()␊ + Proxy_set_implementation(new_implementation)␊ + return ()␊ + end␊ + ` diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index 32df87386..9736bf90d 100644 Binary files a/packages/core-cairo/src/erc721.test.ts.snap and b/packages/core-cairo/src/erc721.test.ts.snap differ diff --git a/packages/core-cairo/src/erc721.ts b/packages/core-cairo/src/erc721.ts index 02ae0a69e..4c8e879d2 100644 --- a/packages/core-cairo/src/erc721.ts +++ b/packages/core-cairo/src/erc721.ts @@ -6,6 +6,23 @@ import { CommonOptions, withCommonDefaults, withImplicitArgs } from './common-op import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { defineModules } from './utils/define-modules'; +import { defaults as commonDefaults } from './common-options'; +import { printContract } from './print'; + +export const defaults: Required = { + name: 'MyToken', + symbol: 'MTK', + burnable: false, + pausable: false, + mintable: false, + access: commonDefaults.access, + upgradeable: commonDefaults.upgradeable, + info: commonDefaults.info +} as const; + +export function printERC721(opts: ERC721Options = defaults): string { + return printContract(buildERC721(opts)); +} export interface ERC721Options extends CommonOptions { name: string; @@ -15,12 +32,22 @@ export interface ERC721Options extends CommonOptions { mintable?: boolean; } +function withDefaults(opts: ERC721Options): Required { + return { + ...opts, + ...withCommonDefaults(opts), + burnable: opts.burnable ?? defaults.burnable, + pausable: opts.pausable ?? defaults.pausable, + mintable: opts.mintable ?? defaults.mintable, + }; +} + export function buildERC721(opts: ERC721Options): Contract { const c = new ContractBuilder(); - const { access, upgradeable, info } = withCommonDefaults(opts); + const allOpts = withDefaults(opts); - addBase(c, opts.name, opts.symbol); + addBase(c, allOpts.name, allOpts.symbol); addSupportsInterface(c); c.addFunction(functions.name); @@ -36,27 +63,27 @@ export function buildERC721(opts: ERC721Options): Contract { c.addFunction(functions.transferFrom); c.addFunction(functions.safeTransferFrom); - if (opts.pausable) { - addPausable(c, access, [functions.approve, functions.setApprovalForAll, functions.transferFrom, functions.safeTransferFrom]); - if (opts.burnable) { + if (allOpts.pausable) { + addPausable(c, allOpts.access, [functions.approve, functions.setApprovalForAll, functions.transferFrom, functions.safeTransferFrom]); + if (allOpts.burnable) { setPausable(c, functions.burn); } - if (opts.mintable) { + if (allOpts.mintable) { setPausable(c, functions.safeMint); } } - if (opts.burnable) { + if (allOpts.burnable) { addBurnable(c); } - if (opts.mintable) { - addMintable(c, access); + if (allOpts.mintable) { + addMintable(c, allOpts.access); } - setUpgradeable(c, upgradeable); + setUpgradeable(c, allOpts.upgradeable); - setInfo(c, info); + setInfo(c, allOpts.info); return c; } diff --git a/packages/core-cairo/src/index.ts b/packages/core-cairo/src/index.ts index bb122798f..52a129d4c 100644 --- a/packages/core-cairo/src/index.ts +++ b/packages/core-cairo/src/index.ts @@ -10,7 +10,9 @@ export type { Access } from './set-access-control'; export type { Upgradeable } from './set-upgradeable'; export type { Info } from './set-info'; -export { premintPattern } from './erc20'; +export { premintPattern, defaults as erc20defaults, printERC20 } from './erc20'; +export { defaults as erc721defaults, printERC721 } from './erc721'; + export { defaults as infoDefaults } from './set-info'; export type { OptionsErrorMessages } from './error'; diff --git a/packages/core/package.json b/packages/core/package.json index 4d1419a36..521c32e4e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "description": "A boilerplate generator to get started with OpenZeppelin Contracts", "license": "MIT", - "repository": "github:OpenZeppelin/wizard", + "repository": "github:OpenZeppelin/contracts-wizard", "main": "dist/index.js", "ts:main": "src/index.ts", "files": [ diff --git a/packages/ui/src/cairo/App.svelte b/packages/ui/src/cairo/App.svelte index dc58f5309..36579f82c 100644 --- a/packages/ui/src/cairo/App.svelte +++ b/packages/ui/src/cairo/App.svelte @@ -13,8 +13,8 @@ import OverflowMenu from '../OverflowMenu.svelte'; import FileIcon from '../icons/FileIcon.svelte'; - import type { KindedOptions, Kind, Contract, OptionsErrorMessages } from 'core-cairo'; - import { ContractBuilder, buildGeneric, printContract, sanitizeKind, OptionsError } from 'core-cairo'; + import type { KindedOptions, Kind, Contract, OptionsErrorMessages } from '@openzeppelin/wizard-cairo'; + import { ContractBuilder, buildGeneric, printContract, sanitizeKind, OptionsError } from '@openzeppelin/wizard-cairo'; import { postConfig } from '../post-config'; import { saveAs } from 'file-saver'; diff --git a/packages/ui/src/cairo/ERC20Controls.svelte b/packages/ui/src/cairo/ERC20Controls.svelte index ecb69e9f7..1b7ffe74b 100644 --- a/packages/ui/src/cairo/ERC20Controls.svelte +++ b/packages/ui/src/cairo/ERC20Controls.svelte @@ -1,9 +1,8 @@ diff --git a/packages/ui/src/cairo/InfoSection.svelte b/packages/ui/src/cairo/InfoSection.svelte index e5c7b77fc..adeb1db74 100644 --- a/packages/ui/src/cairo/InfoSection.svelte +++ b/packages/ui/src/cairo/InfoSection.svelte @@ -1,6 +1,6 @@ diff --git a/packages/ui/src/cairo/UpgradeabilitySection.svelte b/packages/ui/src/cairo/UpgradeabilitySection.svelte index 35864e61d..d0885cb18 100644 --- a/packages/ui/src/cairo/UpgradeabilitySection.svelte +++ b/packages/ui/src/cairo/UpgradeabilitySection.svelte @@ -1,5 +1,5 @@