From 89f588d12141bd59bc97e3a5eea5c8a218e67d9c Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Mon, 4 Dec 2023 08:41:11 -0500 Subject: [PATCH 01/29] Support Cairo 1+ and Contracts for Cairo 0.8.0 --- .github/workflows/test.yml | 1 + packages/core-cairo/CHANGELOG.md | 8 + packages/core-cairo/package.json | 4 +- packages/core-cairo/src/add-pausable.ts | 94 +- packages/core-cairo/src/api.ts | 21 +- packages/core-cairo/src/build-generic.ts | 5 - packages/core-cairo/src/common-components.ts | 26 + packages/core-cairo/src/common-functions.ts | 45 - packages/core-cairo/src/common-options.ts | 8 +- packages/core-cairo/src/contract.test.ts | 117 +- packages/core-cairo/src/contract.test.ts.md | 159 +- packages/core-cairo/src/contract.test.ts.snap | Bin 519 -> 663 bytes packages/core-cairo/src/contract.ts | 247 +- packages/core-cairo/src/custom.test.ts | 5 +- packages/core-cairo/src/custom.test.ts.md | 486 ++-- packages/core-cairo/src/custom.test.ts.snap | Bin 920 -> 1133 bytes packages/core-cairo/src/custom.ts | 15 +- packages/core-cairo/src/erc1155.test.ts | 88 - packages/core-cairo/src/erc1155.test.ts.md | 1239 ---------- packages/core-cairo/src/erc1155.test.ts.snap | Bin 2183 -> 0 bytes packages/core-cairo/src/erc1155.ts | 330 --- packages/core-cairo/src/erc20.test.ts | 28 +- packages/core-cairo/src/erc20.test.ts.md | 2186 ++++++----------- packages/core-cairo/src/erc20.test.ts.snap | Bin 2136 -> 1967 bytes packages/core-cairo/src/erc20.ts | 368 +-- packages/core-cairo/src/erc721.test.ts | 2 +- packages/core-cairo/src/erc721.test.ts.md | 1293 ++++------ packages/core-cairo/src/erc721.test.ts.snap | Bin 1724 -> 1581 bytes packages/core-cairo/src/erc721.ts | 281 +-- packages/core-cairo/src/external-trait.ts | 10 + .../core-cairo/src/generate/alternatives.ts | 2 - packages/core-cairo/src/generate/erc20.ts | 8 +- packages/core-cairo/src/generate/erc721.ts | 4 - packages/core-cairo/src/generate/sources.ts | 2 +- packages/core-cairo/src/index.ts | 2 +- packages/core-cairo/src/kind.ts | 1 - packages/core-cairo/src/options.ts | 12 - packages/core-cairo/src/print.ts | 299 ++- packages/core-cairo/src/set-access-control.ts | 226 +- packages/core-cairo/src/set-upgradeable.ts | 59 +- packages/core-cairo/src/test.ts | 2 +- .../core-cairo/src/utils/define-components.ts | 18 + .../core-cairo/src/utils/define-modules.ts | 18 - packages/core-cairo/src/utils/hash-builtin.ts | 14 - packages/core-cairo/src/utils/imports-map.ts | 57 - packages/core-cairo/src/utils/map-values.ts | 10 - .../core-cairo/src/utils/module-prefix.ts | 27 - packages/core-cairo/src/utils/uint256.test.ts | 32 - packages/core-cairo/src/utils/uint256.ts | 36 - packages/core-cairo/src/utils/version.ts | 2 +- packages/core/package.json | 2 +- packages/ui/package.json | 1 + packages/ui/src/cairo/App.svelte | 11 +- packages/ui/src/cairo/CustomControls.svelte | 16 +- packages/ui/src/cairo/ERC1155Controls.svelte | 72 - packages/ui/src/cairo/ERC20Controls.svelte | 21 +- packages/ui/src/cairo/ERC721Controls.svelte | 7 +- .../ui/src/cairo/UpgradeabilityField.svelte | 15 + .../ui/src/cairo/UpgradeabilitySection.svelte | 34 - packages/ui/src/cairo/highlightjs.ts | 7 +- packages/ui/src/cairo/inject-hyperlinks.ts | 23 +- yarn.lock | 10 +- 62 files changed, 2364 insertions(+), 5752 deletions(-) create mode 100644 packages/core-cairo/src/common-components.ts delete mode 100644 packages/core-cairo/src/common-functions.ts delete mode 100644 packages/core-cairo/src/erc1155.test.ts delete mode 100644 packages/core-cairo/src/erc1155.test.ts.md delete mode 100644 packages/core-cairo/src/erc1155.test.ts.snap delete mode 100644 packages/core-cairo/src/erc1155.ts create mode 100644 packages/core-cairo/src/external-trait.ts delete mode 100644 packages/core-cairo/src/options.ts create mode 100644 packages/core-cairo/src/utils/define-components.ts delete mode 100644 packages/core-cairo/src/utils/define-modules.ts delete mode 100644 packages/core-cairo/src/utils/hash-builtin.ts delete mode 100644 packages/core-cairo/src/utils/imports-map.ts delete mode 100644 packages/core-cairo/src/utils/map-values.ts delete mode 100644 packages/core-cairo/src/utils/module-prefix.ts delete mode 100644 packages/core-cairo/src/utils/uint256.test.ts delete mode 100644 packages/core-cairo/src/utils/uint256.ts delete mode 100644 packages/ui/src/cairo/ERC1155Controls.svelte create mode 100644 packages/ui/src/cairo/UpgradeabilityField.svelte delete mode 100644 packages/ui/src/cairo/UpgradeabilitySection.svelte diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 267b551d..6845f84d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,6 +21,7 @@ jobs: node-version: 18.x cache: 'yarn' - name: Install Foundry + if: matrix.package == 'core' uses: foundry-rs/foundry-toolchain@v1 - name: Install dependencies run: yarn install diff --git a/packages/core-cairo/CHANGELOG.md b/packages/core-cairo/CHANGELOG.md index 70899a71..52057a38 100644 --- a/packages/core-cairo/CHANGELOG.md +++ b/packages/core-cairo/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Unreleased + +- **Breaking changes**: + - Use Cairo 1+ and OpenZeppelin Contracts for Cairo v0.8.0. + - Remove functions for `getInitialSupply` and `toUint256`. + - Remove ERC1155. + - Role-Based Access Control adds separate constructor arguments to assign different users for different roles. + ## 0.6.0 (2023-01-11) - Add ERC1155. ([#167](https://github.com/OpenZeppelin/contracts-wizard/pull/167)) diff --git a/packages/core-cairo/package.json b/packages/core-cairo/package.json index db5d6b4c..fe228a67 100644 --- a/packages/core-cairo/package.json +++ b/packages/core-cairo/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/wizard-cairo", - "version": "0.6.0", + "version": "0.7.0", "description": "A boilerplate generator to get started with OpenZeppelin Contracts for Cairo", "license": "MIT", "repository": "github:OpenZeppelin/contracts-wizard", @@ -20,7 +20,7 @@ }, "devDependencies": { "@types/bn.js": "^5.1.0", - "@types/node": "^10.17.51", + "@types/node": "^18.0.0", "array.prototype.flat": "^1.2.4", "ava": "^5.0.0", "rimraf": "^5.0.0", diff --git a/packages/core-cairo/src/add-pausable.ts b/packages/core-cairo/src/add-pausable.ts index edd99722..158dbf10 100644 --- a/packages/core-cairo/src/add-pausable.ts +++ b/packages/core-cairo/src/add-pausable.ts @@ -1,66 +1,62 @@ -import { withImplicitArgs } from './common-options'; -import type { ContractBuilder, BaseFunction } from './contract'; +import { getSelfArg } from './common-options'; +import type { ContractBuilder, ContractFunction } from './contract'; import { Access, requireAccessControl } from './set-access-control'; import { defineFunctions } from './utils/define-functions'; -import { defineModules } from './utils/define-modules'; +import { defineComponents } from './utils/define-components'; +import { externalTrait } from './external-trait'; -export function addPausable(c: ContractBuilder, access: Access, pausableFns: BaseFunction[]) { - c.addModule(modules.Pausable, [], [functions.pause, functions.unpause], false); +export function addPausable(c: ContractBuilder, access: Access) { + c.addComponent(components.PausableComponent, [], false); - for (const fn of pausableFns) { - setPausable(c, fn); - } - - c.addFunction(functions.paused); - - requireAccessControl(c, functions.pause, access, 'PAUSER'); - requireAccessControl(c, functions.unpause, access, 'PAUSER'); + c.addFunction(externalTrait, functions.pause); + c.addFunction(externalTrait, functions.unpause); + requireAccessControl(c, externalTrait, functions.pause, access, 'PAUSER', 'pauser'); + requireAccessControl(c, externalTrait, functions.unpause, access, 'PAUSER', 'pauser'); } -const modules = defineModules( { - Pausable: { - path: 'openzeppelin.security.pausable.library', - useNamespace: true +const components = defineComponents( { + PausableComponent: { + path: 'openzeppelin::security::pausable', + substorage: { + name: 'pausable', + type: 'PausableComponent::Storage', + }, + event: { + name: 'PausableEvent', + type: 'PausableComponent::Event', + }, + impls: [ + { + name: 'PausableImpl', + value: 'PausableComponent::PausableImpl', + }, + ], + internalImpl: { + name: 'PausableInternalImpl', + value: 'PausableComponent::InternalImpl', + }, }, }); const functions = defineFunctions({ - - paused: { - module: modules.Pausable, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [], - returns: [{ name: 'paused', type: 'felt' }], - passthrough: true, - parentFunctionName: 'is_paused', - }, - pause: { - module: modules.Pausable, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [], - parentFunctionName: '_pause', + args: [ + getSelfArg(), + ], + code: [ + 'self.pausable._pause()' + ] }, - unpause: { - module: modules.Pausable, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [], - parentFunctionName: '_unpause', - }, - - // --- library-only calls --- - - assert_not_paused: { - module: modules.Pausable, - args: [], + args: [ + getSelfArg(), + ], + code: [ + 'self.pausable._unpause()' + ] }, - }); -export function setPausable(c: ContractBuilder, fn: BaseFunction) { - c.addLibraryCall(functions.assert_not_paused, fn); +export function setPausable(c: ContractBuilder, fn: ContractFunction) { + c.addFunctionCodeBefore(externalTrait, fn, 'self.pausable.assert_not_paused()'); } diff --git a/packages/core-cairo/src/api.ts b/packages/core-cairo/src/api.ts index 5a1bbc54..26fdcb7d 100644 --- a/packages/core-cairo/src/api.ts +++ b/packages/core-cairo/src/api.ts @@ -1,9 +1,7 @@ import type { CommonOptions } from './common-options'; -import { printERC20, defaults as erc20defaults, isAccessControlRequired as erc20IsAccessControlRequired, ERC20Options, getInitialSupply } from './erc20'; +import { printERC20, defaults as erc20defaults, isAccessControlRequired as erc20IsAccessControlRequired, ERC20Options } from './erc20'; import { printERC721, defaults as erc721defaults, isAccessControlRequired as erc721IsAccessControlRequired, ERC721Options } from './erc721'; -import { printERC1155, defaults as erc1155defaults, isAccessControlRequired as erc1155IsAccessControlRequired, ERC1155Options } from './erc1155'; import { printCustom, defaults as customDefaults, isAccessControlRequired as customIsAccessControlRequired, CustomOptions } from './custom'; -import { toUint256 } from './utils/uint256'; export interface WizardContractAPI { /** @@ -23,37 +21,22 @@ export interface WizardContractAPI { isAccessControlRequired: (opts: Partial) => boolean, } -export type ERC20 = WizardContractAPI & { - /** - * Calculates the initial supply that would be used in an ERC20 contract based on a given premint amount and number of decimals. - */ - getInitialSupply: (premint: string, decimals: number) => string; -} +export type ERC20 = WizardContractAPI; export type ERC721 = WizardContractAPI; -export type ERC1155 = WizardContractAPI; export type Custom = WizardContractAPI; export const erc20: ERC20 = { print: printERC20, defaults: erc20defaults, isAccessControlRequired: erc20IsAccessControlRequired, - getInitialSupply } export const erc721: ERC721 = { print: printERC721, defaults: erc721defaults, isAccessControlRequired: erc721IsAccessControlRequired } -export const erc1155: ERC1155 = { - print: printERC1155, - defaults: erc1155defaults, - isAccessControlRequired: erc1155IsAccessControlRequired -} export const custom: Custom = { print: printCustom, defaults: customDefaults, isAccessControlRequired: customIsAccessControlRequired } -export const utils = { - toUint256 -} \ No newline at end of file diff --git a/packages/core-cairo/src/build-generic.ts b/packages/core-cairo/src/build-generic.ts index b15eadbe..3a28e208 100644 --- a/packages/core-cairo/src/build-generic.ts +++ b/packages/core-cairo/src/build-generic.ts @@ -1,12 +1,10 @@ import { ERC20Options, buildERC20 } from './erc20'; import { ERC721Options, buildERC721 } from './erc721'; -import { ERC1155Options, buildERC1155 } from './erc1155'; import { CustomOptions, buildCustom } from './custom'; export interface KindedOptions { ERC20: { kind: 'ERC20' } & ERC20Options; ERC721: { kind: 'ERC721' } & ERC721Options; - ERC1155: { kind: 'ERC1155' } & ERC1155Options; Custom: { kind: 'Custom' } & CustomOptions; } @@ -20,9 +18,6 @@ export function buildGeneric(opts: GenericOptions) { case 'ERC721': return buildERC721(opts); - case 'ERC1155': - return buildERC1155(opts); - case 'Custom': return buildCustom(opts); diff --git a/packages/core-cairo/src/common-components.ts b/packages/core-cairo/src/common-components.ts new file mode 100644 index 00000000..dff26e48 --- /dev/null +++ b/packages/core-cairo/src/common-components.ts @@ -0,0 +1,26 @@ +import type { ContractBuilder } from "./contract"; +import { defineComponents } from "./utils/define-components"; + +const components = defineComponents( { + SRC5Component: { + path: 'openzeppelin::introspection::src5', + substorage: { + name: 'src5', + type: 'SRC5Component::Storage', + }, + event: { + name: 'SRC5Event', + type: 'SRC5Component::Event', + }, + impls: [ + { + name: 'SRC5Impl', + value: 'SRC5Component::SRC5Impl', + }, + ], + }, +}) + +export function addSRC5Component(c: ContractBuilder) { + c.addComponent(components.SRC5Component, [], false); +} \ No newline at end of file diff --git a/packages/core-cairo/src/common-functions.ts b/packages/core-cairo/src/common-functions.ts deleted file mode 100644 index 61f4882d..00000000 --- a/packages/core-cairo/src/common-functions.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { withImplicitArgs } from './common-options'; -import type { ContractBuilder } from './contract'; -import { defineFunctions } from './utils/define-functions'; -import { defineModules } from './utils/define-modules'; - -export function addSupportsInterface(c: ContractBuilder) { - c.addModule( - modules.ERC165, [], [], false - ); - c.addFunction(functions.supportsInterface); -} - -export function importGetCallerAddress(c: ContractBuilder) { - c.addModule( - modules.syscalls, [], [], false - ); - c.addModuleFunction(modules.syscalls, 'get_caller_address'); -} - -const modules = defineModules({ - ERC165: { - path: 'openzeppelin.introspection.erc165.library', - useNamespace: true - }, - - syscalls: { - path: 'starkware.starknet.common.syscalls', - useNamespace: false - }, -}) - -const functions = defineFunctions({ - // --- view functions --- - supportsInterface: { - module: modules.ERC165, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'interfaceId', type: 'felt' }, - ], - returns: [{ name: 'success', type: 'felt' }], - passthrough: true, - parentFunctionName: 'supports_interface', - }, -}); \ No newline at end of file diff --git a/packages/core-cairo/src/common-options.ts b/packages/core-cairo/src/common-options.ts index 05ff871a..7666c250 100644 --- a/packages/core-cairo/src/common-options.ts +++ b/packages/core-cairo/src/common-options.ts @@ -24,10 +24,6 @@ export function withCommonDefaults(opts: CommonOptions): Required }; } -export function withImplicitArgs(): Argument[] { - return [ - { name: 'syscall_ptr', type: 'felt*' }, - { name: 'pedersen_ptr', type: 'HashBuiltin*' }, - { name: 'range_check_ptr' } - ]; +export function getSelfArg(): Argument { + return { name: 'ref self', type: 'ContractState' }; } \ No newline at end of file diff --git a/packages/core-cairo/src/contract.test.ts b/packages/core-cairo/src/contract.test.ts index 80cbba5b..ef3c0757 100644 --- a/packages/core-cairo/src/contract.test.ts +++ b/packages/core-cairo/src/contract.test.ts @@ -1,75 +1,110 @@ import test from 'ava'; -import { BaseFunction, ContractBuilder } from './contract'; +import { ContractBuilder, BaseFunction, BaseImplementedTrait, Component } from './contract'; import { printContract } from './print'; +const FOO_COMPONENT: Component = { + name: 'FooComponent', + path: 'some::path', + substorage: { + name: 'foo', + type: 'FooComponent::Storage', + }, + event: { + name: 'FooEvent', + type: 'FooComponent::Event', + }, + impls: [ + { + name: 'FooImpl', + value: 'FooComponent::FooImpl', + }, + ], + internalImpl: { + name: 'FooInternalImpl', + value: 'FooComponent::InternalImpl', + }, +}; + test('contract basics', t => { - const Foo = new ContractBuilder(); + const Foo = new ContractBuilder('Foo'); t.snapshot(printContract(Foo)); }); test('contract with constructor code', t => { - const Foo = new ContractBuilder(); + const Foo = new ContractBuilder('Foo'); Foo.addConstructorCode('someFunction()'); t.snapshot(printContract(Foo)); }); test('contract with constructor code with semicolon', t => { - const Foo = new ContractBuilder(); + const Foo = new ContractBuilder('Foo'); Foo.addConstructorCode('someFunction();'); t.snapshot(printContract(Foo)); }); -test('contract with function code', t => { - const Foo = new ContractBuilder(); - Foo.addFunctionCode('someFunction()', _otherFunction); +test('contract with function code before', t => { + const Foo = new ContractBuilder('Foo'); + const trait: BaseImplementedTrait = { + name: 'External', + of: 'ExternalTrait', + tags: [ + '#[generate_trait]', + '#[external(v0)]' + ], + }; + Foo.addImplementedTrait(trait); + const fn: BaseFunction = { + name: 'someFunction', + args: [], + code: [ + 'someFunction()' + ] + }; + Foo.addFunction(trait, fn); + Foo.addFunctionCodeBefore(trait, fn, 'before()'); t.snapshot(printContract(Foo)); }); -test('contract with function code with semicolon', t => { - const Foo = new ContractBuilder(); - Foo.addFunctionCode('someFunction();', _otherFunction); +test('contract with function code before with semicolons', t => { + const Foo = new ContractBuilder('Foo'); + const trait: BaseImplementedTrait = { + name: 'External', + of: 'ExternalTrait', + tags: [ + '#[generate_trait]', + '#[external(v0)]' + ], + }; + Foo.addImplementedTrait(trait); + const fn: BaseFunction = { + name: 'someFunction', + args: [], + code: [ + 'someFunction();' + ] + }; + Foo.addFunction(trait, fn); + Foo.addFunctionCodeBefore(trait, fn, 'before();'); t.snapshot(printContract(Foo)); }); test('contract with initializer params', t => { - const Foo = new ContractBuilder(); - Foo.addModule( - someModule, + const Foo = new ContractBuilder('Foo'); + + Foo.addComponent( + FOO_COMPONENT, ['param1'], - [], true ); t.snapshot(printContract(Foo)); }); -test('contract with library call', t => { - const Foo = new ContractBuilder(); - Foo.addModule( - someModule, - [], - [], - false +test('contract with standalone import', t => { + const Foo = new ContractBuilder('Foo'); + Foo.addComponent( + FOO_COMPONENT, ); - Foo.addFunction(_libraryFunction); + Foo.addStandaloneImport('some::library::SomeLibrary'); t.snapshot(printContract(Foo)); }); - -const someModule = { - name: 'SomeLibrary', - path: 'contracts/some/library', - useNamespace: true -}; - -const _otherFunction: BaseFunction = { - name: 'otherFunction', - kind: 'external', - args: [], -}; - -const _libraryFunction: BaseFunction = { - module: someModule, - name: 'libraryFunction', - kind: 'external', - args: [], -}; \ No newline at end of file diff --git a/packages/core-cairo/src/contract.test.ts.md b/packages/core-cairo/src/contract.test.ts.md index 1510ca5a..d33d3b48 100644 --- a/packages/core-cairo/src/contract.test.ts.md +++ b/packages/core-cairo/src/contract.test.ts.md @@ -10,7 +10,12 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ + #[starknet::contract]␊ + mod Foo {␊ + #[storage]␊ + struct Storage {␊ + }␊ + }␊ ` ## contract with constructor code @@ -19,14 +24,16 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + #[starknet::contract]␊ + mod Foo {␊ + #[storage]␊ + struct Storage {␊ + }␊ ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - someFunction();␊ - return ();␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + someFunction();␊ + }␊ }␊ ` @@ -36,56 +43,62 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ + #[starknet::contract]␊ + mod Foo {␊ + #[storage]␊ + struct Storage {␊ + }␊ ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - someFunction();␊ - return ();␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + someFunction();␊ + }␊ }␊ ` -## contract with function code +## contract with function code before > Snapshot 1 `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func otherFunction() {␊ - someFunction();␊ - return ();␊ + #[starknet::contract]␊ + mod Foo {␊ + #[storage]␊ + struct Storage {␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn someFunction() {␊ + before();␊ + someFunction();␊ + }␊ + }␊ }␊ ` -## contract with function code with semicolon +## contract with function code before with semicolons > Snapshot 1 `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func otherFunction() {␊ - someFunction();␊ - return ();␊ + #[starknet::contract]␊ + mod Foo {␊ + #[storage]␊ + struct Storage {␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn someFunction() {␊ + before();␊ + someFunction();␊ + }␊ + }␊ }␊ ` @@ -95,38 +108,66 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ + #[starknet::contract]␊ + mod Foo {␊ + use some::path::FooComponent;␊ + ␊ + component!(path: FooComponent, storage: foo, event: FooEvent);␊ ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + #[abi(embed_v0)]␊ + impl FooImpl = FooComponent::FooImpl;␊ ␊ - from contracts.some.library import SomeLibrary␊ + impl FooInternalImpl = FooComponent::InternalImpl;␊ ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - SomeLibrary.initializer('param1');␊ - return ();␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + foo: FooComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + FooEvent: FooComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.foo.initializer('param1');␊ + }␊ }␊ ` -## contract with library call +## contract with standalone import > Snapshot 1 `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ + #[starknet::contract]␊ + mod Foo {␊ + use some::path::FooComponent;␊ + use some::library::SomeLibrary;␊ + ␊ + component!(path: FooComponent, storage: foo, event: FooEvent);␊ ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ + #[abi(embed_v0)]␊ + impl FooImpl = FooComponent::FooImpl;␊ ␊ - from contracts.some.library import SomeLibrary␊ + impl FooInternalImpl = FooComponent::InternalImpl;␊ ␊ - //␊ - // Externals␊ - //␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + foo: FooComponent::Storage,␊ + }␊ ␊ - @external␊ - func libraryFunction() {␊ - SomeLibrary.libraryFunction();␊ - return ();␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + FooEvent: FooComponent::Event,␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/contract.test.ts.snap b/packages/core-cairo/src/contract.test.ts.snap index 63cc588c5aa62c8a3f125842dc4622b722062223..1a82b9125c57cfd1373c44b66e0bea07ee82d7f5 100644 GIT binary patch literal 663 zcmV;I0%-j~RzVEbpT2u(e}d`bNL_47BM_u|VWOffo@U%r82 zDg}&?D?uYgLMmA#ndCH=6IAl^WgJsQk1p=C?zM{1zT3Lr&bGG5=|e zaK#b^A|MCDL(hBqUMeb1IjA70l8?O%W3q=xExG9WMWn`_vW58 zdH!(W@{Fko(KE9Jg?^7=)%4H0>CTVV8eLmy&7+YgyzbiSzCoGTEVrvB`C*Th(sr)1ZL2_}p8!(v|zlt$~as;w2nu&5AThu8RA2L1B) zpqDyw^|HAI{}gQ`R{WIkje#K&$mv~pNHUpr|_BSrj` zbBVmM=@vV=DPLoT`eJjMKj|^6n}$|;)l6ldAO=gv+U-5JLrX4IW5yuZ4E!B|dBLx$ zks)S8z^5501CEa*rRwVRit@6BGPq>mCa!J0ys5uv>J?d;m&-;CK^6|}}cZ>!cL+>aBCzv77 zOZDOCQyf3D+I?0mn#K+!p6Q%Fy%jn`$yKmeXkx@ucu!$L_cYpQ3P1SSxvz4ZkuPfV zOcNwVBl*PmqVTRZhNB5uLB|S<(vzq|&H3xv7sm&U9OG=_Of%_AzF?!R9hMU0GqAF| zr%FhH7+mdaTo(2y = new Set(); - private librariesMap: Map = new Map(); - private functionMap: Map = new Map(); - readonly constructorImplicitArgs: Argument[] = withImplicitArgs(); + private componentsMap: Map = new Map(); + private implementedTraitsMap: Map = new Map(); + private superVariablesMap: Map = new Map(); + private standaloneImportsSet: Set = new Set(); - get libraries(): Library[] { - return [...this.librariesMap.values()]; + constructor(name: string) { + this.name = toIdentifier(name, true); } - get functions(): ContractFunction[] { - return [...this.functionMap.values()]; + get components(): Component[] { + return [...this.componentsMap.values()]; } - get variables(): string[] { - return [...this.variableSet]; + get implementedTraits(): ImplementedTrait[] { + return [...this.implementedTraitsMap.values()]; } - addModule(module: Module, params: Value[] = [], functions: BaseFunction[] = [], initializable: boolean = true): boolean { - const key = module; - const present = this.librariesMap.has(key); - const initializer = initializable ? { params } : undefined; + get superVariables(): Variable[] { + return [...this.superVariablesMap.values()]; + } - if (initializer !== undefined && initializer.params.length > 0) { - // presence of initializer params implies initializer code will be written, so implicit args must be included - importHashBuiltin(this); - } + get standaloneImports(): string[] { + return [...this.standaloneImportsSet]; + } - const functionStrings: string[] = []; - functions.forEach(fn => { - functionStrings.push(getImportName(fn)); - }); - if (initializable) { - functionStrings.push(getImportName({ - module: module, - name: 'initializer', - args: [] - })) - } + addStandaloneImport(fullyQualified: string) { + this.standaloneImportsSet.add(fullyQualified); + } - this.librariesMap.set(module, { module, functions: functionStrings, initializer }); + addComponent(component: Component, params: Value[] = [], initializable: boolean = true): boolean { + const key = component.name; + const present = this.componentsMap.has(key); + if (!present) { + const initializer = initializable ? { params } : undefined; + const cp: Component = { initializer, ...component, impls: [ ...component.impls ] }; // spread impls to deep copy from original component + this.componentsMap.set(key, cp); + } return !present; } - addModuleFunction(module: Module, addFunction: string) { - const existing = this.librariesMap.get(module); - if (existing === undefined) { - throw new Error(`Module ${module} has not been added yet`); + addImplToComponent(component: Component, impl: Impl) { + this.addComponent(component); + let c = this.componentsMap.get(component.name); + if (c == undefined) { + throw new Error(`Component ${component.name} has not been added yet`); } - if (!existing.functions.includes(addFunction)) { - existing.functions.push(addFunction); + + if (!c.impls.some(i => i.name === impl.name)) { + c.impls.push(impl); } } - addLibraryCall(callFn: BaseFunction, baseFn: BaseFunction, args: string[] = []) { - const fn = this.addFunction(baseFn); - if (callFn.module !== undefined) { - this.addModuleFunction(callFn.module, getImportName(callFn)); + addSuperVariable(variable: Variable) { + if (this.superVariablesMap.has(variable.name)) { + return false; + } else { + this.superVariablesMap.set(variable.name, variable); + return true; } - const libraryCall: LibraryCall = { callFn, args }; - fn.libraryCalls.push(libraryCall); } - addFunction(baseFn: BaseFunction): ContractFunction { - importHashBuiltin(this); - - const signature = [baseFn.name, '(', ...baseFn.args.map(a => a.name), ')'].join(''); - const got = this.functionMap.get(signature); - if (got !== undefined) { - return got; + addImplementedTrait(baseTrait: BaseImplementedTrait) { + const key = baseTrait.name; + const existingTrait = this.implementedTraitsMap.get(key); + if (existingTrait !== undefined) { + return existingTrait; } else { - const fn: ContractFunction = { - libraryCalls: [], - code: [], - final: false, - ...baseFn, + const t: ImplementedTrait = { + name: baseTrait.name, + of: baseTrait.of, + tags: [ ...baseTrait.tags ], + functions: [], }; - this.functionMap.set(signature, fn); - return fn; + this.implementedTraitsMap.set(key, t); + return t; } } - addConstructorArgument(arg: Argument) { - for (const existingArg of this.constructorArgs) { - if (existingArg.name == arg.name) { - return; + addFunction(baseTrait: BaseImplementedTrait, fn: BaseFunction) { + const t = this.addImplementedTrait(baseTrait); + + const signature = this.getFunctionSignature(fn); + + // Look for the existing function with the same signature and return it if found + for (let i = 0; i < t.functions.length; i++) { + const existingFn = t.functions[i]; + if (existingFn !== undefined && this.getFunctionSignature(existingFn) === signature) { + return existingFn; } } - this.constructorArgs.push(arg); + + // Otherwise, add the function + const contractFn: ContractFunction = { + ...fn, + codeBefore: [], + }; + t.functions.push(contractFn); + return contractFn; } - addConstructorCode(code: string) { - importHashBuiltin(this); - - this.constructorCode.push(code); + private getFunctionSignature(fn: BaseFunction) { + return [fn.name, '(', ...fn.args.map(a => a.name), ')'].join(''); } - addFunctionCode(code: string, baseFn: BaseFunction) { - const fn = this.addFunction(baseFn); - if (fn.final) { - throw new Error(`Function ${baseFn.name} is already finalized`); - } - fn.code.push(code); + addFunctionCodeBefore(baseTrait: BaseImplementedTrait, fn: BaseFunction, codeBefore: string) { + this.addImplementedTrait(baseTrait); + const existingFn = this.addFunction(baseTrait, fn); + existingFn.codeBefore = [ ...existingFn.codeBefore ?? [], codeBefore ]; } - setFunctionBody(code: string[], baseFn: BaseFunction) { - const fn = this.addFunction(baseFn); - if (fn.code.length > 0) { - throw new Error(`Function ${baseFn.name} has additional code`); + addConstructorArgument(arg: Argument) { + for (const existingArg of this.constructorArgs) { + if (existingArg.name == arg.name) { + return; + } } - fn.code.push(...code); - fn.final = true; + this.constructorArgs.push(arg); } - addVariable(code: string): boolean { - const present = this.variableSet.has(code); - this.variableSet.add(code); - return !present; + addConstructorCode(code: string) { + this.constructorCode.push(code); } } diff --git a/packages/core-cairo/src/custom.test.ts b/packages/core-cairo/src/custom.test.ts index bf729fd5..1b3addab 100644 --- a/packages/core-cairo/src/custom.test.ts +++ b/packages/core-cairo/src/custom.test.ts @@ -7,6 +7,7 @@ import { printContract } from './print'; function testCustom(title: string, opts: Partial) { test(title, t => { const c = buildCustom({ + name: 'MyContract', ...opts, }); t.snapshot(printContract(c)); @@ -19,6 +20,7 @@ function testCustom(title: string, opts: Partial) { function testAPIEquivalence(title: string, opts?: CustomOptions) { test(title, t => { t.is(custom.print(opts), printContract(buildCustom({ + name: 'MyContract', ...opts, }))); }); @@ -55,6 +57,7 @@ testCustom('pausable with access control disabled', { testAPIEquivalence('custom API default'); testAPIEquivalence('custom API full upgradeable', { + name: 'CustomContract', access: 'roles', pausable: true, upgradeable: true, @@ -66,5 +69,5 @@ test('custom API assert defaults', async t => { test('API isAccessControlRequired', async t => { t.is(custom.isAccessControlRequired({ pausable: true }), true); - t.is(custom.isAccessControlRequired({ upgradeable: true }), false); + t.is(custom.isAccessControlRequired({ upgradeable: true }), true); }); \ No newline at end of file diff --git a/packages/core-cairo/src/custom.test.ts.md b/packages/core-cairo/src/custom.test.ts.md index 14169887..8f466a5e 100644 --- a/packages/core-cairo/src/custom.test.ts.md +++ b/packages/core-cairo/src/custom.test.ts.md @@ -10,7 +10,12 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ + #[starknet::contract]␊ + mod MyContract {␊ + #[storage]␊ + struct Storage {␊ + }␊ + }␊ ` ## pausable @@ -19,65 +24,60 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ + #[starknet::contract]␊ + mod MyContract {␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + }␊ }␊ ` @@ -87,31 +87,54 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - from openzeppelin.upgrades.library import Proxy␊ - ␊ - @external␊ - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - proxy_admin: felt␊ - ) {␊ - Proxy.initializer(proxy_admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - new_implementation: felt␊ - ) -> () {␊ - Proxy.assert_only_admin();␊ - Proxy._set_implementation_hash(new_implementation);␊ - return ();␊ + #[starknet::contract]␊ + mod MyContract {␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use starknet::ClassHash;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[external(v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable._upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -121,7 +144,12 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ + #[starknet::contract]␊ + mod MyContract {␊ + #[storage]␊ + struct Storage {␊ + }␊ + }␊ ` ## access control ownable @@ -130,45 +158,37 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ + #[starknet::contract]␊ + mod MyContract {␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.ownable.initializer(owner);␊ + }␊ }␊ ` @@ -178,67 +198,48 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt␊ - ) {␊ - AccessControl.initializer();␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ + #[starknet::contract]␊ + mod MyContract {␊ + use openzeppelin::access::accesscontrol::AccessControlComponent;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + accesscontrol: AccessControlComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + AccessControlEvent: AccessControlComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, defaultAdmin: ContractAddress) {␊ + self.accesscontrol.initializer();␊ + ␊ + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ + }␊ }␊ ` @@ -248,64 +249,59 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - ␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ + #[starknet::contract]␊ + mod MyContract {␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/custom.test.ts.snap b/packages/core-cairo/src/custom.test.ts.snap index 5acfe6d0dcce8aa3fe6e740da233e48c2e3b77bb..a79266f42a24b1590d29904e520a5b3d9273d4b7 100644 GIT binary patch literal 1133 zcmV-z1d{tfRzV0;XKoo8*RoFYWf$7+WY3)Qos)CEZ?^gB_kz$p zWS_nPCp-Y(O&AXcgi#!^e#qH}ubziF-ut*PcV|w%<`?Jg&hv*4(ax*&z2!~f0%fq= z^?-8X6NqiJ)!l8i?!RLk$A=WSZMz}mF?RWWYY=*9>$IcR=zR-`moyDyd;t6DlJPhZ zpY3GVl+AhTyrm%aBb+eY3!nn>?d_jB%3I%WPZDOr0EH3IGl(Jx2(@hnZW0rIYTG#^ z+kU0qb;3auQW0&nVKa7JV9d6|W18*U&fe5)974jW^_SX|>*C8Jy-&B~bWNrnx(Hi*b)wFzA8j96egfZZsK0K@q(x z7f-9mhZU6;Px1onaLnP^>Imlwit=5~p(y#Ed+y)?1lu$?9Tmbbti-A*2jvh`95k0j zx2OegRKRpsg?XX3v8PnoB|T+o6-AS;Vo2)JQI6VU_{k@xCJn>Oc@8{n%zd@+ASOp( zt;b>1)+Q@!*USiLGC=7CBQHO|e2Bsro7$ApPuh(R^f{@^McZCvA}A^=d>Chre2TPd zRt!F35coDS?qOTjOmbd{KbExomth>mJM|og?{mVSMJloi$r99KvN1j)Cye87{uHO#e6v_Tub3Ktn>a`ak5C7jmk>_ zN$B-K$zvH{vfqW`9VXF1j6G-&y>mnK=oO2e!XlLG%@EZj)vhTVkrd@)S8VQTp=)I_ z5Vzq4X8pg=(7Nn2)zfZCp?unwe^>rC;PvSw@t$QjXP#=cs`^Jrj9s(Qtn6!x2jxa!l)|2$%Fhq zEa;f`5%i200000000B+Sle#XFc{uJ6H@MY1K&)_(3Wxy(zL+_3~h88L)xw^H~G6- zb?wM@)^*b^xZ(wPfx(O7#Lkwap%e%!gH}EH_<#TD`yJnOJ4}Rq_2~;}su^^{L}@Xg zij!FNgjOGKqKIg6vbntQXd!(qt}HxWeA;TE_lG+t8~Zc_u3%#?0K`f+3Z;0x>uzha1h=E^190Q{~P!J}P>QRuR4jAo7B1if9L)TxkmV_ZF6^J3P zTiCYUp0^bWuCz=-Eu_~?c!&xeS8Aj}!WfRV(YXsuKUqgHL?9J#+gZ@Sj7ehZd&s;D25{@WHFTBrIRF9WR8zv}B}hM;xAr_6m!K2Lk#CyUp4V!bH+l_P8_{XY z+d8K(w189NK=k`q*U-i$^6hSRha9W}lUqBW3fpN8UI9#|LsM7^hO0oy&6mw68EN;z z*oYJ6%ml7!(P<+{bwRe%WvWNxhCIw+*q-3zTr3v3Tt8n?>+T9_30#<8Xb^Q3VJ@P8 za2jM;6f}>9CwWm3F766JRWkJy#CI = { + name: 'MyContract', pausable: false, access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, @@ -19,6 +20,7 @@ export function printCustom(opts: CustomOptions = defaults): string { } export interface CustomOptions extends CommonOptions { + name: string; pausable?: boolean; } @@ -31,21 +33,22 @@ function withDefaults(opts: CustomOptions): Required { } export function isAccessControlRequired(opts: Partial): boolean { - return opts.pausable === true; + return opts.pausable === true || opts.upgradeable === true; } export function buildCustom(opts: CustomOptions): Contract { - const allOpts = withDefaults(opts); + const c = new ContractBuilder(opts.name); - const c = new ContractBuilder(); + const allOpts = withDefaults(opts); if (allOpts.pausable) { - addPausable(c, allOpts.access, []); + addPausable(c, allOpts.access); } setAccessControl(c, allOpts.access); - setUpgradeable(c, allOpts.upgradeable); + setUpgradeable(c, allOpts.upgradeable, allOpts.access); setInfo(c, allOpts.info); return c; } + diff --git a/packages/core-cairo/src/erc1155.test.ts b/packages/core-cairo/src/erc1155.test.ts deleted file mode 100644 index 630c005f..00000000 --- a/packages/core-cairo/src/erc1155.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import test from 'ava'; -import { erc1155 } from '.'; - -import { buildERC1155, ERC1155Options } from './erc1155'; -import { printContract } from './print'; - -function testERC1155(title: string, opts: Partial) { - test(title, t => { - const c = buildERC1155({ - uri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/', - ...opts, - }); - t.snapshot(printContract(c)); - }); -} - -/** - * Tests external API for equivalence with internal API - */ - function testAPIEquivalence(title: string, opts?: ERC1155Options) { - test(title, t => { - t.is(erc1155.print(opts), printContract(buildERC1155({ - uri: '', - ...opts, - }))); - }); -} - -testERC1155('basic', {}); - -testERC1155('basic + roles', { - access: 'roles', -}); - -testERC1155('no updatable uri', { - updatableUri: false, -}); - -testERC1155('burnable', { - burnable: true, -}); - -testERC1155('pausable', { - pausable: true, -}); - -testERC1155('mintable', { - mintable: true, -}); - -testERC1155('mintable + roles', { - mintable: true, - access: 'roles', -}); - -testERC1155('full upgradeable', { - mintable: true, - access: 'roles', - burnable: true, - pausable: true, - upgradeable: true, -}); - -testAPIEquivalence('API default'); - -testAPIEquivalence('API basic', { uri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/' }); - -testAPIEquivalence('API full upgradeable', { - uri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/', - mintable: true, - access: 'roles', - burnable: true, - pausable: true, - upgradeable: true, -}); - -test('API assert defaults', async t => { - t.is(erc1155.print(erc1155.defaults), erc1155.print()); -}); - -test('API isAccessControlRequired', async t => { - t.is(erc1155.isAccessControlRequired({ updatableUri: false, mintable: true }), true); - t.is(erc1155.isAccessControlRequired({ updatableUri: false, pausable: true }), true); - t.is(erc1155.isAccessControlRequired({ updatableUri: false, upgradeable: true }), false); - t.is(erc1155.isAccessControlRequired({ updatableUri: true }), true); - t.is(erc1155.isAccessControlRequired({ updatableUri: false}), false); - t.is(erc1155.isAccessControlRequired({}), true); // updatableUri is true by default -}); \ No newline at end of file diff --git a/packages/core-cairo/src/erc1155.test.ts.md b/packages/core-cairo/src/erc1155.test.ts.md deleted file mode 100644 index a2f44b38..00000000 --- a/packages/core-cairo/src/erc1155.test.ts.md +++ /dev/null @@ -1,1239 +0,0 @@ -# Snapshot report for `src/erc1155.test.ts` - -The actual snapshot is saved in `erc1155.test.ts.snap`. - -Generated by [AVA](https://avajs.dev). - -## 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - uri: felt␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC1155._set_uri(uri);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ` - -## basic + roles - -> 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - ␊ - const URI_SETTER_ROLE = 0x7804d923f43a17d325d77e781528e0793b2edd9890ab45fc64efd7b4b427744; // keccak256('URI_SETTER_ROLE')[0:251 bits]␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt␊ - ) {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - AccessControl.initializer();␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - AccessControl._grant_role(URI_SETTER_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - uri: felt␊ - ) {␊ - AccessControl.assert_only_role(URI_SETTER_ROLE);␊ - ERC1155._set_uri(uri);␊ - return ();␊ - }␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ - }␊ - ` - -## no updatable uri - -> 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ` - -## burnable - -> 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, id: Uint256, value: Uint256␊ - ) {␊ - ERC1155.assert_owner_or_approved(owner=from_);␊ - ERC1155._burn(from_, id, value);␊ - return ();␊ - }␊ - ␊ - @external␊ - func burnBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, ids_len: felt, ids: Uint256*, values_len: felt, values: Uint256*␊ - ) {␊ - ERC1155.assert_owner_or_approved(owner=from_);␊ - ERC1155._burn_batch(from_, ids_len, ids, values_len, values);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - uri: felt␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC1155._set_uri(uri);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ` - -## pausable - -> 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - uri: felt␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC1155._set_uri(uri);␊ - return ();␊ - }␊ - ` - -## mintable - -> 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC1155._mint(to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func mintBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC1155._mint_batch(to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - uri: felt␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC1155._set_uri(uri);␊ - return ();␊ - }␊ - ` - -## mintable + roles - -> 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - ␊ - const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5; // keccak256('MINTER_ROLE')[0:251 bits]␊ - const URI_SETTER_ROLE = 0x7804d923f43a17d325d77e781528e0793b2edd9890ab45fc64efd7b4b427744; // keccak256('URI_SETTER_ROLE')[0:251 bits]␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt␊ - ) {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - AccessControl.initializer();␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - AccessControl._grant_role(MINTER_ROLE, admin);␊ - AccessControl._grant_role(URI_SETTER_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - AccessControl.assert_only_role(MINTER_ROLE);␊ - ERC1155._mint(to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func mintBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - AccessControl.assert_only_role(MINTER_ROLE);␊ - ERC1155._mint_batch(to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - uri: felt␊ - ) {␊ - AccessControl.assert_only_role(URI_SETTER_ROLE);␊ - ERC1155._set_uri(uri);␊ - return ();␊ - }␊ - ` - -## 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.erc1155.library import ERC1155␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - from openzeppelin.upgrades.library import Proxy␊ - ␊ - const PAUSER_ROLE = 0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862; // keccak256('PAUSER_ROLE')[0:251 bits]␊ - const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5; // keccak256('MINTER_ROLE')[0:251 bits]␊ - const URI_SETTER_ROLE = 0x7804d923f43a17d325d77e781528e0793b2edd9890ab45fc64efd7b4b427744; // keccak256('URI_SETTER_ROLE')[0:251 bits]␊ - ␊ - @external␊ - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt, proxy_admin: felt␊ - ) {␊ - ERC1155.initializer('https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/');␊ - AccessControl.initializer();␊ - Proxy.initializer(proxy_admin);␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - AccessControl._grant_role(PAUSER_ROLE, admin);␊ - AccessControl._grant_role(MINTER_ROLE, admin);␊ - AccessControl._grant_role(URI_SETTER_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func uri{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - id: Uint256␊ - ) -> (uri: felt) {␊ - return ERC1155.uri(id);␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, id: Uint256␊ - ) -> (balance: Uint256) {␊ - return ERC1155.balance_of(account, id);␊ - }␊ - ␊ - @view␊ - func balanceOfBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - accounts_len: felt, accounts: felt*, ids_len: felt, ids: Uint256*␊ - ) -> (balances_len: felt, balances: Uint256*) {␊ - return ERC1155.balance_of_batch(accounts_len, accounts, ids_len, ids);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC1155.is_approved_for_all(account, operator);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.safe_transfer_from(from_, to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeBatchTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt,␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.safe_batch_transfer_from(from_, to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - AccessControl.assert_only_role(PAUSER_ROLE);␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - AccessControl.assert_only_role(PAUSER_ROLE);␊ - Pausable._unpause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, id: Uint256, value: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.assert_owner_or_approved(owner=from_);␊ - ERC1155._burn(from_, id, value);␊ - return ();␊ - }␊ - ␊ - @external␊ - func burnBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, ids_len: felt, ids: Uint256*, values_len: felt, values: Uint256*␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC1155.assert_owner_or_approved(owner=from_);␊ - ERC1155._burn_batch(from_, ids_len, ids, values_len, values);␊ - return ();␊ - }␊ - ␊ - @external␊ - func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, id: Uint256, value: Uint256, data_len: felt, data: felt*␊ - ) {␊ - Pausable.assert_not_paused();␊ - AccessControl.assert_only_role(MINTER_ROLE);␊ - ERC1155._mint(to, id, value, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func mintBatch{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt,␊ - ids_len: felt,␊ - ids: Uint256*,␊ - values_len: felt,␊ - values: Uint256*,␊ - data_len: felt,␊ - data: felt*,␊ - ) {␊ - Pausable.assert_not_paused();␊ - AccessControl.assert_only_role(MINTER_ROLE);␊ - ERC1155._mint_batch(to, ids_len, ids, values_len, values, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - uri: felt␊ - ) {␊ - AccessControl.assert_only_role(URI_SETTER_ROLE);␊ - ERC1155._set_uri(uri);␊ - return ();␊ - }␊ - ␊ - @external␊ - func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - new_implementation: felt␊ - ) -> () {␊ - Proxy.assert_only_admin();␊ - Proxy._set_implementation_hash(new_implementation);␊ - return ();␊ - }␊ - ` diff --git a/packages/core-cairo/src/erc1155.test.ts.snap b/packages/core-cairo/src/erc1155.test.ts.snap deleted file mode 100644 index 8568ac070ccf336d274b3447a2d2ca72db007e8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2183 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 = { - uri: '', - burnable: false, - pausable: false, - mintable: false, - updatableUri: true, - access: commonDefaults.access, - upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info -} as const; - -export function printERC1155(opts: ERC1155Options = defaults): string { - return printContract(buildERC1155(opts)); -} - -export interface ERC1155Options extends CommonOptions { - uri: string; - burnable?: boolean; - pausable?: boolean; - mintable?: boolean; - updatableUri?: boolean; -} - -function withDefaults(opts: ERC1155Options): Required { - return { - ...opts, - ...withCommonDefaults(opts), - burnable: opts.burnable ?? defaults.burnable, - pausable: opts.pausable ?? defaults.pausable, - mintable: opts.mintable ?? defaults.mintable, - updatableUri: opts.updatableUri ?? defaults.updatableUri, - }; -} - -export function isAccessControlRequired(opts: Partial): boolean { - return opts.mintable || opts.pausable || opts.updatableUri !== false; -} - -export function buildERC1155(opts: ERC1155Options): Contract { - const c = new ContractBuilder(); - - const allOpts = withDefaults(opts); - - addBase(c, allOpts.uri); - addSupportsInterface(c); - - c.addFunction(functions.uri); - c.addFunction(functions.balanceOf); - c.addFunction(functions.balanceOfBatch); - c.addFunction(functions.isApprovedForAll); - - c.addFunction(functions.setApprovalForAll); - c.addFunction(functions.safeTransferFrom); - c.addFunction(functions.safeBatchTransferFrom); - - importUint256(c); - - if (allOpts.pausable) { - addPausable(c, allOpts.access, [ - functions.setApprovalForAll, - functions.safeTransferFrom, - functions.safeBatchTransferFrom, - ]); - if (allOpts.burnable) { - setPausable(c, functions.burn); - setPausable(c, functions.burnBatch); - } - if (allOpts.mintable) { - setPausable(c, functions.mint); - setPausable(c, functions.mintBatch); - } - } - - if (allOpts.burnable) { - addBurnable(c); - } - - if (allOpts.mintable) { - addMintable(c, allOpts.access); - } - - if (allOpts.updatableUri) { - addSetUri(c, allOpts.access); - } - - setAccessControl(c, allOpts.access); - setUpgradeable(c, allOpts.upgradeable); - - setInfo(c, allOpts.info); - - return c; -} - -function addBase(c: ContractBuilder, uri: string) { - c.addModule( - modules.ERC1155, - [uri], - [ - functions.safeTransferFrom, - functions.safeBatchTransferFrom, - ], - true, - ); -} - -function addBurnable(c: ContractBuilder) { - c.addFunction(functions.burn); - c.addLibraryCall(functions.assert_owner_or_approved, functions.burn, [ 'owner=from_' ]); - - c.addFunction(functions.burnBatch); - c.addLibraryCall(functions.assert_owner_or_approved, functions.burnBatch, [ 'owner=from_' ]); -} - -function addMintable(c: ContractBuilder, access: Access) { - c.addFunction(functions.mint); - requireAccessControl(c, functions.mint, access, 'MINTER'); - - c.addFunction(functions.mintBatch); - requireAccessControl(c, functions.mintBatch, access, 'MINTER'); -} - -function addSetUri(c: ContractBuilder, access: Access) { - c.addFunction(functions.setURI); - requireAccessControl(c, functions.setURI, access, 'URI_SETTER'); -} - -const modules = defineModules( { - ERC1155: { - path: 'openzeppelin.token.erc1155.library', - useNamespace: true - }, - - math: { - path: 'starkware.cairo.common.math', - useNamespace: false - } -}); - -const functions = defineFunctions({ - - // --- view functions --- - - uri: { - module: modules.ERC1155, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'id', type: 'Uint256' }, - ], - returns: [{ name: 'uri', type: 'felt' }], - passthrough: true, - }, - - balanceOf: { - module: modules.ERC1155, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'account', type: 'felt' }, - { name: 'id', type: 'Uint256' }, - ], - returns: [{ name: 'balance', type: 'Uint256' }], - passthrough: true, - parentFunctionName: 'balance_of', - }, - - balanceOfBatch: { - module: modules.ERC1155, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'accounts_len', type: 'felt' }, - { name: 'accounts', type: 'felt*' }, - { name: 'ids_len', type: 'felt' }, - { name: 'ids', type: 'Uint256*' }, - ], - returns: [ - { name: 'balances_len', type: 'felt' }, - { name: 'balances', type: 'Uint256*' }], - passthrough: true, - parentFunctionName: 'balance_of_batch', - }, - - isApprovedForAll: { - module: modules.ERC1155, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'account', type: 'felt' }, - { name: 'operator', type: 'felt' }, - ], - returns: [{ name: 'approved', type: 'felt' }], - passthrough: true, - parentFunctionName: 'is_approved_for_all', - }, - - // --- external functions --- - - setURI: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'uri', type: 'felt' }, - ], - parentFunctionName: '_set_uri', - }, - - setApprovalForAll: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'operator', type: 'felt' }, - { name: 'approved', type: 'felt' }, - ], - parentFunctionName: 'set_approval_for_all', - }, - - safeTransferFrom: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'from_', type: 'felt' }, - { name: 'to', type: 'felt' }, - { name: 'id', type: 'Uint256' }, - { name: 'value', type: 'Uint256' }, - { name: 'data_len', type: 'felt' }, - { name: 'data', type: 'felt*' }, - ], - parentFunctionName: 'safe_transfer_from', - }, - - safeBatchTransferFrom: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'from_', type: 'felt' }, - { name: 'to', type: 'felt' }, - { name: 'ids_len', type: 'felt' }, - { name: 'ids', type: 'Uint256*' }, - { name: 'values_len', type: 'felt' }, - { name: 'values', type: 'Uint256*' }, - { name: 'data_len', type: 'felt' }, - { name: 'data', type: 'felt*' }, - ], - parentFunctionName: 'safe_batch_transfer_from', - }, - - mint: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'to', type: 'felt' }, - { name: 'id', type: 'Uint256' }, - { name: 'value', type: 'Uint256' }, - { name: 'data_len', type: 'felt' }, - { name: 'data', type: 'felt*' }, - ], - parentFunctionName: '_mint', - }, - - mintBatch: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'to', type: 'felt' }, - { name: 'ids_len', type: 'felt' }, - { name: 'ids', type: 'Uint256*' }, - { name: 'values_len', type: 'felt' }, - { name: 'values', type: 'Uint256*' }, - { name: 'data_len', type: 'felt' }, - { name: 'data', type: 'felt*' }, - ], - parentFunctionName: '_mint_batch', - }, - - burn: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'from_', type: 'felt' }, - { name: 'id', type: 'Uint256' }, - { name: 'value', type: 'Uint256' }, - ], - parentFunctionName: '_burn', - }, - - burnBatch: { - module: modules.ERC1155, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'from_', type: 'felt' }, - { name: 'ids_len', type: 'felt' }, - { name: 'ids', type: 'Uint256*' }, - { name: 'values_len', type: 'felt' }, - { name: 'values', type: 'Uint256*' }, - ], - parentFunctionName: '_burn_batch', - }, - - // --- library-only calls --- - - assert_owner_or_approved: { - module: modules.ERC1155, - args: [ - { name: 'owner', type: 'felt' }, - ], - }, - -}); \ No newline at end of file diff --git a/packages/core-cairo/src/erc20.test.ts b/packages/core-cairo/src/erc20.test.ts index 1b78da22..2b7efda0 100644 --- a/packages/core-cairo/src/erc20.test.ts +++ b/packages/core-cairo/src/erc20.test.ts @@ -4,7 +4,6 @@ import { buildERC20, ERC20Options } from './erc20'; import { printContract } from './print'; import { erc20 } from '.'; -import type { OptionsError } from './error'; function testERC20(title: string, opts: Partial) { test(title, t => { @@ -69,23 +68,27 @@ testERC20('erc20 mintable with roles', { access: 'roles', }); +testERC20('erc20 safe allowance', { + safeAllowance: true, +}); + testERC20('erc20 full upgradeable', { premint: '2000', - decimals: '9', access: 'ownable', burnable: true, mintable: true, pausable: true, + safeAllowance: true, upgradeable: true, }); testERC20('erc20 full upgradeable with roles', { premint: '2000', - decimals: '9', access: 'roles', burnable: true, mintable: true, pausable: true, + safeAllowance: true, upgradeable: true, }); @@ -97,11 +100,11 @@ testAPIEquivalence('erc20 API full upgradeable', { name: 'CustomToken', symbol: 'CTK', premint: '2000', - decimals: '9', access: 'roles', burnable: true, mintable: true, pausable: true, + safeAllowance: true, upgradeable: true, }); @@ -112,20 +115,5 @@ test('erc20 API assert defaults', async t => { test('erc20 API isAccessControlRequired', async t => { t.is(erc20.isAccessControlRequired({ mintable: true }), true); t.is(erc20.isAccessControlRequired({ pausable: true }), true); - t.is(erc20.isAccessControlRequired({ upgradeable: true }), false); + t.is(erc20.isAccessControlRequired({ upgradeable: true }), true); }); - -test('erc20 API getInitialSupply', async t => { - t.is(erc20.getInitialSupply('1000', 18), '1000000000000000000000'); - t.is(erc20.getInitialSupply('1000.1', 18), '1000100000000000000000'); - t.is(erc20.getInitialSupply('.1', 18), '100000000000000000'); - t.is(erc20.getInitialSupply('.01', 2), '1'); - - let error = t.throws(() => erc20.getInitialSupply('.01', 1)); - t.not(error, undefined); - t.is((error as OptionsError).messages.premint, 'Too many decimals'); - - error = t.throws(() => erc20.getInitialSupply('1.1.1', 18)); - t.not(error, undefined); - t.is((error as OptionsError).messages.premint, 'Not a valid number'); -}); \ 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 c476d220..917e990d 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -10,95 +10,38 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + }␊ }␊ ` @@ -108,105 +51,48 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - from starkware.starknet.common.syscalls import get_caller_address␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - amount: Uint256␊ - ) {␊ - let (owner) = get_caller_address();␊ - ERC20._burn(owner, amount);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use starknet::get_caller_address;␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn burn(ref self: ContractState, value: u256) {␊ + let caller = get_caller_address();␊ + self.erc20._burn(caller, value);␊ + }␊ + }␊ }␊ ` @@ -216,143 +102,74 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + }␊ }␊ ` @@ -362,168 +179,89 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - ␊ - const PAUSER_ROLE = 0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862; // keccak256('PAUSER_ROLE')[0:251 bits]␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - AccessControl.initializer();␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - AccessControl._grant_role(PAUSER_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - AccessControl.assert_only_role(PAUSER_ROLE);␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - AccessControl.assert_only_role(PAUSER_ROLE);␊ - Pausable._unpause();␊ - return ();␊ + const PAUSER_ROLE: felt252 = selector!("PAUSER_ROLE");␊ + ␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::accesscontrol::AccessControlComponent;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use starknet::ContractAddress;␊ + use super::{PAUSER_ROLE};␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + accesscontrol: AccessControlComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + AccessControlEvent: AccessControlComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, defaultAdmin: ContractAddress, pauser: ContractAddress) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + self.accesscontrol.initializer();␊ + ␊ + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ + self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn pause(ref self: ContractState) {␊ + self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ + self.pausable._unpause();␊ + }␊ + }␊ }␊ ` @@ -533,154 +271,81 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - from starkware.starknet.common.syscalls import get_caller_address␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - amount: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - let (owner) = get_caller_address();␊ - ERC20._burn(owner, amount);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::get_caller_address;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn burn(ref self: ContractState, value: u256) {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._burn(caller, value);␊ + }␊ + ␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + }␊ }␊ ` @@ -690,99 +355,41 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - ␊ - ERC20._mint(recipient, Uint256(1000000000000000000000, 0));␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use starknet::ContractAddress;␊ ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ ␊ - //␊ - // Externals␊ - //␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + }␊ ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer(recipient, amount);␊ - }␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + }␊ ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ + #[constructor]␊ + fn constructor(ref self: ContractState, recipient: ContractAddress) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ + self.erc20._mint(recipient, 1000);␊ + }␊ }␊ ` @@ -792,95 +399,38 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ - from openzeppelin.token.erc20.library import ERC20␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + }␊ ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + }␊ ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + }␊ }␊ ` @@ -890,127 +440,60 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, amount: Uint256␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC20._mint(to, amount);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + self.ownable.assert_only_owner();␊ + self.erc20._mint(recipient, amount);␊ + }␊ + }␊ }␊ ` @@ -1020,152 +503,120 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - ␊ - const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5; // keccak256('MINTER_ROLE')[0:251 bits]␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 18);␊ - AccessControl.initializer();␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - AccessControl._grant_role(MINTER_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ + const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊ + ␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::access::accesscontrol::AccessControlComponent;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use starknet::ContractAddress;␊ + use super::{MINTER_ROLE};␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + #[substorage(v0)]␊ + accesscontrol: AccessControlComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + #[flat]␊ + AccessControlEvent: AccessControlComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, defaultAdmin: ContractAddress, minter: ContractAddress) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + self.accesscontrol.initializer();␊ + ␊ + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ + self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + self.accesscontrol.assert_only_role(MINTER_ROLE);␊ + self.erc20._mint(recipient, amount);␊ + }␊ + }␊ }␊ + ` + +## erc20 safe allowance + +> Snapshot 1 + + `// SPDX-License-Identifier: MIT␊ ␊ - @external␊ - func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, amount: Uint256␊ - ) {␊ - AccessControl.assert_only_role(MINTER_ROLE);␊ - ERC20._mint(to, amount);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SafeAllowanceImpl = ERC20Component::SafeAllowanceImpl;␊ + #[abi(embed_v0)]␊ + impl SafeAllowanceCamelImpl = ERC20Component::SafeAllowanceCamelImpl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + }␊ }␊ ` @@ -1175,176 +626,109 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - from starkware.starknet.common.syscalls import get_caller_address␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - from openzeppelin.upgrades.library import Proxy␊ - ␊ - @external␊ - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, recipient: felt, proxy_admin: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 9);␊ - Ownable.initializer(owner);␊ - Proxy.initializer(proxy_admin);␊ - ␊ - ERC20._mint(recipient, Uint256(2000000000000, 0));␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - amount: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - let (owner) = get_caller_address();␊ - ERC20._burn(owner, amount);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, amount: Uint256␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC20._mint(to, amount);␊ - return ();␊ - }␊ - ␊ - @external␊ - func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - new_implementation: felt␊ - ) -> () {␊ - Proxy.assert_only_admin();␊ - Proxy._set_implementation_hash(new_implementation);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use starknet::ContractAddress;␊ + use starknet::get_caller_address;␊ + use starknet::ClassHash;␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SafeAllowanceImpl = ERC20Component::SafeAllowanceImpl;␊ + #[abi(embed_v0)]␊ + impl SafeAllowanceCamelImpl = ERC20Component::SafeAllowanceCamelImpl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, recipient: ContractAddress, owner: ContractAddress) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + self.ownable.initializer(owner);␊ + ␊ + self.erc20._mint(recipient, 2000);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn burn(ref self: ContractState, value: u256) {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._burn(caller, value);␊ + }␊ + ␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + ␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + self.ownable.assert_only_owner();␊ + self.erc20._mint(recipient, amount);␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable._upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` @@ -1354,201 +738,133 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - %lang starknet␊ - ␊ - from starkware.cairo.common.cairo_builtins import HashBuiltin␊ - from starkware.cairo.common.uint256 import Uint256␊ - from starkware.starknet.common.syscalls import get_caller_address␊ - ␊ - from openzeppelin.token.erc20.library import ERC20␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - from openzeppelin.upgrades.library import Proxy␊ - ␊ - const PAUSER_ROLE = 0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862; // keccak256('PAUSER_ROLE')[0:251 bits]␊ - const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5; // keccak256('MINTER_ROLE')[0:251 bits]␊ - ␊ - @external␊ - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt, recipient: felt, proxy_admin: felt␊ - ) {␊ - ERC20.initializer('MyToken', 'MTK', 9);␊ - AccessControl.initializer();␊ - Proxy.initializer(proxy_admin);␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - AccessControl._grant_role(PAUSER_ROLE, admin);␊ - ERC20._mint(recipient, Uint256(2000000000000, 0));␊ - AccessControl._grant_role(MINTER_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC20.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC20.symbol();␊ - }␊ - ␊ - @view␊ - func totalSupply{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (totalSupply: Uint256) {␊ - let (totalSupply) = ERC20.total_supply();␊ - return (totalSupply=totalSupply);␊ - }␊ - ␊ - @view␊ - func decimals{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (decimals: felt) {␊ - return ERC20.decimals();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - account: felt␊ - ) -> (balance: Uint256) {␊ - return ERC20.balance_of(account);␊ - }␊ - ␊ - @view␊ - func allowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, spender: felt␊ - ) -> (remaining: Uint256) {␊ - return ERC20.allowance(owner, spender);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func transfer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer(recipient, amount);␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - sender: felt, recipient: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.transfer_from(sender, recipient, amount);␊ - }␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, amount: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.approve(spender, amount);␊ - }␊ - ␊ - @external␊ - func increaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, added_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.increase_allowance(spender, added_value);␊ - }␊ - ␊ - @external␊ - func decreaseAllowance{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - spender: felt, subtracted_value: Uint256␊ - ) -> (success: felt) {␊ - Pausable.assert_not_paused();␊ - return ERC20.decrease_allowance(spender, subtracted_value);␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - amount: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - let (owner) = get_caller_address();␊ - ERC20._burn(owner, amount);␊ - return ();␊ - }␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - AccessControl.assert_only_role(PAUSER_ROLE);␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - AccessControl.assert_only_role(PAUSER_ROLE);␊ - Pausable._unpause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, amount: Uint256␊ - ) {␊ - AccessControl.assert_only_role(MINTER_ROLE);␊ - ERC20._mint(to, amount);␊ - return ();␊ - }␊ - ␊ - @external␊ - func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - new_implementation: felt␊ - ) -> () {␊ - Proxy.assert_only_admin();␊ - Proxy._set_implementation_hash(new_implementation);␊ - return ();␊ + const PAUSER_ROLE: felt252 = selector!("PAUSER_ROLE");␊ + const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊ + const UPGRADER_ROLE: felt252 = selector!("UPGRADER_ROLE");␊ + ␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::accesscontrol::AccessControlComponent;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use starknet::ContractAddress;␊ + use starknet::get_caller_address;␊ + use starknet::ClassHash;␊ + use super::{PAUSER_ROLE, MINTER_ROLE, UPGRADER_ROLE};␊ + ␊ + component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ + impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SafeAllowanceImpl = ERC20Component::SafeAllowanceImpl;␊ + #[abi(embed_v0)]␊ + impl SafeAllowanceCamelImpl = ERC20Component::SafeAllowanceCamelImpl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc20: ERC20Component::Storage,␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + accesscontrol: AccessControlComponent::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC20Event: ERC20Component::Event,␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + AccessControlEvent: AccessControlComponent::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + defaultAdmin: ContractAddress,␊ + pauser: ContractAddress,␊ + minter: ContractAddress,␊ + upgrader: ContractAddress,␊ + ) {␊ + self.erc20.initializer('MyToken', 'MTK');␊ + self.accesscontrol.initializer();␊ + ␊ + self.erc20._mint(recipient, 2000);␊ + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ + self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊ + self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ + self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn burn(ref self: ContractState, value: u256) {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._burn(caller, value);␊ + }␊ + ␊ + fn pause(ref self: ContractState) {␊ + self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ + self.pausable._unpause();␊ + }␊ + ␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + self.accesscontrol.assert_only_role(MINTER_ROLE);␊ + self.erc20._mint(recipient, amount);␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.accesscontrol.assert_only_role(UPGRADER_ROLE);␊ + self.upgradeable._upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 1954a8db5f8d9cce8169091c0b3ebae7ed38af08..983e7c592144a4e7cd12fc7c16fd54e98f9c4a6a 100644 GIT binary patch literal 1967 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 = { name: 'MyToken', @@ -18,8 +17,8 @@ export const defaults: Required = { burnable: false, pausable: false, premint: '0', - decimals: '18', mintable: false, + safeAllowance: false, access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, info: commonDefaults.info @@ -36,19 +35,7 @@ export interface ERC20Options extends CommonOptions { pausable?: boolean; premint?: string; mintable?: boolean; - decimals?: string; -} - -function checkDecimals(decimals: string) { - if (!/^\d+$/.test(decimals)) { - throw new OptionsError({ - decimals: 'Not a valid number', - }); - } else if (parseInt(decimals) >= 256) { // 8 bits - throw new OptionsError({ - decimals: 'Number too large', - }); - } + safeAllowance?: boolean; } function withDefaults(opts: ERC20Options): Required { @@ -59,330 +46,153 @@ function withDefaults(opts: ERC20Options): Required { pausable: opts.pausable ?? defaults.pausable, premint: opts.premint || defaults.premint, mintable: opts.mintable ?? defaults.mintable, - decimals: opts.decimals || defaults.decimals, + safeAllowance: opts.safeAllowance ?? defaults.safeAllowance, }; } export function isAccessControlRequired(opts: Partial): boolean { - return opts.mintable === true || opts.pausable === true; + return opts.mintable === true || opts.pausable === true || opts.upgradeable === true; } export function buildERC20(opts: ERC20Options): Contract { - const c = new ContractBuilder(); + const c = new ContractBuilder(opts.name); const allOpts = withDefaults(opts); - checkDecimals(allOpts.decimals); - - addBase(c, allOpts.name, allOpts.symbol, allOpts.decimals); + addBase(c, allOpts.name, allOpts.symbol); - c.addFunction(functions.name); - c.addFunction(functions.symbol); - c.addFunction(functions.totalSupply); - c.addFunction(functions.decimals); - c.addFunction(functions.balanceOf); - c.addFunction(functions.allowance); - - c.addFunction(functions.transfer); - c.addFunction(functions.transferFrom); - c.addFunction(functions.approve); - c.addFunction(functions.increaseAllowance); - c.addFunction(functions.decreaseAllowance); - - importUint256(c); + if (allOpts.premint) { + addPremint(c, allOpts.premint); + } if (allOpts.burnable) { addBurnable(c); } if (allOpts.pausable) { - addPausable(c, allOpts.access, [functions.transfer, functions.transferFrom, functions.approve, functions.increaseAllowance, functions.decreaseAllowance]); + addPausable(c, allOpts.access); if (allOpts.burnable) { setPausable(c, functions.burn); } } - if (allOpts.premint) { - addPremint(c, allOpts.premint, allOpts.decimals); - } - if (allOpts.mintable) { addMintable(c, allOpts.access); } + if (allOpts.safeAllowance) { + addSafeAllowance(c); + } + setAccessControl(c, allOpts.access); - setUpgradeable(c, allOpts.upgradeable); - + setUpgradeable(c, allOpts.upgradeable, allOpts.access); setInfo(c, allOpts.info); return c; } -function addBase(c: ContractBuilder, name: string, symbol: string, decimals: string) { - c.addModule( - modules.ERC20, - [ - name, symbol, { lit: decimals } - ], +function addBase(c: ContractBuilder, name: string, symbol: string) { + c.addComponent( + components.ERC20Component, [ - functions.transfer, functions.transferFrom, functions.approve, functions.increaseAllowance, functions.decreaseAllowance + name, symbol ], true, ); } -function addBurnable(c: ContractBuilder) { - importGetCallerAddress(c); - c.addFunction(functions.burn); - c.setFunctionBody( - [ - 'let (owner) = get_caller_address()', - 'ERC20._burn(owner, amount)' - ], - functions.burn +function addSafeAllowance(c: ContractBuilder) { + c.addImplToComponent(components.ERC20Component, + { + name: 'SafeAllowanceImpl', + value: 'ERC20Component::SafeAllowanceImpl', + }, + ); + c.addImplToComponent(components.ERC20Component, + { + name: 'SafeAllowanceCamelImpl', + value: 'ERC20Component::SafeAllowanceCamelImpl', + }, ); } +function addBurnable(c: ContractBuilder) { + c.addStandaloneImport('starknet::get_caller_address'); + c.addFunction(externalTrait, functions.burn); +} + export const premintPattern = /^(\d*\.?\d*)$/; -function addPremint(c: ContractBuilder, amount: string, decimals: string) { +function addPremint(c: ContractBuilder, amount: string) { if (amount !== undefined && amount !== '0') { - if (!premintPattern.test(amount)) { throw new OptionsError({ premint: 'Not a valid number', }); } - const premintAbsolute = getInitialSupply(amount, parseInt(decimals)); - - try { - const premintUint256 = toUint256(premintAbsolute); - - c.addConstructorArgument({ name:'recipient', type:'felt' }); - c.addConstructorCode(`ERC20._mint(recipient, Uint256(${premintUint256.lowBits}, ${premintUint256.highBits}))`); - } catch (e: any) { - if (e instanceof NumberTooLarge) { - throw new OptionsError({ - premint: 'Premint argument too large', - decimals: 'Premint argument too large', - }); - } - } + c.addStandaloneImport('starknet::ContractAddress'); + c.addConstructorArgument({ name:'recipient', type:'ContractAddress' }); + c.addConstructorCode(`self.erc20._mint(recipient, ${amount})`); } } -/** - * Calculates the initial supply that would be used in an ERC20 contract based on a given premint amount and number of decimals. - * - * @param premint Premint amount in token units, may be fractional - * @param decimals The number of decimals in the token - * @returns `premint` with zeros padded or removed based on `decimals`. - * @throws OptionsError if `premint` has more than one decimal character or is more precise than allowed by the `decimals` argument. - */ -export function getInitialSupply(premint: string, decimals: number): string { - let result; - const premintSegments = premint.split("."); - if (premintSegments.length > 2) { - throw new OptionsError({ - premint: 'Not a valid number', - }); - } else { - let firstSegment = premintSegments[0] ?? ''; - let lastSegment = premintSegments[1] ?? ''; - if (decimals > lastSegment.length) { - try { - lastSegment += "0".repeat(decimals - lastSegment.length); - } catch (e) { - // .repeat gives an error if number is too large, although this should not happen since decimals is limited to 256 - throw new OptionsError({ - decimals: 'Number too large', - }); - } - } else if (decimals < lastSegment.length) { - throw new OptionsError({ - premint: 'Too many decimals', - }); - } - // concat segments without leading zeros - result = firstSegment.concat(lastSegment).replace(/^0+/, ''); - } - if (result.length === 0) { - result = '0'; - } - return result; -} - function addMintable(c: ContractBuilder, access: Access) { - requireAccessControl(c, functions.mint, access, 'MINTER'); + c.addStandaloneImport('starknet::ContractAddress'); + requireAccessControl(c, externalTrait, functions.mint, access, 'MINTER', 'minter'); } -const modules = defineModules( { - ERC20: { - path: 'openzeppelin.token.erc20.library', - useNamespace: true +const components = defineComponents( { + ERC20Component: { + path: 'openzeppelin::token::erc20', + substorage: { + name: 'erc20', + type: 'ERC20Component::Storage', + }, + event: { + name: 'ERC20Event', + type: 'ERC20Component::Event', + }, + impls: [ + { + name: 'ERC20Impl', + value: 'ERC20Component::ERC20Impl', + }, + { + name: 'ERC20MetadataImpl', + value: 'ERC20Component::ERC20MetadataImpl', + }, + { + name: 'ERC20CamelOnlyImpl', + value: 'ERC20Component::ERC20CamelOnlyImpl', + }, + ], + internalImpl: { + name: 'ERC20InternalImpl', + value: 'ERC20Component::InternalImpl', + }, }, - - bool: { - path: 'starkware.cairo.common.bool', - useNamespace: false - } -}) +}); const functions = defineFunctions({ - - // --- view functions --- - - name: { - module: modules.ERC20, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - ], - returns: [{ name: 'name', type: 'felt' }], - passthrough: true, - }, - - symbol: { - module: modules.ERC20, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - ], - returns: [{ name: 'symbol', type: 'felt' }], - passthrough: true, - }, - - totalSupply: { - module: modules.ERC20, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - ], - returns: [{ name: 'totalSupply', type: 'Uint256' }], - passthrough: 'strict', - parentFunctionName: 'total_supply', - }, - - decimals: { - module: modules.ERC20, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - ], - returns: [{ name: 'decimals', type: 'felt' }], - passthrough: true, - }, - - balanceOf: { - module: modules.ERC20, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'account', type: 'felt' }, - ], - returns: [{ name: 'balance', type: 'Uint256' }], - passthrough: true, - parentFunctionName: 'balance_of', - }, - - allowance: { - module: modules.ERC20, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'owner', type: 'felt' }, - { name: 'spender', type: 'felt' }, - ], - returns: [{ name: 'remaining', type: 'Uint256' }], - passthrough: true, - }, - - // --- external functions --- - - transfer: { - module: modules.ERC20, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'recipient', type: 'felt' }, - { name: 'amount', type: 'Uint256' }, - ], - returns: [{ name: 'success', type: 'felt' }], - passthrough: true, - }, - - transferFrom: { - module: modules.ERC20, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'sender', type: 'felt' }, - { name: 'recipient', type: 'felt' }, - { name: 'amount', type: 'Uint256' }, - ], - returns: [{ name: 'success', type: 'felt' }], - passthrough: true, - parentFunctionName: 'transfer_from', - }, - - approve: { - module: modules.ERC20, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'spender', type: 'felt' }, - { name: 'amount', type: 'Uint256' }, - ], - returns: [{ name: 'success', type: 'felt' }], - passthrough: true, - }, - - increaseAllowance: { - module: modules.ERC20, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'spender', type: 'felt' }, - { name: 'added_value', type: 'Uint256' }, - ], - returns: [{ name: 'success', type: 'felt' }], - passthrough: true, - parentFunctionName: 'increase_allowance', - }, - - decreaseAllowance: { - module: modules.ERC20, - kind: 'external', - implicitArgs: withImplicitArgs(), + burn: { args: [ - { name: 'spender', type: 'felt' }, - { name: 'subtracted_value', type: 'Uint256' }, + getSelfArg(), + { name: 'value', type: 'u256' } ], - returns: [{ name: 'success', type: 'felt' }], - passthrough: true, - parentFunctionName: 'decrease_allowance', + code: [ + 'let caller = get_caller_address();', + 'self.erc20._burn(caller, value);' + ] }, - mint: { - module: modules.ERC20, - kind: 'external', - implicitArgs: withImplicitArgs(), args: [ - { name: 'to', type: 'felt' }, - { name: 'amount', type: 'Uint256' }, + getSelfArg(), + { name: 'recipient', type: 'ContractAddress' }, + { name: 'amount', type: 'u256' } ], - parentFunctionName: '_mint' - }, - - burn: { - module: modules.ERC20, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'amount', type: 'Uint256' }, - ], - parentFunctionName: '_burn' - }, - + code: [ + 'self.erc20._mint(recipient, amount);' + ] + } }); diff --git a/packages/core-cairo/src/erc721.test.ts b/packages/core-cairo/src/erc721.test.ts index ed79d152..248d5bf0 100644 --- a/packages/core-cairo/src/erc721.test.ts +++ b/packages/core-cairo/src/erc721.test.ts @@ -75,5 +75,5 @@ test('API assert defaults', async t => { test('API isAccessControlRequired', async t => { t.is(erc721.isAccessControlRequired({ mintable: true }), true); t.is(erc721.isAccessControlRequired({ pausable: true }), true); - t.is(erc721.isAccessControlRequired({ upgradeable: true }), false); + t.is(erc721.isAccessControlRequired({ upgradeable: true }), true); }); \ 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 5a987f27..c52f942a 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -10,111 +10,48 @@ Generated by [AVA](https://avajs.dev). `// 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␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - ERC721.initializer('MyToken', 'MTK');␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC721.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC721.symbol();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) -> (balance: Uint256) {␊ - return ERC721.balance_of(owner);␊ - }␊ - ␊ - @view␊ - func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (owner: felt) {␊ - return ERC721.owner_of(token_id);␊ - }␊ - ␊ - @view␊ - func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (approved: felt) {␊ - return ERC721.get_approved(token_id);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC721.is_approved_for_all(owner, operator);␊ - }␊ - ␊ - @view␊ - func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) -> (tokenURI: felt) {␊ - let (tokenURI) = ERC721.token_uri(tokenId);␊ - return (tokenURI=tokenURI);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.approve(to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC721.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.transfer_from(from_, to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + ␊ + component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc721: ERC721Component::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC721Event: ERC721Component::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.erc721.initializer('MyToken', 'MTK');␊ + }␊ }␊ ` @@ -124,120 +61,59 @@ Generated by [AVA](https://avajs.dev). `// 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␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - ERC721.initializer('MyToken', 'MTK');␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC721.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC721.symbol();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) -> (balance: Uint256) {␊ - return ERC721.balance_of(owner);␊ - }␊ - ␊ - @view␊ - func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (owner: felt) {␊ - return ERC721.owner_of(token_id);␊ - }␊ - ␊ - @view␊ - func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (approved: felt) {␊ - return ERC721.get_approved(token_id);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC721.is_approved_for_all(owner, operator);␊ - }␊ - ␊ - @view␊ - func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) -> (tokenURI: felt) {␊ - let (tokenURI) = ERC721.token_uri(tokenId);␊ - return (tokenURI=tokenURI);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.approve(to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC721.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.transfer_from(from_, to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) {␊ - ERC721.assert_only_token_owner(tokenId);␊ - ERC721._burn(tokenId);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use starknet::get_caller_address;␊ + ␊ + component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + ␊ + impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc721: ERC721Component::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC721Event: ERC721Component::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState) {␊ + self.erc721.initializer('MyToken', 'MTK');␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn burn(ref self: ContractState, token_id: u256) {␊ + let caller = get_caller_address();␊ + assert(self.erc721._is_approved_or_owner(caller, token_id), ERC721Component::Errors::UNAUTHORIZED);␊ + self.erc721._burn(token_id);␊ + }␊ + }␊ }␊ ` @@ -247,158 +123,84 @@ Generated by [AVA](https://avajs.dev). `// 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␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC721.initializer('MyToken', 'MTK');␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC721.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC721.symbol();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) -> (balance: Uint256) {␊ - return ERC721.balance_of(owner);␊ - }␊ - ␊ - @view␊ - func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (owner: felt) {␊ - return ERC721.owner_of(token_id);␊ - }␊ - ␊ - @view␊ - func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (approved: felt) {␊ - return ERC721.get_approved(token_id);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC721.is_approved_for_all(owner, operator);␊ - }␊ - ␊ - @view␊ - func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) -> (tokenURI: felt) {␊ - let (tokenURI) = ERC721.token_uri(tokenId);␊ - return (tokenURI=tokenURI);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.approve(to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.transfer_from(from_, to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc721: ERC721Component::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC721Event: ERC721Component::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.erc721.initializer('MyToken', 'MTK');␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + }␊ }␊ ` @@ -408,144 +210,77 @@ Generated by [AVA](https://avajs.dev). `// 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␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.access.ownable.library import Ownable␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) {␊ - ERC721.initializer('MyToken', 'MTK');␊ - Ownable.initializer(owner);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC721.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC721.symbol();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) -> (balance: Uint256) {␊ - return ERC721.balance_of(owner);␊ - }␊ - ␊ - @view␊ - func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (owner: felt) {␊ - return ERC721.owner_of(token_id);␊ - }␊ - ␊ - @view␊ - func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (approved: felt) {␊ - return ERC721.get_approved(token_id);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC721.is_approved_for_all(owner, operator);␊ - }␊ - ␊ - @view␊ - func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) -> (tokenURI: felt) {␊ - let (tokenURI) = ERC721.token_uri(tokenId);␊ - return (tokenURI=tokenURI);␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.approve(to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC721.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.transfer_from(from_, to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeMint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256, data_len: felt, data: felt*, tokenURI: felt␊ - ) {␊ - Ownable.assert_only_owner();␊ - ERC721._safe_mint(to, tokenId, data_len, data);␊ - ERC721._set_token_uri(tokenId, tokenURI);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use starknet::ContractAddress;␊ + ␊ + component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc721: ERC721Component::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC721Event: ERC721Component::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.erc721.initializer('MyToken', 'MTK');␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn safe_mint(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + token_uri: felt252,␊ + ) {␊ + self.ownable.assert_only_owner();␊ + self.erc721._safe_mint(recipient, token_id, data);␊ + self.erc721._set_token_uri(token_id, token_uri);␊ + }␊ + }␊ }␊ ` @@ -555,169 +290,84 @@ Generated by [AVA](https://avajs.dev). `// 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␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.access.accesscontrol.library import AccessControl␊ - from openzeppelin.utils.constants.library import DEFAULT_ADMIN_ROLE␊ - ␊ - const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5; // keccak256('MINTER_ROLE')[0:251 bits]␊ - ␊ - @constructor␊ - func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - admin: felt␊ - ) {␊ - ERC721.initializer('MyToken', 'MTK');␊ - AccessControl.initializer();␊ - ␊ - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin);␊ - AccessControl._grant_role(MINTER_ROLE, admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC721.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC721.symbol();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) -> (balance: Uint256) {␊ - return ERC721.balance_of(owner);␊ - }␊ - ␊ - @view␊ - func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (owner: felt) {␊ - return ERC721.owner_of(token_id);␊ - }␊ - ␊ - @view␊ - func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (approved: felt) {␊ - return ERC721.get_approved(token_id);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC721.is_approved_for_all(owner, operator);␊ - }␊ - ␊ - @view␊ - func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) -> (tokenURI: felt) {␊ - let (tokenURI) = ERC721.token_uri(tokenId);␊ - return (tokenURI=tokenURI);␊ - }␊ - ␊ - @view␊ - func hasRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) -> (has_role: felt) {␊ - return AccessControl.has_role(role, user);␊ - }␊ - ␊ - @view␊ - func getRoleAdmin{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt␊ - ) -> (admin: felt) {␊ - return AccessControl.get_role_admin(role);␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.approve(to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - ERC721.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256␊ - ) {␊ - ERC721.transfer_from(from_, to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*␊ - ) {␊ - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func grantRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.grant_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func revokeRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.revoke_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceRole{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - role: felt, user: felt␊ - ) {␊ - AccessControl.renounce_role(role, user);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeMint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256, data_len: felt, data: felt*, tokenURI: felt␊ - ) {␊ - AccessControl.assert_only_role(MINTER_ROLE);␊ - ERC721._safe_mint(to, tokenId, data_len, data);␊ - ERC721._set_token_uri(tokenId, tokenURI);␊ - return ();␊ + const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊ + ␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::access::accesscontrol::AccessControlComponent;␊ + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use starknet::ContractAddress;␊ + use super::{MINTER_ROLE};␊ + ␊ + component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + #[abi(embed_v0)]␊ + impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ + #[abi(embed_v0)]␊ + impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ + ␊ + impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc721: ERC721Component::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + accesscontrol: AccessControlComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC721Event: ERC721Component::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + AccessControlEvent: AccessControlComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, defaultAdmin: ContractAddress, minter: ContractAddress) {␊ + self.erc721.initializer('MyToken', 'MTK');␊ + self.accesscontrol.initializer();␊ + ␊ + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ + self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn safe_mint(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + token_uri: felt252,␊ + ) {␊ + self.accesscontrol.assert_only_role(MINTER_ROLE);␊ + self.erc721._safe_mint(recipient, token_id, data);␊ + self.erc721._set_token_uri(token_id, token_uri);␊ + }␊ + }␊ }␊ ` @@ -727,189 +377,120 @@ Generated by [AVA](https://avajs.dev). `// 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␊ - from openzeppelin.introspection.erc165.library import ERC165␊ - from openzeppelin.security.pausable.library import Pausable␊ - from openzeppelin.access.ownable.library import Ownable␊ - from openzeppelin.upgrades.library import Proxy␊ - ␊ - @external␊ - func initializer{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, proxy_admin: felt␊ - ) {␊ - ERC721.initializer('MyToken', 'MTK');␊ - Ownable.initializer(owner);␊ - Proxy.initializer(proxy_admin);␊ - return ();␊ - }␊ - ␊ - //␊ - // Getters␊ - //␊ - ␊ - @view␊ - func supportsInterface{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - interfaceId: felt␊ - ) -> (success: felt) {␊ - return ERC165.supports_interface(interfaceId);␊ - }␊ - ␊ - @view␊ - func name{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (name: felt) {␊ - return ERC721.name();␊ - }␊ - ␊ - @view␊ - func symbol{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (symbol: felt) {␊ - return ERC721.symbol();␊ - }␊ - ␊ - @view␊ - func balanceOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt␊ - ) -> (balance: Uint256) {␊ - return ERC721.balance_of(owner);␊ - }␊ - ␊ - @view␊ - func ownerOf{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (owner: felt) {␊ - return ERC721.owner_of(token_id);␊ - }␊ - ␊ - @view␊ - func getApproved{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - token_id: Uint256␊ - ) -> (approved: felt) {␊ - return ERC721.get_approved(token_id);␊ - }␊ - ␊ - @view␊ - func isApprovedForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - owner: felt, operator: felt␊ - ) -> (approved: felt) {␊ - return ERC721.is_approved_for_all(owner, operator);␊ - }␊ - ␊ - @view␊ - func tokenURI{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) -> (tokenURI: felt) {␊ - let (tokenURI) = ERC721.token_uri(tokenId);␊ - return (tokenURI=tokenURI);␊ - }␊ - ␊ - @view␊ - func paused{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (paused: felt) {␊ - return Pausable.is_paused();␊ - }␊ - ␊ - @view␊ - func owner{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (owner: felt) {␊ - return Ownable.owner();␊ - }␊ - ␊ - //␊ - // Externals␊ - //␊ - ␊ - @external␊ - func approve{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.approve(to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func setApprovalForAll{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - operator: felt, approved: felt␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.set_approval_for_all(operator, approved);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.transfer_from(from_, to, tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeTransferFrom{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - from_: felt, to: felt, tokenId: Uint256, data_len: felt, data: felt*␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.safe_transfer_from(from_, to, tokenId, data_len, data);␊ - return ();␊ - }␊ - ␊ - @external␊ - func transferOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - newOwner: felt␊ - ) {␊ - Ownable.transfer_ownership(newOwner);␊ - return ();␊ - }␊ - ␊ - @external␊ - func renounceOwnership{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.renounce_ownership();␊ - return ();␊ - }␊ - ␊ - @external␊ - func pause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._pause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func unpause{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() {␊ - Ownable.assert_only_owner();␊ - Pausable._unpause();␊ - return ();␊ - }␊ - ␊ - @external␊ - func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - tokenId: Uint256␊ - ) {␊ - Pausable.assert_not_paused();␊ - ERC721.assert_only_token_owner(tokenId);␊ - ERC721._burn(tokenId);␊ - return ();␊ - }␊ - ␊ - @external␊ - func safeMint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - to: felt, tokenId: Uint256, data_len: felt, data: felt*, tokenURI: felt␊ - ) {␊ - Pausable.assert_not_paused();␊ - Ownable.assert_only_owner();␊ - ERC721._safe_mint(to, tokenId, data_len, data);␊ - ERC721._set_token_uri(tokenId, tokenURI);␊ - return ();␊ - }␊ - ␊ - @external␊ - func upgrade{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(␊ - new_implementation: felt␊ - ) -> () {␊ - Proxy.assert_only_admin();␊ - Proxy._set_implementation_hash(new_implementation);␊ - return ();␊ + #[starknet::contract]␊ + mod MyToken {␊ + use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::upgrades::interface::IUpgradeable;␊ + use starknet::get_caller_address;␊ + use starknet::ContractAddress;␊ + use starknet::ClassHash;␊ + ␊ + component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ + component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ + ␊ + #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl SRC5Impl = SRC5Component::SRC5Impl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableImpl = OwnableComponent::OwnableImpl;␊ + #[abi(embed_v0)]␊ + impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + ␊ + impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ + ␊ + #[storage]␊ + struct Storage {␊ + #[substorage(v0)]␊ + erc721: ERC721Component::Storage,␊ + #[substorage(v0)]␊ + src5: SRC5Component::Storage,␊ + #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + #[substorage(v0)]␊ + upgradeable: UpgradeableComponent::Storage,␊ + }␊ + ␊ + #[event]␊ + #[derive(Drop, starknet::Event)]␊ + enum Event {␊ + #[flat]␊ + ERC721Event: ERC721Component::Event,␊ + #[flat]␊ + SRC5Event: SRC5Component::Event,␊ + #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + #[flat]␊ + UpgradeableEvent: UpgradeableComponent::Event,␊ + }␊ + ␊ + #[constructor]␊ + fn constructor(ref self: ContractState, owner: ContractAddress) {␊ + self.erc721.initializer('MyToken', 'MTK');␊ + self.ownable.initializer(owner);␊ + }␊ + ␊ + #[generate_trait]␊ + #[external(v0)]␊ + impl External of ExternalTrait {␊ + fn burn(ref self: ContractState, token_id: u256) {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + assert(self.erc721._is_approved_or_owner(caller, token_id), ERC721Component::Errors::UNAUTHORIZED);␊ + self.erc721._burn(token_id);␊ + }␊ + ␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + ␊ + fn safe_mint(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + token_uri: felt252,␊ + ) {␊ + self.ownable.assert_only_owner();␊ + self.erc721._safe_mint(recipient, token_id, data);␊ + self.erc721._set_token_uri(token_id, token_uri);␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl UpgradeableImpl of IUpgradeable {␊ + fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {␊ + self.ownable.assert_only_owner();␊ + self.upgradeable._upgrade(new_class_hash);␊ + }␊ + }␊ }␊ ` diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index 0eb9b9792fe5b60f07b7004b7d42614b0ce0467e..3a22f3ee281f4e344751386051885ebd93bde108 100644 GIT binary patch literal 1581 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 = { name: 'MyToken', @@ -45,44 +45,25 @@ function withDefaults(opts: ERC721Options): Required { } export function isAccessControlRequired(opts: Partial): boolean { - return opts.mintable === true || opts.pausable === true; + return opts.mintable === true || opts.pausable === true || opts.upgradeable === true; } export function buildERC721(opts: ERC721Options): Contract { - const c = new ContractBuilder(); + const c = new ContractBuilder(opts.name); const allOpts = withDefaults(opts); addBase(c, allOpts.name, allOpts.symbol); - addSupportsInterface(c); - c.addFunction(functions.name); - c.addFunction(functions.symbol); - c.addFunction(functions.balanceOf); - c.addFunction(functions.ownerOf); - c.addFunction(functions.getApproved); - c.addFunction(functions.isApprovedForAll); - c.addFunction(functions.tokenURI); - - c.addFunction(functions.approve); - c.addFunction(functions.setApprovalForAll); - c.addFunction(functions.transferFrom); - c.addFunction(functions.safeTransferFrom); - - importUint256(c); + if (allOpts.burnable) { + addBurnable(c); + } if (allOpts.pausable) { - addPausable(c, allOpts.access, [functions.approve, functions.setApprovalForAll, functions.transferFrom, functions.safeTransferFrom]); + addPausable(c, allOpts.access); if (allOpts.burnable) { setPausable(c, functions.burn); } - if (allOpts.mintable) { - setPausable(c, functions.safeMint); - } - } - - if (allOpts.burnable) { - addBurnable(c); } if (allOpts.mintable) { @@ -90,206 +71,92 @@ export function buildERC721(opts: ERC721Options): Contract { } setAccessControl(c, allOpts.access); - setUpgradeable(c, allOpts.upgradeable); - + setUpgradeable(c, allOpts.upgradeable, allOpts.access); setInfo(c, allOpts.info); return c; } function addBase(c: ContractBuilder, name: string, symbol: string) { - c.addModule( - modules.ERC721, - [name, symbol], - [functions.approve, functions.setApprovalForAll, functions.transferFrom, functions.safeTransferFrom], + c.addComponent( + components.ERC721Component, + [ + name, symbol + ], true, ); + addSRC5Component(c); } function addBurnable(c: ContractBuilder) { - c.addFunction(functions.burn); - c.setFunctionBody( - [ - 'ERC721.assert_only_token_owner(tokenId)', - 'ERC721._burn(tokenId)' - ], - functions.burn - ); + c.addStandaloneImport('starknet::get_caller_address'); + c.addFunction(externalTrait, functions.burn); } function addMintable(c: ContractBuilder, access: Access) { - requireAccessControl(c, functions.safeMint, access, 'MINTER'); - c.setFunctionBody( - [ - 'ERC721._safe_mint(to, tokenId, data_len, data)', - 'ERC721._set_token_uri(tokenId, tokenURI)' - ], - functions.safeMint - ); + c.addStandaloneImport('starknet::ContractAddress'); + requireAccessControl(c, externalTrait, functions.safe_mint, access, 'MINTER', 'minter'); } -const modules = defineModules( { - ERC721: { - path: 'openzeppelin.token.erc721.library', - useNamespace: true +const components = defineComponents( { + ERC721Component: { + path: 'openzeppelin::token::erc721', + substorage: { + name: 'erc721', + type: 'ERC721Component::Storage', + }, + event: { + name: 'ERC721Event', + type: 'ERC721Component::Event', + }, + impls: [ + { + name: 'ERC721Impl', + value: 'ERC721Component::ERC721Impl', + }, + { + name: 'ERC721MetadataImpl', + value: 'ERC721Component::ERC721MetadataImpl', + }, + { + name: 'ERC721CamelOnly', + value: 'ERC721Component::ERC721CamelOnlyImpl', + }, + { + name: 'ERC721MetadataCamelOnly', + value: 'ERC721Component::ERC721MetadataCamelOnlyImpl', + } + ], + internalImpl: { + name: 'ERC721InternalImpl', + value: 'ERC721Component::InternalImpl', + }, }, }); const functions = defineFunctions({ - - // --- view functions --- - - name: { - module: modules.ERC721, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - ], - returns: [{ name: 'name', type: 'felt' }], - passthrough: true, - }, - - symbol: { - module: modules.ERC721, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - ], - returns: [{ name: 'symbol', type: 'felt' }], - passthrough: true, - }, - - balanceOf: { - module: modules.ERC721, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'owner', type: 'felt' }, - ], - returns: [{ name: 'balance', type: 'Uint256' }], - passthrough: true, - parentFunctionName: 'balance_of', - }, - - ownerOf: { - module: modules.ERC721, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'token_id', type: 'Uint256' }, - ], - returns: [{ name: 'owner', type: 'felt' }], - passthrough: true, - parentFunctionName: 'owner_of', - }, - - getApproved: { - module: modules.ERC721, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'token_id', type: 'Uint256' }, - ], - returns: [{ name: 'approved', type: 'felt' }], - passthrough: true, - parentFunctionName: 'get_approved', - }, - - isApprovedForAll: { - module: modules.ERC721, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'owner', type: 'felt' }, - { name: 'operator', type: 'felt' }, - ], - returns: [{ name: 'approved', type: 'felt' }], - passthrough: true, - parentFunctionName: 'is_approved_for_all', - }, - - tokenURI: { - module: modules.ERC721, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'tokenId', type: 'Uint256' }, - ], - returns: [{ name: 'tokenURI', type: 'felt' }], - passthrough: 'strict', - parentFunctionName: 'token_uri', - }, - - // --- external functions --- - - approve: { - module: modules.ERC721, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'to', type: 'felt' }, - { name: 'tokenId', type: 'Uint256' }, - ], - }, - - setApprovalForAll: { - module: modules.ERC721, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'operator', type: 'felt' }, - { name: 'approved', type: 'felt' }, - ], - parentFunctionName: 'set_approval_for_all', - }, - - transferFrom: { - module: modules.ERC721, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'from_', type: 'felt' }, - { name: 'to', type: 'felt' }, - { name: 'tokenId', type: 'Uint256' }, - ], - parentFunctionName: 'transfer_from', - }, - - safeTransferFrom: { - module: modules.ERC721, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'from_', type: 'felt' }, - { name: 'to', type: 'felt' }, - { name: 'tokenId', type: 'Uint256' }, - { name: 'data_len', type: 'felt' }, - { name: 'data', type: 'felt*' }, - ], - parentFunctionName: 'safe_transfer_from', - }, - - safeMint: { - module: modules.ERC721, - kind: 'external', - implicitArgs: withImplicitArgs(), + burn: { args: [ - { name: 'to', type: 'felt' }, - { name: 'tokenId', type: 'Uint256' }, - { name: 'data_len', type: 'felt' }, - { name: 'data', type: 'felt*' }, - { name: 'tokenURI', type: 'felt' }, + getSelfArg(), + { name: 'token_id', type: 'u256' } ], - parentFunctionName: '_safe_mint', + code: [ + 'let caller = get_caller_address();', + 'assert(self.erc721._is_approved_or_owner(caller, token_id), ERC721Component::Errors::UNAUTHORIZED)', + 'self.erc721._burn(token_id);' + ] }, - - burn: { - module: modules.ERC721, - kind: 'external', - implicitArgs: withImplicitArgs(), + safe_mint: { args: [ - { name: 'tokenId', type: 'Uint256' }, + getSelfArg(), + { name: 'recipient', type: 'ContractAddress' }, + { name: 'token_id', type: 'u256' }, + { name: 'data', type: 'Span' }, + { name: 'token_uri', type: 'felt252' }, ], - }, - -}); \ No newline at end of file + code: [ + 'self.erc721._safe_mint(recipient, token_id, data);', + 'self.erc721._set_token_uri(token_id, token_uri);', + ] + } +}); diff --git a/packages/core-cairo/src/external-trait.ts b/packages/core-cairo/src/external-trait.ts new file mode 100644 index 00000000..a89fea14 --- /dev/null +++ b/packages/core-cairo/src/external-trait.ts @@ -0,0 +1,10 @@ +import type { BaseImplementedTrait } from "./contract"; + +export const externalTrait: BaseImplementedTrait = { + name: 'External', + of: 'ExternalTrait', + tags: [ + '#[generate_trait]', + '#[external(v0)]' + ], +} diff --git a/packages/core-cairo/src/generate/alternatives.ts b/packages/core-cairo/src/generate/alternatives.ts index e2660353..afd89ab6 100644 --- a/packages/core-cairo/src/generate/alternatives.ts +++ b/packages/core-cairo/src/generate/alternatives.ts @@ -1,5 +1,3 @@ -import { mapValues } from "../utils/map-values"; - type Blueprint = Record; type Alternatives = { diff --git a/packages/core-cairo/src/generate/erc20.ts b/packages/core-cairo/src/generate/erc20.ts index 50a80305..5621199e 100644 --- a/packages/core-cairo/src/generate/erc20.ts +++ b/packages/core-cairo/src/generate/erc20.ts @@ -10,17 +10,13 @@ const blueprint = { name: ['MyToken'], symbol: ['MTK'], burnable: booleans, - snapshots: booleans, pausable: booleans, mintable: booleans, - permit: booleans, - votes: booleans, - flashmint: booleans, + safeAllowance: booleans, premint: ['1'], access: accessOptions, upgradeable: upgradeableOptions, - info: infoOptions, - decimals: ['18'] + info: infoOptions }; export function* generateERC20Options(): Generator> { diff --git a/packages/core-cairo/src/generate/erc721.ts b/packages/core-cairo/src/generate/erc721.ts index 2d60c848..c420495f 100644 --- a/packages/core-cairo/src/generate/erc721.ts +++ b/packages/core-cairo/src/generate/erc721.ts @@ -9,13 +9,9 @@ const booleans = [true, false]; const blueprint = { name: ['MyToken'], symbol: ['MTK'], - baseUri: ['https://example.com/'], - enumerable: booleans, - uriStorage: booleans, burnable: booleans, pausable: booleans, mintable: booleans, - incremental: booleans, access: accessOptions, upgradeable: upgradeableOptions, info: infoOptions, diff --git a/packages/core-cairo/src/generate/sources.ts b/packages/core-cairo/src/generate/sources.ts index 319ea77f..2846be40 100644 --- a/packages/core-cairo/src/generate/sources.ts +++ b/packages/core-cairo/src/generate/sources.ts @@ -62,7 +62,7 @@ function generateContractSubset(subset: Subset): GeneratedContract[] { if (subset === 'all') { return contracts; } else { - const getParents = (c: GeneratedContract) => c.contract.libraries.map(p => p.module.path); + const getParents = (c: GeneratedContract) => c.contract.components.map(p => p.path); return [ ...findCover(contracts.filter(c => c.options.upgradeable), getParents), ...findCover(contracts.filter(c => !c.options.upgradeable), getParents), diff --git a/packages/core-cairo/src/index.ts b/packages/core-cairo/src/index.ts index 4d386280..ea2f8341 100644 --- a/packages/core-cairo/src/index.ts +++ b/packages/core-cairo/src/index.ts @@ -22,4 +22,4 @@ export { sanitizeKind } from './kind'; export { contractsVersion, contractsVersionTag } from './utils/version'; -export { erc20, erc721, erc1155, custom, utils } from './api'; +export { erc20, erc721, custom } from './api'; diff --git a/packages/core-cairo/src/kind.ts b/packages/core-cairo/src/kind.ts index 30544f33..8f816e99 100644 --- a/packages/core-cairo/src/kind.ts +++ b/packages/core-cairo/src/kind.ts @@ -16,7 +16,6 @@ function isKind(value: Kind | T): value is Kind { switch (value) { case 'ERC20': case 'ERC721': - case 'ERC1155': case 'Custom': return true; diff --git a/packages/core-cairo/src/options.ts b/packages/core-cairo/src/options.ts deleted file mode 100644 index 67e7b2e9..00000000 --- a/packages/core-cairo/src/options.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Contract } from './contract'; - -export interface Helpers { - upgradeable: boolean; -} - -export function withHelpers(contract: Contract): Helpers { - const upgradeable = contract.upgradeable; - return { - upgradeable - }; -} diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 8985b4e4..53a117e8 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -1,62 +1,31 @@ import 'array.prototype.flatmap/auto'; -import type { Contract, Library, ContractFunction, Argument, Value, } from './contract'; -import { Helpers, withHelpers } from './options'; +import type { Contract, Component, Argument, Value, Impl, ContractFunction, } from './contract'; import { formatLines, spaceBetween, Lines } from './utils/format-lines'; -import { getImportsMap } from './utils/imports-map'; -import { mapValues } from './utils/map-values'; -import { getFunctionName } from './utils/module-prefix'; +import { getSelfArg } from './common-options'; export function printContract(contract: Contract): string { - const helpers = withHelpers(contract); - - const fns = mapValues( - sortedFunctions(contract), - fns => fns.map(fn => printFunction(fn)), - ); - - const hasViews = fns.views.some(l => l.length > 0); - const hasExternals = fns.externals.some(l => l.length > 0); - - const { starkwareImports, ozImports } = printImports(contract); - return formatLines( ...spaceBetween( [ `// SPDX-License-Identifier: ${contract.license}`, ], - - [ - `%lang starknet` - ], - + printSuperVariables(contract), [ - ...starkwareImports, + `#[starknet::contract]`, + `mod ${contract.name} {`, + spaceBetween( + printImports(contract), + printComponentDeclarations(contract), + printImpls(contract), + printStorage(contract), + printEvents(contract), + printConstructor(contract), + printImplementedTraits(contract), + ), + `}`, ], - - ozImports, - - spaceBetween( - contract.variables, - printConstructor(contract, helpers), - ...fns.code, - ...fns.modifiers, - hasViews ? - [ - `//`, - `// Getters`, - `//` - ] : [], - ...fns.views, - hasExternals ? - [ - `//`, - `// Externals`, - `//` - ] : [], - ...fns.externals, - ), ), ); } @@ -65,53 +34,134 @@ function withSemicolons(lines: string[]): string[] { return lines.map(line => line.endsWith(';') ? line : line + ';'); } -function printImports(contract: Contract) { - const modulesToLibraryFunctions = getImportsMap(contract); - const { starkwareImportsMap, ozImportsMap } = getVendoredImports(modulesToLibraryFunctions); +function printSuperVariables(contract: Contract) { + return withSemicolons(contract.superVariables.map(v => `const ${v.name}: ${v.type} = ${v.value}`)); +} - const starkwareImports = printImportLines(starkwareImportsMap); - const ozImports = printImportLines(ozImportsMap); - return { starkwareImports, ozImports }; +function printImports(contract: Contract) { + const lines: string[] = []; + const { ozImports, otherImports, superImports } = getCategorizedImports(contract); + ozImports.forEach(i => lines.push(`use ${i}`)); + otherImports.forEach(i => lines.push(`use ${i}`)); + superImports.forEach(i => lines.push(`use ${i}`)); + return withSemicolons(lines); } -function getVendoredImports(parentImportsMap: Map>) { - const starkwareImportsMap: Map> = new Map>(); - const ozImportsMap: Map> = new Map>(); - for (let [key, value] of parentImportsMap) { - if (key.startsWith('starkware')) { - starkwareImportsMap.set(key, value); +function getCategorizedImports(contract: Contract) { + const componentImports = contract.components.flatMap(c => `${c.path}::${c.name}`); + const combined = componentImports.concat(contract.standaloneImports); + + const ozImports = []; + const otherImports = []; + const superImports = []; + + for (const importStatement of combined) { + if (importStatement.startsWith('openzeppelin')) { + ozImports.push(importStatement); } else { - ozImportsMap.set(key, value); + otherImports.push(importStatement); } } - return { starkwareImportsMap, ozImportsMap }; + if (contract.superVariables.length > 0) { + superImports.push(`super::{${contract.superVariables.map(v => v.name).join(', ')}}`); + } + return { ozImports, otherImports, superImports }; } -function printImportLines(importStatements: Map>) { +function printComponentDeclarations(contract: Contract) { const lines = []; - for (const [module, fns] of importStatements.entries()) { - if (fns.size > 1) { - lines.push(`from ${module} import (`); - lines.push(Array.from(fns).map(p => `${p},`)); - lines.push(`)`); - } else if (fns.size === 1) { - lines.push(`from ${module} import ${Array.from(fns)[0]}`); + for (const component of contract.components) { + lines.push(`component!(path: ${component.name}, storage: ${component.substorage.name}, event: ${component.event.name});`); + } + return lines; +} + +function printImpls(contract: Contract) { + const externalImpls = contract.components.flatMap(c => c.impls); + const internalImpls = contract.components.flatMap(c => c.internalImpl ? [c.internalImpl] : []); + + return spaceBetween( + externalImpls.flatMap(impl => printImpl(impl)), + internalImpls.flatMap(impl => printImpl(impl, true)) + ); +} + +function printImpl(impl: Impl, internal = false) { + const lines = []; + if (!internal) { + lines.push('#[abi(embed_v0)]'); + } + lines.push(`impl ${impl.name} = ${impl.value};`); + return lines; +} + +function printStorage(contract: Contract) { + const lines = []; + // storage is required regardless of whether there are components + lines.push('#[storage]'); + lines.push('struct Storage {'); + const storageLines = []; + for (const component of contract.components) { + storageLines.push(`#[substorage(v0)]`); + storageLines.push(`${component.substorage.name}: ${component.substorage.type},`); + } + lines.push(storageLines); + lines.push('}'); + return lines; +} + +function printEvents(contract: Contract) { + const lines = []; + if (contract.components.length > 0) { + lines.push('#[event]'); + lines.push('#[derive(Drop, starknet::Event)]'); + lines.push('enum Event {') + const eventLines = []; + for (const component of contract.components) { + eventLines.push('#[flat]'); + eventLines.push(`${component.event.name}: ${component.event.type},`); } + lines.push(eventLines); + lines.push('}'); } return lines; } -function printConstructor(contract: Contract, helpers: Helpers): Lines[] { - const hasParentParams = contract.libraries.some(p => p.initializer !== undefined && p.initializer.params.length > 0); +function printImplementedTraits(contract: Contract) { + const impls = []; + for (const trait of contract.implementedTraits) { + const implLines = []; + implLines.push(...trait.tags.map(t => `${t}`)); + implLines.push(`impl ${trait.name} of ${trait.of} {`); + const fns = trait.functions.map(fn => printFunction(fn)); + implLines.push(spaceBetween(...fns)); + implLines.push('}'); + impls.push(implLines); + } + return spaceBetween(...impls); +} + +function printFunction(fn: ContractFunction) { + const head = `fn ${fn.name}`; + const args = fn.args.map(a => printArgument(a)); + + const body = spaceBetween( + withSemicolons(fn.codeBefore?.concat(fn.code) ?? fn.code), + ); + return printFunction2(head, args, undefined, undefined, undefined, body); +} + +function printConstructor(contract: Contract): Lines[] { + const hasParentParams = contract.components.some(p => p.initializer !== undefined && p.initializer.params.length > 0); const hasConstructorCode = contract.constructorCode.length > 0; if (hasParentParams || hasConstructorCode) { - const parents = contract.libraries + const parents = contract.components .filter(hasInitializer) .flatMap(p => printParentConstructor(p)); - const modifier = helpers.upgradeable ? 'external' : 'constructor'; - const head = helpers.upgradeable ? 'func initializer' : 'func constructor'; - const args = contract.constructorArgs.map(a => printArgument(a)); - const implicitArgs = contract.constructorImplicitArgs?.map(a => printArgument(a)); + const tag = 'constructor'; + const head = 'fn constructor'; + const args = [ getSelfArg(), ...contract.constructorArgs ]; + const body = spaceBetween( withSemicolons(parents), withSemicolons(contract.constructorCode), @@ -119,11 +169,10 @@ function printConstructor(contract: Contract, helpers: Helpers): Lines[] { const constructor = printFunction2( head, - implicitArgs ?? [], - args, - modifier, + args.map(a => printArgument(a)), + tag, + undefined, undefined, - 'return ();', body, ); return constructor; @@ -132,33 +181,15 @@ function printConstructor(contract: Contract, helpers: Helpers): Lines[] { } } -function hasInitializer(parent: Library) { - return parent.initializer !== undefined && parent.module.name !== undefined; -} - -type SortedFunctions = Record<'code' | 'modifiers' | 'views' | 'externals', ContractFunction[]>; - -function sortedFunctions(contract: Contract): SortedFunctions { - const fns: SortedFunctions = { code: [], modifiers: [], views: [], externals: [] }; - - for (const fn of contract.functions) { - if (fn.kind === undefined && fn.code.length > 0) { // fallback case, not sure if anything fits in this category - fns.code.push(fn); - } else if (fn.kind === 'view') { - fns.views.push(fn); - } else { - fns.externals.push(fn); - } - } - - return fns; +function hasInitializer(parent: Component) { + return parent.initializer !== undefined && parent.substorage?.name !== undefined; } -function printParentConstructor({ module, initializer }: Library): [] | [string] { - if (initializer === undefined || module.name === undefined || !module.useNamespace) { +function printParentConstructor({ substorage, initializer }: Component): [] | [string] { + if (initializer === undefined || substorage?.name === undefined) { return []; } - const fn = `${module.name}.initializer`; + const fn = `self.${substorage.name}.initializer`; return [ fn + '(' + initializer.params.map(printValue).join(', ') + ')', ]; @@ -184,75 +215,29 @@ export function printValue(value: Value): string { } } -function printFunction(fn: ContractFunction): Lines[] { - const code = []; - - const returnArgs = fn.returns?.map(a => typeof a === 'string' ? a : a.name); - - fn.libraryCalls.forEach(libraryCall => { - const libraryCallString = `${getFunctionName(libraryCall.callFn)}(${libraryCall.args.join(', ')})`; - code.push(libraryCallString); - }); - - let returnLine = 'return ();'; - - if (!fn.final && fn.module !== undefined) { - const fnName = getFunctionName(fn); - const parentFunctionCall = fn.read ? - `${fnName}.read()` : - `${fnName}(${fn.args.map(a => a.name).join(', ')})`; - if (!fn.passthrough || returnArgs === undefined || returnArgs.length === 0) { - code.push(parentFunctionCall); - } else if (fn.passthrough === 'strict') { - code.push(`let (${returnArgs}) = ${parentFunctionCall}`); - const namedReturnVars = returnArgs.map(v => `${v}=${v}`).join(', '); - returnLine = `return (${namedReturnVars});`; - } else if (fn.passthrough === true) { - returnLine = `return ${parentFunctionCall};`; - } - } - - code.push(...fn.code); - - return printFunction2( - 'func ' + fn.name, - fn.implicitArgs?.map(a => printArgument(a)) ?? [], - fn.args.map(a => printArgument(a)), - fn.kind, - fn.returns?.map(a => typeof a === 'string' ? a : printArgument(a)), - returnLine, - withSemicolons(code), - ); -} - // generic for functions and constructors -// kindedName = 'func foo' -function printFunction2(kindedName: string, implicitArgs: string[], args: string[], kind: string | undefined, returns: string[] | undefined, returnLine: string, code: Lines[]): Lines[] { +// kindedName = 'fn foo' +function printFunction2(kindedName: string, args: string[], tag: string | undefined, returns: string[] | undefined, returnLine: string | undefined, code: Lines[]): Lines[] { const fn = []; - if (kind !== undefined) { - fn.push(`@${kind}`); + if (tag !== undefined) { + fn.push(`#[${tag}]`); } - let accum = kindedName; + let accum = `${kindedName}(`; - if (implicitArgs.length > 0) { - accum += '{' + implicitArgs.join(', ') + '}'; - } - if (args.length > 0) { - fn.push(`${accum}(`); let formattedArgs = args.join(', '); if (formattedArgs.length > 80) { + fn.push(accum); + accum = ''; // print each arg in a separate line fn.push(args.map(arg => `${arg},`)); } else { - fn.push([formattedArgs]); + accum += `${formattedArgs}`; } - accum = ')'; - } else { - accum += '()'; } + accum += ')'; if (returns === undefined) { accum += ' {'; diff --git a/packages/core-cairo/src/set-access-control.ts b/packages/core-cairo/src/set-access-control.ts index ed2d321d..712d4803 100644 --- a/packages/core-cairo/src/set-access-control.ts +++ b/packages/core-cairo/src/set-access-control.ts @@ -1,9 +1,6 @@ -import { withImplicitArgs } from './common-options'; -import type { ContractBuilder, BaseFunction } from './contract'; -import { defineFunctions } from './utils/define-functions'; -import { defineModules } from './utils/define-modules'; -import { keccak256 } from 'ethereum-cryptography/keccak'; -import { utf8ToBytes, bytesToHex } from 'ethereum-cryptography/utils'; +import type { BaseFunction, BaseImplementedTrait, ContractBuilder } from './contract'; +import { defineComponents } from './utils/define-components'; +import { addSRC5Component } from './common-components'; export const accessOptions = [false, 'ownable', 'roles'] as const; @@ -15,26 +12,22 @@ export type Access = typeof accessOptions[number]; export function setAccessControl(c: ContractBuilder, access: Access) { switch (access) { case 'ownable': { - c.addModule(modules.Ownable, [{ lit:'owner' }], [], true); - c.addConstructorArgument({ name: 'owner', type: 'felt'}); - - c.addFunction(functions.owner); - c.addFunction(functions.transferOwnership); - c.addFunction(functions.renounceOwnership); + c.addComponent(components.OwnableComponent, [{ lit:'owner' }], true); + + c.addStandaloneImport('starknet::ContractAddress'); + c.addConstructorArgument({ name: 'owner', type: 'ContractAddress'}); + break; } case 'roles': { - if (c.addModule(modules.AccessControl)) { - importDefaultAdminRole(c); + if (c.addComponent(components.AccessControlComponent, [], true)) { + addSRC5Component(c); - c.addConstructorArgument({ name: 'admin', type: 'felt'}); - c.addConstructorCode('AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin)'); + c.addStandaloneImport('starknet::ContractAddress'); + c.addConstructorArgument({ name: 'defaultAdmin', type: 'ContractAddress'}); - c.addFunction(functions.hasRole); - c.addFunction(functions.getRoleAdmin); - c.addFunction(functions.grantRole); - c.addFunction(functions.revokeRole); - c.addFunction(functions.renounceRole); + c.addStandaloneImport('openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE'); + c.addConstructorCode('self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin)'); } break; } @@ -44,7 +37,7 @@ export type Access = typeof accessOptions[number]; /** * Enables access control for the contract and restricts the given function with access control. */ -export function requireAccessControl(c: ContractBuilder, fn: BaseFunction, access: Access, role: string) { +export function requireAccessControl(c: ContractBuilder, trait: BaseImplementedTrait, fn: BaseFunction, access: Access, roleIdPrefix: string, roleOwner: string | undefined) { if (access === false) { access = 'ownable'; } @@ -53,147 +46,76 @@ export function requireAccessControl(c: ContractBuilder, fn: BaseFunction, acces switch (access) { case 'ownable': { - c.addLibraryCall(functions.assert_only_owner, fn); + c.addFunctionCodeBefore(trait, fn, 'self.ownable.assert_only_owner()'); break; } case 'roles': { - const roleId = role + '_ROLE'; - if (c.addVariable(`const ${roleId} = ${to251BitHash(roleId)}; // keccak256('${roleId}')[0:251 bits]`)) { - c.addConstructorCode(`AccessControl._grant_role(${roleId}, admin)`); + const roleId = roleIdPrefix + '_ROLE'; + const addedSuper = c.addSuperVariable({ name: roleId, type: 'felt252', value: `selector!("${roleId}")` }) + if (roleOwner !== undefined) { + c.addStandaloneImport('starknet::ContractAddress'); + c.addConstructorArgument({ name: roleOwner, type: 'ContractAddress'}); + if (addedSuper) { + c.addConstructorCode(`self.accesscontrol._grant_role(${roleId}, ${roleOwner})`); + } } - c.addLibraryCall(functions.assert_only_role, fn, [roleId]); + c.addFunctionCodeBefore(trait, fn, `self.accesscontrol.assert_only_role(${roleId})`); + break; } } } -export function to251BitHash(label: string): string { - const hash = bytesToHex(keccak256(utf8ToBytes(label))); - const bin = BigInt('0x' + hash).toString(2).substring(0, 251); - const hex = BigInt('0b' + bin).toString(16); - return '0x' + hex; -} - -function importDefaultAdminRole(c: ContractBuilder) { - c.addModule(modules.constants, [], [], false); - c.addModuleFunction(modules.constants, 'DEFAULT_ADMIN_ROLE'); -} - -const modules = defineModules( { - Ownable: { - path: 'openzeppelin.access.ownable.library', - useNamespace: true - }, - AccessControl: { - path: 'openzeppelin.access.accesscontrol.library', - useNamespace: true - }, - constants: { - path: 'openzeppelin.utils.constants.library', - useNamespace: false - } -}) - -const functions = defineFunctions({ - // --- library-only calls --- - assert_only_owner: { - module: modules.Ownable, - args: [], - }, - - assert_only_role: { - module: modules.AccessControl, - args: [] - }, - - // --- view functions --- - - owner: { - module: modules.Ownable, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [], - returns: [{ name: 'owner', type: 'felt' }], - passthrough: true, - }, - - // --- external functions --- - - transferOwnership: { - module: modules.Ownable, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'newOwner', type: 'felt' }, - ], - parentFunctionName: 'transfer_ownership', - }, - - renounceOwnership: { - module: modules.Ownable, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [], - parentFunctionName: 'renounce_ownership', - }, - - hasRole: { - module: modules.AccessControl, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'role', type: 'felt' }, - { name: 'user', type: 'felt' }, - ], - parentFunctionName: 'has_role', - returns: [{ name: 'has_role', type: 'felt' }], - passthrough: true, - }, - - getRoleAdmin: { - module: modules.AccessControl, - kind: 'view', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'role', type: 'felt' }, +const components = defineComponents( { + OwnableComponent: { + path: 'openzeppelin::access::ownable', + substorage: { + name: 'ownable', + type: 'OwnableComponent::Storage', + }, + event: { + name: 'OwnableEvent', + type: 'OwnableComponent::Event', + }, + impls: [ + { + name: 'OwnableImpl', + value: 'OwnableComponent::OwnableImpl', + }, + { + name: 'OwnableCamelOnlyImpl', + value: 'OwnableComponent::OwnableCamelOnlyImpl', + }, ], - parentFunctionName: 'get_role_admin', - returns: [{ name: 'admin', type: 'felt' }], - passthrough: true, + internalImpl: { + name: 'OwnableInternalImpl', + value: 'OwnableComponent::InternalImpl', + }, }, - - grantRole: { - module: modules.AccessControl, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'role', type: 'felt' }, - { name: 'user', type: 'felt' }, - ], - parentFunctionName: 'grant_role', - }, - - revokeRole: { - module: modules.AccessControl, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'role', type: 'felt' }, - { name: 'user', type: 'felt' }, + AccessControlComponent: { + path: 'openzeppelin::access::accesscontrol', + substorage: { + name: 'accesscontrol', + type: 'AccessControlComponent::Storage', + }, + event: { + name: 'AccessControlEvent', + type: 'AccessControlComponent::Event', + }, + impls: [ + { + name: 'AccessControlImpl', + value: 'AccessControlComponent::AccessControlImpl', + }, + { + name: 'AccessControlCamelImpl', + value: 'AccessControlComponent::AccessControlCamelImpl', + }, ], - parentFunctionName: 'revoke_role', + internalImpl: { + name: 'AccessControlInternalImpl', + value: 'AccessControlComponent::InternalImpl', + }, }, - - renounceRole: { - module: modules.AccessControl, - kind: 'external', - implicitArgs: withImplicitArgs(), - args: [ - { name: 'role', type: 'felt' }, - { name: 'user', type: 'felt' }, - ], - parentFunctionName: 'renounce_role', - }, - -}); \ No newline at end of file +}); diff --git a/packages/core-cairo/src/set-upgradeable.ts b/packages/core-cairo/src/set-upgradeable.ts index 10f9be74..a77cd53f 100644 --- a/packages/core-cairo/src/set-upgradeable.ts +++ b/packages/core-cairo/src/set-upgradeable.ts @@ -1,46 +1,63 @@ -import { withImplicitArgs } from './common-options'; -import type { ContractBuilder } from './contract'; -//import { Access, setAccessControl } from './set-access-control'; +import { getSelfArg } from './common-options'; +import type { BaseImplementedTrait, ContractBuilder } from './contract'; +import { Access, requireAccessControl } from './set-access-control'; +import { defineComponents } from './utils/define-components'; import { defineFunctions } from './utils/define-functions'; -import { defineModules } from './utils/define-modules'; export const upgradeableOptions = [false, true] as const; export type Upgradeable = typeof upgradeableOptions[number]; -export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable) { +export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, access: Access) { if (upgradeable === false) { return; } c.upgradeable = true; - c.addModule(modules.Proxy, [ {lit: 'proxy_admin' }], [], true); + c.addComponent(components.UpgradeableComponent, [], false); - c.addConstructorArgument({ name:'proxy_admin', type:'felt' }); + c.addStandaloneImport('openzeppelin::upgrades::interface::IUpgradeable'); + c.addStandaloneImport('starknet::ClassHash'); - c.setFunctionBody([ - 'Proxy.assert_only_admin()', - 'Proxy._set_implementation_hash(new_implementation)' - ], functions.upgrade); + const t: BaseImplementedTrait = { + name: 'UpgradeableImpl', + of: 'IUpgradeable', + tags: [ + '#[external(v0)]' + ], + }; + c.addImplementedTrait(t); + requireAccessControl(c, t, functions.upgrade, access, 'UPGRADER', 'upgrader'); } -const modules = defineModules( { - Proxy: { - path: 'openzeppelin.upgrades.library', - useNamespace: true +const components = defineComponents( { + UpgradeableComponent: { + path: 'openzeppelin::upgrades', + substorage: { + name: 'upgradeable', + type: 'UpgradeableComponent::Storage', + }, + event: { + name: 'UpgradeableEvent', + type: 'UpgradeableComponent::Event', + }, + impls: [], + internalImpl: { + name: 'UpgradeableInternalImpl', + value: 'UpgradeableComponent::InternalImpl', + }, }, }); const functions = defineFunctions({ - upgrade: { - kind: 'external', - implicitArgs: withImplicitArgs(), args: [ - { name: 'new_implementation', type: 'felt' }, + getSelfArg(), + { name: 'new_class_hash', type: 'ClassHash' }, ], - returns: [], + code: [ + 'self.upgradeable._upgrade(new_class_hash)' + ] }, - }); diff --git a/packages/core-cairo/src/test.ts b/packages/core-cairo/src/test.ts index 0fef5a08..723fe109 100644 --- a/packages/core-cairo/src/test.ts +++ b/packages/core-cairo/src/test.ts @@ -19,7 +19,7 @@ function isAccessControlRequired(opts: GenericOptions) { test('is access control required', async t => { for (const contract of generateSources('all')) { - const regexOwnable = /(from openzeppelin.access.ownable.library import Ownable)/gm; + const regexOwnable = /(use openzeppelin::access::ownable::OwnableComponent)/gm; if (!contract.options.access) { if (isAccessControlRequired(contract.options)) { diff --git a/packages/core-cairo/src/utils/define-components.ts b/packages/core-cairo/src/utils/define-components.ts new file mode 100644 index 00000000..62ba3ca6 --- /dev/null +++ b/packages/core-cairo/src/utils/define-components.ts @@ -0,0 +1,18 @@ +import type { Component } from '../contract'; + +type ImplicitNameComponent = Omit; + +export function defineComponents( + fns: Record, +): Record; + +export function defineComponents( + modules: Record, +): Record { + return Object.fromEntries( + Object.entries(modules).map(([name, module]) => [ + name, + Object.assign({ name }, module), + ]), + ); +} diff --git a/packages/core-cairo/src/utils/define-modules.ts b/packages/core-cairo/src/utils/define-modules.ts deleted file mode 100644 index ac84d3eb..00000000 --- a/packages/core-cairo/src/utils/define-modules.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Module } from '../contract'; - -type ImplicitNameModule = Omit; - -export function defineModules( - fns: Record, -): Record; - -export function defineModules( - modules: Record, -): Record { - return Object.fromEntries( - Object.entries(modules).map(([name, module]) => [ - name, - Object.assign({ name }, module), - ]), - ); -} diff --git a/packages/core-cairo/src/utils/hash-builtin.ts b/packages/core-cairo/src/utils/hash-builtin.ts deleted file mode 100644 index bced024e..00000000 --- a/packages/core-cairo/src/utils/hash-builtin.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ContractBuilder } from "../contract"; -import { defineModules } from "./define-modules"; - -const modules = defineModules( { - cairo_builtins: { - path: 'starkware.cairo.common.cairo_builtins', - useNamespace: false - }, -}) - -export function importHashBuiltin(c: ContractBuilder) { - c.addModule(modules.cairo_builtins, [], [], false); - c.addModuleFunction(modules.cairo_builtins, 'HashBuiltin'); -} \ No newline at end of file diff --git a/packages/core-cairo/src/utils/imports-map.ts b/packages/core-cairo/src/utils/imports-map.ts deleted file mode 100644 index 8d434afd..00000000 --- a/packages/core-cairo/src/utils/imports-map.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { Contract } from "../contract"; -import { getFunctionName, getImportName } from "./module-prefix"; - -export function getImportsMap(contract: Contract) { - const modulesToParentFunctions = getModulesToParentFunctions(contract); - const modulesToLibraryFunctions = getModulesToLibraryFunctions(contract); - mergeToLibraryFunctions(modulesToParentFunctions, modulesToLibraryFunctions); - return modulesToLibraryFunctions; -} - -function mergeToLibraryFunctions(modulesToParentFunctions: Map>, modulesToLibraryFunctions: Map>) { - modulesToParentFunctions.forEach((value, key) => { - const functionsToMerge = modulesToLibraryFunctions.get(key); - if (functionsToMerge !== undefined) { - functionsToMerge.forEach(fn => { value.add(fn) }); - modulesToLibraryFunctions.set(key, value); - } - }); -} - -function getModulesToLibraryFunctions(contract: Contract) { - const modulesToLibraryFunctions: Map> = new Map(); - for (const parent of contract.libraries) { - if (parent.functions !== undefined) { - modulesToLibraryFunctions.set(convertPathToImport(parent.module.path), new Set(parent.functions)); - } - } - return modulesToLibraryFunctions; -} - -function getModulesToParentFunctions(contract: Contract) { - const functionsToModules: Map = new Map(); - for (const fn of contract.functions) { - if (fn.module !== undefined) { - functionsToModules.set(getImportName(fn), convertPathToImport(fn.module.path)); - } - } - const modulesToFunctions = invertMapToSet(functionsToModules); - return modulesToFunctions; -} - -function convertPathToImport(relativePath: any): string { - return relativePath.split('/').join('.'); -} - -function invertMapToSet(functionsToModules: Map): Map> { - const modulesToFunctions: Map> = new Map(); - for (const [functionName, moduleName] of functionsToModules.entries()) { - const moduleFunctions = modulesToFunctions.get(moduleName); - if (moduleFunctions === undefined) { - modulesToFunctions.set(moduleName, new Set().add(functionName)); - } else { - moduleFunctions.add(functionName); - } - } - return modulesToFunctions; -} \ No newline at end of file diff --git a/packages/core-cairo/src/utils/map-values.ts b/packages/core-cairo/src/utils/map-values.ts deleted file mode 100644 index 56d598de..00000000 --- a/packages/core-cairo/src/utils/map-values.ts +++ /dev/null @@ -1,10 +0,0 @@ -export function mapValues( - obj: Record, - fn: (val: V) => W, -): Record { - const res = {} as Record; - for (const key in obj) { - res[key] = fn(obj[key]); - } - return res; -} diff --git a/packages/core-cairo/src/utils/module-prefix.ts b/packages/core-cairo/src/utils/module-prefix.ts deleted file mode 100644 index d58d09e5..00000000 --- a/packages/core-cairo/src/utils/module-prefix.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { BaseFunction } from "../contract"; - -/** - * If the function's module has a namespace, returns the namespace. - * Otherwise returns the function name itself. - */ -export function getImportName(fn: BaseFunction): string { - if (fn.module?.useNamespace) { - return fn.module.name; - } else { - return getFunctionName(fn); - } -} - -/** - * Returns the function name with either namespace or module prefix based on extensibility pattern. - */ -export function getFunctionName(fn: BaseFunction): string { - const suffix = fn.parentFunctionName ?? fn.name; - let prefix: string; - if (fn.module !== undefined && fn.module.useNamespace) { - prefix = `${fn.module.name}.` - } else { - prefix = ''; - } - return `${prefix}${suffix}`; -} \ No newline at end of file diff --git a/packages/core-cairo/src/utils/uint256.test.ts b/packages/core-cairo/src/utils/uint256.test.ts deleted file mode 100644 index 6bfcf650..00000000 --- a/packages/core-cairo/src/utils/uint256.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import test from 'ava'; -import BN from 'bn.js'; - -import { NumberTooLarge, toUint256 } from './uint256'; - -test('basic', t => { - t.deepEqual(toUint256('1000'), { lowBits: new BN(1000), highBits: new BN(0) }); - t.deepEqual(toUint256('0'), { lowBits: new BN(0), highBits: new BN(0) }); - t.deepEqual(toUint256(''), { lowBits: new BN(0), highBits: new BN(0) }); -}); - -test('max values', t => { - const twoE128minus1 = toUint256('340282366920938463463374607431768211455'); // 2^128-1 - t.is(twoE128minus1.highBits.toString(), '0'); - t.is(twoE128minus1.lowBits.toString(), '340282366920938463463374607431768211455'); - - const twoE128 = toUint256('340282366920938463463374607431768211456'); // 2^128 - t.is(twoE128.highBits.toString(), '1'); - t.is(twoE128.lowBits.toString(), '0'); - - const twoE128plus1 = toUint256('340282366920938463463374607431768211457'); // 2^128+1 - t.is(twoE128plus1.highBits.toString(), '1'); - t.is(twoE128plus1.lowBits.toString(), '1'); - - const maxValue = toUint256('115792089237316195423570985008687907853269984665640564039457584007913129639935'); // 2^256-1 - t.is(maxValue.highBits.toString(), '340282366920938463463374607431768211455'); // 2^128-1 - t.is(maxValue.lowBits.toString(), '340282366920938463463374607431768211455'); // 2^128-1 - - const error = t.throws(() => toUint256('115792089237316195423570985008687907853269984665640564039457584007913129639936')); // 2^256 - t.assert(error instanceof NumberTooLarge); -}); - diff --git a/packages/core-cairo/src/utils/uint256.ts b/packages/core-cairo/src/utils/uint256.ts deleted file mode 100644 index fabfbbc4..00000000 --- a/packages/core-cairo/src/utils/uint256.ts +++ /dev/null @@ -1,36 +0,0 @@ -import BN from "bn.js"; -import type { ContractBuilder } from "../contract"; -import { defineModules } from "./define-modules"; - -/** - * Returns Uint256 components for low and high bits based on a given number in string format. - * @param num Number in string format - * @returns Object with lowBits and highBits - * @throws {NumberTooLarge} if the provided number is larger than 256 bits - */ -export function toUint256(num: string) { - const bignum = new BN(num, 10); - if (bignum.bitLength() > 256) { // 256 bits - throw new NumberTooLarge(); - } else { - const highBits = bignum.shrn(128); - const lowBits = bignum.maskn(128); - return { - lowBits, highBits - } - } -} - -export class NumberTooLarge extends Error {} - -const modules = defineModules( { - uint256: { - path: 'starkware.cairo.common.uint256', - useNamespace: false - }, -}) - -export function importUint256(c: ContractBuilder) { - c.addModule(modules.uint256, [], [], false); - c.addModuleFunction(modules.uint256, 'Uint256'); -} \ No newline at end of file diff --git a/packages/core-cairo/src/utils/version.ts b/packages/core-cairo/src/utils/version.ts index 7ee0475a..d4e0b24b 100644 --- a/packages/core-cairo/src/utils/version.ts +++ b/packages/core-cairo/src/utils/version.ts @@ -1,2 +1,2 @@ -export const contractsVersion = '0.6.0'; +export const contractsVersion = '0.8.0'; export const contractsVersionTag = `v${contractsVersion}`; diff --git a/packages/core/package.json b/packages/core/package.json index fd262d85..9c3bf5bb 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -22,7 +22,7 @@ "devDependencies": { "@openzeppelin/contracts": "^5.0.0", "@openzeppelin/contracts-upgradeable": "^5.0.0", - "@types/node": "^10.17.51", + "@types/node": "^18.0.0", "array.prototype.flat": "^1.2.4", "ava": "^5.0.0", "hardhat": "^2.1.1", diff --git a/packages/ui/package.json b/packages/ui/package.json index 17600a84..d95dc7d9 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -18,6 +18,7 @@ "@types/file-saver": "^2.0.1", "@types/resize-observer-browser": "^0.1.5", "@types/uuid": "^9.0.0", + "@types/node": "^18.0.0", "autoprefixer": "^10.4.2", "path-browserify": "^1.0.1", "postcss": "^8.2.8", diff --git a/packages/ui/src/cairo/App.svelte b/packages/ui/src/cairo/App.svelte index 26dc08dc..6a735050 100644 --- a/packages/ui/src/cairo/App.svelte +++ b/packages/ui/src/cairo/App.svelte @@ -5,7 +5,6 @@ import ERC20Controls from './ERC20Controls.svelte'; import ERC721Controls from './ERC721Controls.svelte'; - import ERC1155Controls from './ERC1155Controls.svelte'; import CustomControls from './CustomControls.svelte'; import CopyIcon from '../icons/CopyIcon.svelte'; import CheckIcon from '../icons/CheckIcon.svelte'; @@ -34,7 +33,7 @@ let allOpts: { [k in Kind]?: Required } = {}; let errors: { [k in Kind]?: OptionsErrorMessages } = {}; - let contract: Contract = new ContractBuilder(); + let contract: Contract = new ContractBuilder('MyToken'); $: opts = allOpts[tab]; @@ -91,9 +90,9 @@ - @@ -136,9 +135,9 @@
-
+
diff --git a/packages/ui/src/cairo/CustomControls.svelte b/packages/ui/src/cairo/CustomControls.svelte index 1c21dbff..ecffe9aa 100644 --- a/packages/ui/src/cairo/CustomControls.svelte +++ b/packages/ui/src/cairo/CustomControls.svelte @@ -5,7 +5,7 @@ import { custom, infoDefaults } from '@openzeppelin/wizard-cairo'; import AccessControlSection from './AccessControlSection.svelte'; - import UpgradeabilitySection from './UpgradeabilitySection.svelte'; + import UpgradeabilityField from './UpgradeabilityField.svelte'; import InfoSection from './InfoSection.svelte'; export const opts: Required = { @@ -17,6 +17,15 @@ $: requireAccessControl = custom.isAccessControlRequired(opts); +
+

Settings

+ + +
+

Features

@@ -29,11 +38,12 @@ Useful for emergency response. + +
+ - - \ No newline at end of file diff --git a/packages/ui/src/cairo/ERC1155Controls.svelte b/packages/ui/src/cairo/ERC1155Controls.svelte deleted file mode 100644 index 802cb0a0..00000000 --- a/packages/ui/src/cairo/ERC1155Controls.svelte +++ /dev/null @@ -1,72 +0,0 @@ - - -
-

Settings

- - -
- -
-

Features

- -
- - - - -
-
- - - - - - diff --git a/packages/ui/src/cairo/ERC20Controls.svelte b/packages/ui/src/cairo/ERC20Controls.svelte index 835260fd..23eaa291 100644 --- a/packages/ui/src/cairo/ERC20Controls.svelte +++ b/packages/ui/src/cairo/ERC20Controls.svelte @@ -5,7 +5,7 @@ import { premintPattern, erc20, infoDefaults } from '@openzeppelin/wizard-cairo'; import AccessControlSection from './AccessControlSection.svelte'; - import UpgradeabilitySection from './UpgradeabilitySection.svelte'; + import UpgradeabilityField from './UpgradeabilityField.svelte'; import InfoSection from './InfoSection.svelte'; import { error } from '../error-tooltip'; @@ -36,13 +36,6 @@ - - + + + + - - diff --git a/packages/ui/src/cairo/ERC721Controls.svelte b/packages/ui/src/cairo/ERC721Controls.svelte index 90aedb63..553452a4 100644 --- a/packages/ui/src/cairo/ERC721Controls.svelte +++ b/packages/ui/src/cairo/ERC721Controls.svelte @@ -5,7 +5,7 @@ import { erc721, infoDefaults } from '@openzeppelin/wizard-cairo'; import AccessControlSection from './AccessControlSection.svelte'; - import UpgradeabilitySection from './UpgradeabilitySection.svelte'; + import UpgradeabilityField from './UpgradeabilityField.svelte'; import InfoSection from './InfoSection.svelte'; export const opts: Required = { @@ -58,11 +58,10 @@ Useful for emergency response. + - - - + \ No newline at end of file diff --git a/packages/ui/src/cairo/UpgradeabilityField.svelte b/packages/ui/src/cairo/UpgradeabilityField.svelte new file mode 100644 index 00000000..5e839007 --- /dev/null +++ b/packages/ui/src/cairo/UpgradeabilityField.svelte @@ -0,0 +1,15 @@ + + + diff --git a/packages/ui/src/cairo/UpgradeabilitySection.svelte b/packages/ui/src/cairo/UpgradeabilitySection.svelte deleted file mode 100644 index 0a073e63..00000000 --- a/packages/ui/src/cairo/UpgradeabilitySection.svelte +++ /dev/null @@ -1,34 +0,0 @@ - - -
-

- - -

- -
- -
-
- diff --git a/packages/ui/src/cairo/highlightjs.ts b/packages/ui/src/cairo/highlightjs.ts index c94c0108..7cff0fef 100644 --- a/packages/ui/src/cairo/highlightjs.ts +++ b/packages/ui/src/cairo/highlightjs.ts @@ -1,7 +1,10 @@ import hljs from 'highlight.js/lib/core'; +import rust from 'highlight.js/lib/languages/rust'; // @ts-ignore -import hljsDefineCairo from 'highlightjs-cairo'; -hljsDefineCairo(hljs); +//import hljsDefineCairo from 'highlightjs-cairo'; +//hljsDefineCairo(hljs); + +hljs.registerLanguage('cairo', rust); export default hljs; diff --git a/packages/ui/src/cairo/inject-hyperlinks.ts b/packages/ui/src/cairo/inject-hyperlinks.ts index b1d0a1c0..5dea15e5 100644 --- a/packages/ui/src/cairo/inject-hyperlinks.ts +++ b/packages/ui/src/cairo/inject-hyperlinks.ts @@ -1,18 +1,23 @@ import { contractsVersionTag } from "@openzeppelin/wizard-cairo/src"; export function injectHyperlinks(code: string) { - const importRegex = /( )(openzeppelin|starkware)([^\s]*)( )/g + const importRegex = /use<\/span> (openzeppelin)::([^\s]*);/g let result = code; let match = importRegex.exec(code); while (match != null) { - const [line, spaceBefore, libraryPrefix, libraryPath, spaceAfter] = match; - if (line !== undefined && spaceBefore !== undefined && libraryPrefix !== undefined && libraryPath !== undefined && spaceAfter !== undefined) { - const libraryRelativePath = libraryPath.replace(/\./g, '/'); - const githubPrefix = (libraryPrefix === 'openzeppelin') ? - `https://github.com/OpenZeppelin/cairo-contracts/blob/${contractsVersionTag}/src/` : - 'https://github.com/starkware-libs/cairo-lang/blob/master/src/'; - const replacedImportLine = `${spaceBefore}${libraryPrefix}${libraryPath}${spaceAfter}`; - result = result.replace(line, replacedImportLine); + const [line, libraryPrefix, libraryPath] = match; + if (line !== undefined && libraryPrefix !== undefined && libraryPath !== undefined) { + const githubPrefix = `https://github.com/OpenZeppelin/cairo-contracts/blob/${contractsVersionTag}/src/`; + + let libraryPathSegments = libraryPath.split('::'); + + // Remove the component name + libraryPathSegments.pop(); + + if (libraryPathSegments !== undefined && libraryPathSegments.length > 0) { + const replacedImportLine = `use<\/span> ${libraryPrefix}::${libraryPath};`; + result = result.replace(line, replacedImportLine); + } } match = importRegex.exec(code); } diff --git a/yarn.lock b/yarn.lock index df880d28..cf4986ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1038,10 +1038,12 @@ dependencies: undici-types "~5.26.4" -"@types/node@^10.17.51": - version "10.17.60" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== +"@types/node@^18.0.0": + version "18.19.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.1.tgz#e3ed7d5ab5ea21f33a4503decb2171e0d8f53070" + integrity sha512-mZJ9V11gG5Vp0Ox2oERpeFDl+JvCwK24PGy76vVY/UgBtjwJWc5rYBThFxmbnYOm9UPZNm6wEl/sxHt2SU7x9A== + dependencies: + undici-types "~5.26.4" "@types/parse-json@^4.0.0": version "4.0.2" From 8bf47767c64ad0e6a32cf6f8a957dd575afd5cd6 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Mon, 4 Dec 2023 18:35:41 -0500 Subject: [PATCH 02/29] Add reimplemented impls WIP --- packages/core-cairo/src/add-pausable.ts | 6 +- packages/core-cairo/src/common-options.ts | 8 +- packages/core-cairo/src/contract.ts | 3 +- packages/core-cairo/src/erc20.ts | 171 ++++++++++++++++++++-- packages/core-cairo/src/erc721.ts | 2 +- 5 files changed, 171 insertions(+), 19 deletions(-) diff --git a/packages/core-cairo/src/add-pausable.ts b/packages/core-cairo/src/add-pausable.ts index 158dbf10..e6f1e0f2 100644 --- a/packages/core-cairo/src/add-pausable.ts +++ b/packages/core-cairo/src/add-pausable.ts @@ -1,5 +1,5 @@ import { getSelfArg } from './common-options'; -import type { ContractBuilder, ContractFunction } from './contract'; +import type { BaseImplementedTrait, ContractBuilder, ContractFunction } from './contract'; import { Access, requireAccessControl } from './set-access-control'; import { defineFunctions } from './utils/define-functions'; import { defineComponents } from './utils/define-components'; @@ -57,6 +57,6 @@ const functions = defineFunctions({ }, }); -export function setPausable(c: ContractBuilder, fn: ContractFunction) { - c.addFunctionCodeBefore(externalTrait, fn, 'self.pausable.assert_not_paused()'); +export function setPausable(c: ContractBuilder, t: BaseImplementedTrait, fn: ContractFunction) { + c.addFunctionCodeBefore(t, fn, 'self.pausable.assert_not_paused()'); } diff --git a/packages/core-cairo/src/common-options.ts b/packages/core-cairo/src/common-options.ts index 7666c250..6961816d 100644 --- a/packages/core-cairo/src/common-options.ts +++ b/packages/core-cairo/src/common-options.ts @@ -24,6 +24,10 @@ export function withCommonDefaults(opts: CommonOptions): Required }; } -export function getSelfArg(): Argument { - return { name: 'ref self', type: 'ContractState' }; +export function getSelfArg(scope: 'external' | 'view' = 'external'): Argument { + if (scope === 'view') { + return { name: 'self', type: '@ContractState' }; + } else { + return { name: 'ref self', type: 'ContractState' }; + } } \ No newline at end of file diff --git a/packages/core-cairo/src/contract.ts b/packages/core-cairo/src/contract.ts index ef5f15e6..a65c8ba7 100644 --- a/packages/core-cairo/src/contract.ts +++ b/packages/core-cairo/src/contract.ts @@ -57,6 +57,7 @@ export interface BaseFunction { name: string; args: Argument[]; code: string[]; + returns?: string; } export interface ContractFunction extends BaseFunction { @@ -162,7 +163,7 @@ export class ContractBuilder implements Contract { addFunction(baseTrait: BaseImplementedTrait, fn: BaseFunction) { const t = this.addImplementedTrait(baseTrait); - + const signature = this.getFunctionSignature(fn); // Look for the existing function with the same signature and return it if found diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 3b38372d..7bd38eb4 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -1,4 +1,4 @@ -import { Contract, ContractBuilder } from './contract'; +import { BaseImplementedTrait, Contract, ContractBuilder } from './contract'; import { Access, requireAccessControl, setAccessControl } from './set-access-control'; import { addPausable, setPausable } from './add-pausable'; import { defineFunctions } from './utils/define-functions'; @@ -60,6 +60,7 @@ export function buildERC20(opts: ERC20Options): Contract { const allOpts = withDefaults(opts); addBase(c, allOpts.name, allOpts.symbol); + addReimplementedImpls(c, allOpts); if (allOpts.premint) { addPremint(c, allOpts.premint); @@ -72,7 +73,7 @@ export function buildERC20(opts: ERC20Options): Contract { if (allOpts.pausable) { addPausable(c, allOpts.access); if (allOpts.burnable) { - setPausable(c, functions.burn); + setPausable(c, externalTrait, functions.burn); } } @@ -91,6 +92,51 @@ export function buildERC20(opts: ERC20Options): Contract { return c; } +function addReimplementedImpls(c: ContractBuilder, allOpts: Required) { + if (allOpts.pausable) { + + // TODO also do this for safeAllowance + + c.addStandaloneImport('starknet::get_caller_address'); + + c.addStandaloneImport('openzeppelin::token::erc20::interface::IERC20'); + const ERC20Impl: BaseImplementedTrait = { + name: 'ERC20Impl', + of: 'IERC20', + tags: [ + '#[external(v0)]' + ], + } + c.addFunction(ERC20Impl, functions.total_supply); + c.addFunction(ERC20Impl, functions.balance_of); + c.addFunction(ERC20Impl, functions.allowance); + setPausable(c, ERC20Impl, functions.transfer); + setPausable(c, ERC20Impl, functions.transfer_from); + setPausable(c, ERC20Impl, functions.approve); + + c.addStandaloneImport('openzeppelin::token::erc20::interface::IERC20CamelOnly'); + const ERC20CamelOnlyImpl: BaseImplementedTrait = { + name: 'ERC20CamelOnlyImpl', + of: 'IERC20CamelOnly', + tags: [ + '#[external(v0)]' + ], + } + c.addFunction(ERC20CamelOnlyImpl, functions.totalSupply); + c.addFunction(ERC20CamelOnlyImpl, functions.balanceOf); + setPausable(c, ERC20CamelOnlyImpl, functions.transferFrom); + } else { + c.addImplToComponent(components.ERC20Component, { + name: 'ERC20Impl', + value: 'ERC20Component::ERC20Impl', + }); + c.addImplToComponent(components.ERC20Component, { + name: 'ERC20CamelOnlyImpl', + value: 'ERC20Component::ERC20CamelOnlyImpl', + }); + } +} + function addBase(c: ContractBuilder, name: string, symbol: string) { c.addComponent( components.ERC20Component, @@ -154,18 +200,10 @@ const components = defineComponents( { type: 'ERC20Component::Event', }, impls: [ - { - name: 'ERC20Impl', - value: 'ERC20Component::ERC20Impl', - }, { name: 'ERC20MetadataImpl', value: 'ERC20Component::ERC20MetadataImpl', - }, - { - name: 'ERC20CamelOnlyImpl', - value: 'ERC20Component::ERC20CamelOnlyImpl', - }, + }, ], internalImpl: { name: 'ERC20InternalImpl', @@ -194,5 +232,114 @@ const functions = defineFunctions({ code: [ 'self.erc20._mint(recipient, amount);' ] - } + }, + + // Re-implements ERC20Impl + + total_supply: { + args: [ + getSelfArg('view') + ], + code: [ + 'self.erc20.total_supply();' + ], + returns : 'u256', + }, + balance_of: { + args: [ + getSelfArg('view'), + { name: 'account', type: 'ContractAddress' }, + ], + code: [ + 'self.erc20.balance_of(account);' + ], + returns : 'u256', + }, + allowance: { + args: [ + getSelfArg('view'), + { name: 'owner', type: 'ContractAddress' }, + { name: 'spender', type: 'ContractAddress' }, + ], + code: [ + 'self.erc20.allowance(owner, spender);' + ], + returns : 'u256', + }, + transfer: { + args: [ + getSelfArg(), + { name: 'recipient', type: 'ContractAddress' }, + { name: 'amount', type: 'u256' }, + ], + code: [ + 'let caller = get_caller_address();', + 'self.erc20.transfer(caller, recipient, amount);', + 'true', + ], + returns : 'bool', + }, + transfer_from: { + args: [ + getSelfArg(), + { name: 'sender', type: 'ContractAddress' }, + { name: 'recipient', type: 'ContractAddress' }, + { name: 'amount', type: 'u256' }, + ], + code: [ + 'let caller = get_caller_address();', + 'self.erc20._spend_allowance(sender, caller, amount);', + 'self.erc20._transfer(sender, recipient, amount);', + 'true', + ], + returns : 'bool', + }, + approve: { + args: [ + getSelfArg(), + { name: 'spender', type: 'ContractAddress' }, + { name: 'amount', type: 'u256' }, + ], + code: [ + 'let caller = get_caller_address();', + 'self.erc20._approve(caller, spender, amount);', + 'true', + ], + returns : 'bool', + }, + + // Re-implements ERC20CamelOnlyImpl + + totalSupply: { + args: [ + getSelfArg('view') + ], + code: [ + 'self.total_supply();' + ], + returns : 'u256', + }, + balanceOf: { + args: [ + getSelfArg('view'), + { name: 'account', type: 'ContractAddress' }, + ], + code: [ + 'self.balance_of(account);' + ], + returns : 'u256', + }, + transferFrom: { + args: [ + getSelfArg(), + { name: 'sender', type: 'ContractAddress' }, + { name: 'recipient', type: 'ContractAddress' }, + { name: 'amount', type: 'u256' }, + ], + code: [ + 'self.transfer_from(sender, recipient, amount);', + ], + returns : 'bool', + }, + }); diff --git a/packages/core-cairo/src/erc721.ts b/packages/core-cairo/src/erc721.ts index 467ed3ba..81074177 100644 --- a/packages/core-cairo/src/erc721.ts +++ b/packages/core-cairo/src/erc721.ts @@ -62,7 +62,7 @@ export function buildERC721(opts: ERC721Options): Contract { if (allOpts.pausable) { addPausable(c, allOpts.access); if (allOpts.burnable) { - setPausable(c, functions.burn); + setPausable(c, externalTrait, functions.burn); } } From 9620830cf350ba37b87e8ea5341d67fc3092db0c Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Mon, 4 Dec 2023 18:40:44 -0500 Subject: [PATCH 03/29] Handle returns WIP --- packages/core-cairo/src/print.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 53a117e8..aca66960 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -148,7 +148,8 @@ function printFunction(fn: ContractFunction) { const body = spaceBetween( withSemicolons(fn.codeBefore?.concat(fn.code) ?? fn.code), ); - return printFunction2(head, args, undefined, undefined, undefined, body); + // TODO if there is a return, do not insert semicolon at the end + return printFunction2(head, args, undefined, fn.returns ? [fn.returns] : undefined, undefined, body); } function printConstructor(contract: Contract): Lines[] { From 41018a162c2da3ce92a998e860f5247ccee333f6 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Mon, 4 Dec 2023 18:51:48 -0500 Subject: [PATCH 04/29] Reimplement safe allowance --- packages/core-cairo/src/erc20.ts | 109 +++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 20 deletions(-) diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 7bd38eb4..6afb455a 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -60,7 +60,11 @@ export function buildERC20(opts: ERC20Options): Contract { const allOpts = withDefaults(opts); addBase(c, allOpts.name, allOpts.symbol); - addReimplementedImpls(c, allOpts); + addERC20ImplAndCamelOnlyImpl(c, allOpts.pausable); + + if (allOpts.safeAllowance) { + addSafeAllowance(c, allOpts.pausable); + } if (allOpts.premint) { addPremint(c, allOpts.premint); @@ -81,10 +85,6 @@ export function buildERC20(opts: ERC20Options): Contract { addMintable(c, allOpts.access); } - if (allOpts.safeAllowance) { - addSafeAllowance(c); - } - setAccessControl(c, allOpts.access); setUpgradeable(c, allOpts.upgradeable, allOpts.access); setInfo(c, allOpts.info); @@ -92,8 +92,8 @@ export function buildERC20(opts: ERC20Options): Contract { return c; } -function addReimplementedImpls(c: ContractBuilder, allOpts: Required) { - if (allOpts.pausable) { +function addERC20ImplAndCamelOnlyImpl(c: ContractBuilder, pausable: boolean) { + if (pausable) { // TODO also do this for safeAllowance @@ -147,19 +147,43 @@ function addBase(c: ContractBuilder, name: string, symbol: string) { ); } -function addSafeAllowance(c: ContractBuilder) { - c.addImplToComponent(components.ERC20Component, - { +function addSafeAllowance(c: ContractBuilder, pausable: boolean) { + if (pausable) { + c.addStandaloneImport('openzeppelin::token::erc20::interface::ISafeAllowance'); + const SafeAllowanceImpl: BaseImplementedTrait = { name: 'SafeAllowanceImpl', - value: 'ERC20Component::SafeAllowanceImpl', - }, - ); - c.addImplToComponent(components.ERC20Component, - { + of: 'ISafeAllowance', + tags: [ + '#[external(v0)]' + ], + } + setPausable(c, SafeAllowanceImpl, functions.increase_allowance); + setPausable(c, SafeAllowanceImpl, functions.decrease_allowance); + + c.addStandaloneImport('openzeppelin::token::erc20::interface::ISafeAllowanceCamel'); + const SafeAllowanceCamelImpl: BaseImplementedTrait = { name: 'SafeAllowanceCamelImpl', - value: 'ERC20Component::SafeAllowanceCamelImpl', - }, - ); + of: 'ISafeAllowanceCamel', + tags: [ + '#[external(v0)]' + ], + } + setPausable(c, SafeAllowanceCamelImpl, functions.increaseAllowance); + setPausable(c, SafeAllowanceCamelImpl, functions.decreaseAllowance); + } else { + c.addImplToComponent(components.ERC20Component, + { + name: 'SafeAllowanceImpl', + value: 'ERC20Component::SafeAllowanceImpl', + }, + ); + c.addImplToComponent(components.ERC20Component, + { + name: 'SafeAllowanceCamelImpl', + value: 'ERC20Component::SafeAllowanceCamelImpl', + }, + ); + } } function addBurnable(c: ContractBuilder) { @@ -235,7 +259,6 @@ const functions = defineFunctions({ }, // Re-implements ERC20Impl - total_supply: { args: [ getSelfArg('view') @@ -309,7 +332,6 @@ const functions = defineFunctions({ }, // Re-implements ERC20CamelOnlyImpl - totalSupply: { args: [ getSelfArg('view') @@ -342,4 +364,51 @@ const functions = defineFunctions({ returns : 'bool', }, + // Re-implements SafeAllowanceImpl + increase_allowance: { + args: [ + getSelfArg(), + { name: 'spender', type: 'ContractAddress' }, + { name: 'added_value', type: 'u256' }, + ], + code: [ + 'self.erc20._increase_allowance(spender, added_value)' + ], + returns : 'bool', + }, + decrease_allowance: { + args: [ + getSelfArg(), + { name: 'spender', type: 'ContractAddress' }, + { name: 'subtracted_value', type: 'u256' }, + ], + code: [ + 'self.erc20._decrease_allowance(spender, subtracted_value)' + ], + returns : 'bool', + }, + + // Re-implements SafeAllowanceCamelImpl + increaseAllowance: { + args: [ + getSelfArg(), + { name: 'spender', type: 'ContractAddress' }, + { name: 'addedValue', type: 'u256' }, + ], + code: [ + 'self.increase_allowance(spender, addedValue)' + ], + returns : 'bool', + }, + decreaseAllowance: { + args: [ + getSelfArg(), + { name: 'spender', type: 'ContractAddress' }, + { name: 'subtractedValue', type: 'u256' }, + ], + code: [ + 'self.decrease_allowance(spender, subtractedValue)' + ], + returns : 'bool', + }, }); From c5f7f905dff1f7a8a8e7d9f497d270d78f4bcac1 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Mon, 4 Dec 2023 22:33:45 -0500 Subject: [PATCH 05/29] Fix function syntax --- packages/core-cairo/src/erc20.ts | 17 +++++++---------- packages/core-cairo/src/print.ts | 23 ++++++++++++++++------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 6afb455a..a12206f1 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -94,9 +94,6 @@ export function buildERC20(opts: ERC20Options): Contract { function addERC20ImplAndCamelOnlyImpl(c: ContractBuilder, pausable: boolean) { if (pausable) { - - // TODO also do this for safeAllowance - c.addStandaloneImport('starknet::get_caller_address'); c.addStandaloneImport('openzeppelin::token::erc20::interface::IERC20'); @@ -264,7 +261,7 @@ const functions = defineFunctions({ getSelfArg('view') ], code: [ - 'self.erc20.total_supply();' + 'self.erc20.total_supply()' ], returns : 'u256', }, @@ -274,7 +271,7 @@ const functions = defineFunctions({ { name: 'account', type: 'ContractAddress' }, ], code: [ - 'self.erc20.balance_of(account);' + 'self.erc20.balance_of(account)' ], returns : 'u256', }, @@ -285,7 +282,7 @@ const functions = defineFunctions({ { name: 'spender', type: 'ContractAddress' }, ], code: [ - 'self.erc20.allowance(owner, spender);' + 'self.erc20.allowance(owner, spender)' ], returns : 'u256', }, @@ -297,7 +294,7 @@ const functions = defineFunctions({ ], code: [ 'let caller = get_caller_address();', - 'self.erc20.transfer(caller, recipient, amount);', + 'self.erc20._transfer(caller, recipient, amount);', 'true', ], returns : 'bool', @@ -337,7 +334,7 @@ const functions = defineFunctions({ getSelfArg('view') ], code: [ - 'self.total_supply();' + 'self.total_supply()' ], returns : 'u256', }, @@ -347,7 +344,7 @@ const functions = defineFunctions({ { name: 'account', type: 'ContractAddress' }, ], code: [ - 'self.balance_of(account);' + 'self.balance_of(account)' ], returns : 'u256', }, @@ -359,7 +356,7 @@ const functions = defineFunctions({ { name: 'amount', type: 'u256' }, ], code: [ - 'self.transfer_from(sender, recipient, amount);', + 'self.transfer_from(sender, recipient, amount)', ], returns : 'bool', }, diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index aca66960..350f81b2 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -145,11 +145,20 @@ function printFunction(fn: ContractFunction) { const head = `fn ${fn.name}`; const args = fn.args.map(a => printArgument(a)); - const body = spaceBetween( - withSemicolons(fn.codeBefore?.concat(fn.code) ?? fn.code), - ); - // TODO if there is a return, do not insert semicolon at the end - return printFunction2(head, args, undefined, fn.returns ? [fn.returns] : undefined, undefined, body); + const codeLines = fn.codeBefore?.concat(fn.code) ?? fn.code; + for (let i = 0; i < codeLines.length; i++) { + const line = codeLines[i]; + const shouldEndWithSemicolon = i < codeLines.length - 1 || fn.returns === undefined; + if (line !== undefined) { + if (shouldEndWithSemicolon && !line.endsWith(';')) { + codeLines[i] += ';'; + } else if (!shouldEndWithSemicolon && line.endsWith(';')) { + codeLines[i] = line.slice(0, line.length - 1); + } + } + } + + return printFunction2(head, args, undefined, fn.returns, undefined, codeLines); } function printConstructor(contract: Contract): Lines[] { @@ -218,7 +227,7 @@ export function printValue(value: Value): string { // generic for functions and constructors // kindedName = 'fn foo' -function printFunction2(kindedName: string, args: string[], tag: string | undefined, returns: string[] | undefined, returnLine: string | undefined, code: Lines[]): Lines[] { +function printFunction2(kindedName: string, args: string[], tag: string | undefined, returns: string | undefined, returnLine: string | undefined, code: Lines[]): Lines[] { const fn = []; if (tag !== undefined) { @@ -243,7 +252,7 @@ function printFunction2(kindedName: string, args: string[], tag: string | undefi if (returns === undefined) { accum += ' {'; } else { - accum += ` -> (${returns.join(', ')}) {`; + accum += ` -> ${returns} {`; } fn.push(accum); From 820d285a2d7fb3120506f7b5f978d8bc9a84b113 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Mon, 4 Dec 2023 22:37:49 -0500 Subject: [PATCH 06/29] Update snapshots --- packages/core-cairo/src/erc20.test.ts.md | 443 +++++++++++++++++++-- packages/core-cairo/src/erc20.test.ts.snap | Bin 1967 -> 2472 bytes 2 files changed, 399 insertions(+), 44 deletions(-) diff --git a/packages/core-cairo/src/erc20.test.ts.md b/packages/core-cairo/src/erc20.test.ts.md index 917e990d..0775f6a6 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -16,11 +16,11 @@ Generated by [AVA](https://avajs.dev). ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ @@ -58,11 +58,11 @@ Generated by [AVA](https://avajs.dev). ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ @@ -107,19 +107,18 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::token::erc20::interface::IERC20;␊ + use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ + use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl PausableImpl = PausableComponent::PausableImpl;␊ #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ @@ -156,6 +155,69 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer('MyToken', 'MTK');␊ self.ownable.initializer(owner);␊ }␊ + ␊ + #[external(v0)]␊ + impl ERC20Impl of IERC20 {␊ + fn total_supply(self: @ContractState) -> u256 {␊ + self.erc20.total_supply()␊ + }␊ + ␊ + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.erc20.balance_of(account)␊ + }␊ + ␊ + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 {␊ + self.erc20.allowance(owner, spender)␊ + }␊ + ␊ + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._transfer(caller, recipient, amount);␊ + true␊ + }␊ + ␊ + fn transfer_from(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._spend_allowance(sender, caller, amount);␊ + self.erc20._transfer(sender, recipient, amount);␊ + true␊ + }␊ + ␊ + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._approve(caller, spender, amount);␊ + true␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + fn totalSupply(self: @ContractState) -> u256 {␊ + self.total_supply()␊ + }␊ + ␊ + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.balance_of(account)␊ + }␊ + ␊ + fn transferFrom(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.transfer_from(sender, recipient, amount)␊ + }␊ + }␊ ␊ #[generate_trait]␊ #[external(v0)]␊ @@ -187,7 +249,10 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::token::erc20::interface::IERC20;␊ + use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ + use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ use super::{PAUSER_ROLE};␊ ␊ @@ -196,13 +261,9 @@ Generated by [AVA](https://avajs.dev). component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl PausableImpl = PausableComponent::PausableImpl;␊ #[abi(embed_v0)]␊ impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ @@ -248,6 +309,69 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊ }␊ + ␊ + #[external(v0)]␊ + impl ERC20Impl of IERC20 {␊ + fn total_supply(self: @ContractState) -> u256 {␊ + self.erc20.total_supply()␊ + }␊ + ␊ + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.erc20.balance_of(account)␊ + }␊ + ␊ + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 {␊ + self.erc20.allowance(owner, spender)␊ + }␊ + ␊ + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._transfer(caller, recipient, amount);␊ + true␊ + }␊ + ␊ + fn transfer_from(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._spend_allowance(sender, caller, amount);␊ + self.erc20._transfer(sender, recipient, amount);␊ + true␊ + }␊ + ␊ + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._approve(caller, spender, amount);␊ + true␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + fn totalSupply(self: @ContractState) -> u256 {␊ + self.total_supply()␊ + }␊ + ␊ + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.balance_of(account)␊ + }␊ + ␊ + fn transferFrom(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.transfer_from(sender, recipient, amount)␊ + }␊ + }␊ ␊ #[generate_trait]␊ #[external(v0)]␊ @@ -276,6 +400,8 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::token::erc20::interface::IERC20;␊ + use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ ␊ @@ -283,13 +409,9 @@ Generated by [AVA](https://avajs.dev). component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl PausableImpl = PausableComponent::PausableImpl;␊ #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ @@ -326,6 +448,69 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer('MyToken', 'MTK');␊ self.ownable.initializer(owner);␊ }␊ + ␊ + #[external(v0)]␊ + impl ERC20Impl of IERC20 {␊ + fn total_supply(self: @ContractState) -> u256 {␊ + self.erc20.total_supply()␊ + }␊ + ␊ + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.erc20.balance_of(account)␊ + }␊ + ␊ + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 {␊ + self.erc20.allowance(owner, spender)␊ + }␊ + ␊ + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._transfer(caller, recipient, amount);␊ + true␊ + }␊ + ␊ + fn transfer_from(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._spend_allowance(sender, caller, amount);␊ + self.erc20._transfer(sender, recipient, amount);␊ + true␊ + }␊ + ␊ + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._approve(caller, spender, amount);␊ + true␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + fn totalSupply(self: @ContractState) -> u256 {␊ + self.total_supply()␊ + }␊ + ␊ + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.balance_of(account)␊ + }␊ + ␊ + fn transferFrom(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.transfer_from(sender, recipient, amount)␊ + }␊ + }␊ ␊ #[generate_trait]␊ #[external(v0)]␊ @@ -362,11 +547,11 @@ Generated by [AVA](https://avajs.dev). ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ @@ -405,11 +590,11 @@ Generated by [AVA](https://avajs.dev). ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ @@ -449,11 +634,11 @@ Generated by [AVA](https://avajs.dev). component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ @@ -518,11 +703,11 @@ Generated by [AVA](https://avajs.dev). component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ #[abi(embed_v0)]␊ impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ @@ -587,11 +772,11 @@ Generated by [AVA](https://avajs.dev). ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl ERC20Impl = ERC20Component::ERC20Impl;␊ + #[abi(embed_v0)]␊ impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ #[abi(embed_v0)]␊ impl SafeAllowanceImpl = ERC20Component::SafeAllowanceImpl;␊ @@ -632,9 +817,13 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::interface::IERC20;␊ + use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ + use openzeppelin::token::erc20::interface::ISafeAllowance;␊ + use openzeppelin::token::erc20::interface::ISafeAllowanceCamel;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ContractAddress;␊ use starknet::get_caller_address;␊ + use starknet::ContractAddress;␊ use starknet::ClassHash;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ @@ -642,17 +831,9 @@ Generated by [AVA](https://avajs.dev). component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ - impl SafeAllowanceImpl = ERC20Component::SafeAllowanceImpl;␊ - #[abi(embed_v0)]␊ - impl SafeAllowanceCamelImpl = ERC20Component::SafeAllowanceCamelImpl;␊ - #[abi(embed_v0)]␊ impl PausableImpl = PausableComponent::PausableImpl;␊ #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ @@ -696,6 +877,95 @@ Generated by [AVA](https://avajs.dev). ␊ self.erc20._mint(recipient, 2000);␊ }␊ + ␊ + #[external(v0)]␊ + impl ERC20Impl of IERC20 {␊ + fn total_supply(self: @ContractState) -> u256 {␊ + self.erc20.total_supply()␊ + }␊ + ␊ + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.erc20.balance_of(account)␊ + }␊ + ␊ + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 {␊ + self.erc20.allowance(owner, spender)␊ + }␊ + ␊ + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._transfer(caller, recipient, amount);␊ + true␊ + }␊ + ␊ + fn transfer_from(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._spend_allowance(sender, caller, amount);␊ + self.erc20._transfer(sender, recipient, amount);␊ + true␊ + }␊ + ␊ + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._approve(caller, spender, amount);␊ + true␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + fn totalSupply(self: @ContractState) -> u256 {␊ + self.total_supply()␊ + }␊ + ␊ + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.balance_of(account)␊ + }␊ + ␊ + fn transferFrom(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.transfer_from(sender, recipient, amount)␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl SafeAllowanceImpl of ISafeAllowance {␊ + fn increase_allowance(ref self: ContractState, spender: ContractAddress, added_value: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.erc20._increase_allowance(spender, added_value)␊ + }␊ + ␊ + fn decrease_allowance(ref self: ContractState, spender: ContractAddress, subtracted_value: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.erc20._decrease_allowance(spender, subtracted_value)␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl SafeAllowanceCamelImpl of ISafeAllowanceCamel {␊ + fn increaseAllowance(ref self: ContractState, spender: ContractAddress, addedValue: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.increase_allowance(spender, addedValue)␊ + }␊ + ␊ + fn decreaseAllowance(ref self: ContractState, spender: ContractAddress, subtractedValue: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.decrease_allowance(spender, subtractedValue)␊ + }␊ + }␊ ␊ #[generate_trait]␊ #[external(v0)]␊ @@ -749,10 +1019,14 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc20::interface::IERC20;␊ + use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ + use openzeppelin::token::erc20::interface::ISafeAllowance;␊ + use openzeppelin::token::erc20::interface::ISafeAllowanceCamel;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::ContractAddress;␊ use starknet::get_caller_address;␊ + use starknet::ContractAddress;␊ use starknet::ClassHash;␊ use super::{PAUSER_ROLE, MINTER_ROLE, UPGRADER_ROLE};␊ ␊ @@ -762,17 +1036,9 @@ Generated by [AVA](https://avajs.dev). component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC20Impl = ERC20Component::ERC20Impl;␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC20CamelOnlyImpl = ERC20Component::ERC20CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ - impl SafeAllowanceImpl = ERC20Component::SafeAllowanceImpl;␊ - #[abi(embed_v0)]␊ - impl SafeAllowanceCamelImpl = ERC20Component::SafeAllowanceCamelImpl;␊ - #[abi(embed_v0)]␊ impl PausableImpl = PausableComponent::PausableImpl;␊ #[abi(embed_v0)]␊ impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ @@ -833,6 +1099,95 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ + ␊ + #[external(v0)]␊ + impl ERC20Impl of IERC20 {␊ + fn total_supply(self: @ContractState) -> u256 {␊ + self.erc20.total_supply()␊ + }␊ + ␊ + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.erc20.balance_of(account)␊ + }␊ + ␊ + fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 {␊ + self.erc20.allowance(owner, spender)␊ + }␊ + ␊ + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._transfer(caller, recipient, amount);␊ + true␊ + }␊ + ␊ + fn transfer_from(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._spend_allowance(sender, caller, amount);␊ + self.erc20._transfer(sender, recipient, amount);␊ + true␊ + }␊ + ␊ + fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._approve(caller, spender, amount);␊ + true␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + fn totalSupply(self: @ContractState) -> u256 {␊ + self.total_supply()␊ + }␊ + ␊ + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.balance_of(account)␊ + }␊ + ␊ + fn transferFrom(␊ + ref self: ContractState,␊ + sender: ContractAddress,␊ + recipient: ContractAddress,␊ + amount: u256,␊ + ) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.transfer_from(sender, recipient, amount)␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl SafeAllowanceImpl of ISafeAllowance {␊ + fn increase_allowance(ref self: ContractState, spender: ContractAddress, added_value: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.erc20._increase_allowance(spender, added_value)␊ + }␊ + ␊ + fn decrease_allowance(ref self: ContractState, spender: ContractAddress, subtracted_value: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.erc20._decrease_allowance(spender, subtracted_value)␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl SafeAllowanceCamelImpl of ISafeAllowanceCamel {␊ + fn increaseAllowance(ref self: ContractState, spender: ContractAddress, addedValue: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.increase_allowance(spender, addedValue)␊ + }␊ + ␊ + fn decreaseAllowance(ref self: ContractState, spender: ContractAddress, subtractedValue: u256) -> bool {␊ + self.pausable.assert_not_paused();␊ + self.decrease_allowance(spender, subtractedValue)␊ + }␊ + }␊ ␊ #[generate_trait]␊ #[external(v0)]␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 983e7c592144a4e7cd12fc7c16fd54e98f9c4a6a..1272a4e20f5c3969881d31eaf5d162328bcd43c0 100644 GIT binary patch literal 2472 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 Date: Tue, 5 Dec 2023 15:12:40 -0500 Subject: [PATCH 07/29] Properly sanitize short strings --- packages/core-cairo/src/print.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 350f81b2..7cafbf7a 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -221,10 +221,30 @@ export function printValue(value: Value): string { throw new Error(`Number not representable (${value})`); } } else { - return `'${value}'`; + return `'${toPrintableShortString(value)}'`; } } +/** + * Converts to a felt252-compatible short string according to the rules in https://docs.cairo-lang.org/language_constructs/literal-expressions.html#short_string_literals + */ +function toPrintableShortString(str: string): string { + let result = ''; + for (let i = 0; i < str.length && i < 31; i++) { + let code = str.charCodeAt(i); + if (code >= 32 && code <= 126) { + if (code === 39) { + result += '\\\''; // escape single quote + } else if (code === 92) { + result += '\\\\'; // escape backslash + } else { + result += str.charAt(i); + } + } + } + return result; +} + // generic for functions and constructors // kindedName = 'fn foo' function printFunction2(kindedName: string, args: string[], tag: string | undefined, returns: string | undefined, returnLine: string | undefined, code: Lines[]): Lines[] { From 1194c622ede2bb87a8318a7d0ca4332a2fe0d286 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Tue, 5 Dec 2023 15:51:05 -0500 Subject: [PATCH 08/29] Improve string handling --- packages/core-cairo/src/print.ts | 21 +----------- .../src/utils/to-identifier.test.ts | 34 ++++++++++++++++--- .../core-cairo/src/utils/to-identifier.ts | 18 ++++++++-- 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 7cafbf7a..3116b2b8 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -1,5 +1,6 @@ import 'array.prototype.flatmap/auto'; +import { toPrintableShortString } from './utils/to-identifier'; import type { Contract, Component, Argument, Value, Impl, ContractFunction, } from './contract'; import { formatLines, spaceBetween, Lines } from './utils/format-lines'; @@ -225,26 +226,6 @@ export function printValue(value: Value): string { } } -/** - * Converts to a felt252-compatible short string according to the rules in https://docs.cairo-lang.org/language_constructs/literal-expressions.html#short_string_literals - */ -function toPrintableShortString(str: string): string { - let result = ''; - for (let i = 0; i < str.length && i < 31; i++) { - let code = str.charCodeAt(i); - if (code >= 32 && code <= 126) { - if (code === 39) { - result += '\\\''; // escape single quote - } else if (code === 92) { - result += '\\\\'; // escape backslash - } else { - result += str.charAt(i); - } - } - } - return result; -} - // generic for functions and constructors // kindedName = 'fn foo' function printFunction2(kindedName: string, args: string[], tag: string | undefined, returns: string | undefined, returnLine: string | undefined, code: Lines[]): Lines[] { diff --git a/packages/core-cairo/src/utils/to-identifier.test.ts b/packages/core-cairo/src/utils/to-identifier.test.ts index 6af3b3a1..52959912 100644 --- a/packages/core-cairo/src/utils/to-identifier.test.ts +++ b/packages/core-cairo/src/utils/to-identifier.test.ts @@ -1,20 +1,44 @@ import test from 'ava'; -import { toIdentifier } from './to-identifier'; +import { toIdentifier, toPrintableShortString } from './to-identifier'; -test('unmodified', t => { +test('toIdentifier - unmodified', t => { t.is(toIdentifier('abc'), 'abc'); }); -test('remove leading specials', t => { +test('toIdentifier - remove leading specials', t => { t.is(toIdentifier('--abc'), 'abc'); }); -test('remove specials and upcase next char', t => { +test('toIdentifier - remove specials and upcase next char', t => { t.is(toIdentifier('abc-def'), 'abcDef'); t.is(toIdentifier('abc--def'), 'abcDef'); }); -test('capitalize', t => { +test('toIdentifier - capitalize', t => { t.is(toIdentifier('abc', true), 'Abc'); }); + +test('toPrintableShortString - unmodified', t => { + t.is(toPrintableShortString('abc'), 'abc'); +}); + +test('toPrintableShortString - remove accents', t => { + t.is(toPrintableShortString('ábc'), 'abc'); +}); + +test('toPrintableShortString - remove non-ascii-printable characters', t => { + t.is(toPrintableShortString('abc😀'), 'abc'); +}); + +test('toPrintableShortString - escape single quote', t => { + t.is(toPrintableShortString("abc'def"), "abc\\'def"); +}); + +test('toPrintableShortString - escape backslash', t => { + t.is(toPrintableShortString('abc\\def'), 'abc\\\\def'); +}); + +test('toPrintableShortString - limit to 31 characters', t => { + t.is(toPrintableShortString('A123456789B123456789C123456789D123456789'), 'A123456789B123456789C123456789D'); +}); \ No newline at end of file diff --git a/packages/core-cairo/src/utils/to-identifier.ts b/packages/core-cairo/src/utils/to-identifier.ts index 2e4a2f9f..e0cceb0a 100644 --- a/packages/core-cairo/src/utils/to-identifier.ts +++ b/packages/core-cairo/src/utils/to-identifier.ts @@ -1,7 +1,21 @@ +/** + * Converts to an identifier according to the rules in https://docs.cairo-lang.org/language_constructs/identifiers.html + */ export function toIdentifier(str: string, capitalize = false): string { return str .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents - .replace(/^[^a-zA-Z$_]+/, '') + .replace(/^[^a-zA-Z_]+/, '') .replace(/^(.)/, c => capitalize ? c.toUpperCase() : c) - .replace(/[^\w$]+(.?)/g, (_, c) => c.toUpperCase()); + .replace(/[^\w]+(.?)/g, (_, c) => c.toUpperCase()); } + +/** + * Converts to a felt252-compatible short string according to the rules in https://docs.cairo-lang.org/language_constructs/literal-expressions.html#short_string_literals + */ +export function toPrintableShortString(str: string): string { + return str + .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents + .replace(/[^\x20-\x7E]+/g, '') // remove non-ascii-printable characters + .replace(/(\\|')/g, (_, c) => '\\' + c) // escape backslash or single quote + .slice(0, 31); // limit to 31 characters +} \ No newline at end of file From f176251dfc76594807c2f8ee3c86cce2940f7c16 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Tue, 5 Dec 2023 15:54:14 -0500 Subject: [PATCH 09/29] Add tests --- packages/core-cairo/src/utils/to-identifier.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/core-cairo/src/utils/to-identifier.test.ts b/packages/core-cairo/src/utils/to-identifier.test.ts index 52959912..95eff53d 100644 --- a/packages/core-cairo/src/utils/to-identifier.test.ts +++ b/packages/core-cairo/src/utils/to-identifier.test.ts @@ -19,6 +19,18 @@ test('toIdentifier - capitalize', t => { t.is(toIdentifier('abc', true), 'Abc'); }); +test('toIdentifier - remove accents', t => { + t.is(toIdentifier('ábc'), 'abc'); +}); + +test('toIdentifier - underscores', t => { + t.is(toIdentifier('_abc_'), '_abc_'); +}); + +test('toIdentifier - remove starting numbers', t => { + t.is(toIdentifier('123abc456'), 'abc456'); +}); + test('toPrintableShortString - unmodified', t => { t.is(toPrintableShortString('abc'), 'abc'); }); From 38432df2c553a4faf1dcb8e64c2c70d072b7d447 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Tue, 5 Dec 2023 15:58:07 -0500 Subject: [PATCH 10/29] Rename file --- packages/core-cairo/src/contract.ts | 2 +- packages/core-cairo/src/print.ts | 2 +- .../src/utils/{to-identifier.test.ts => strings.test.ts} | 2 +- packages/core-cairo/src/utils/{to-identifier.ts => strings.ts} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename packages/core-cairo/src/utils/{to-identifier.test.ts => strings.test.ts} (95%) rename packages/core-cairo/src/utils/{to-identifier.ts => strings.ts} (100%) diff --git a/packages/core-cairo/src/contract.ts b/packages/core-cairo/src/contract.ts index a65c8ba7..a7d484e2 100644 --- a/packages/core-cairo/src/contract.ts +++ b/packages/core-cairo/src/contract.ts @@ -1,4 +1,4 @@ -import { toIdentifier } from './utils/to-identifier'; +import { toIdentifier } from './utils/strings'; export interface Contract { license: string; diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 3116b2b8..2f2ce455 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -1,6 +1,6 @@ import 'array.prototype.flatmap/auto'; -import { toPrintableShortString } from './utils/to-identifier'; +import { toPrintableShortString } from './utils/strings'; import type { Contract, Component, Argument, Value, Impl, ContractFunction, } from './contract'; import { formatLines, spaceBetween, Lines } from './utils/format-lines'; diff --git a/packages/core-cairo/src/utils/to-identifier.test.ts b/packages/core-cairo/src/utils/strings.test.ts similarity index 95% rename from packages/core-cairo/src/utils/to-identifier.test.ts rename to packages/core-cairo/src/utils/strings.test.ts index 95eff53d..4966ccb5 100644 --- a/packages/core-cairo/src/utils/to-identifier.test.ts +++ b/packages/core-cairo/src/utils/strings.test.ts @@ -1,6 +1,6 @@ import test from 'ava'; -import { toIdentifier, toPrintableShortString } from './to-identifier'; +import { toIdentifier, toPrintableShortString } from './strings'; test('toIdentifier - unmodified', t => { t.is(toIdentifier('abc'), 'abc'); diff --git a/packages/core-cairo/src/utils/to-identifier.ts b/packages/core-cairo/src/utils/strings.ts similarity index 100% rename from packages/core-cairo/src/utils/to-identifier.ts rename to packages/core-cairo/src/utils/strings.ts From 4fb644bd7ad6e414ac9f05ef7ef50f3750b04d3d Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Tue, 5 Dec 2023 15:59:20 -0500 Subject: [PATCH 11/29] Rename file --- packages/core-cairo/src/contract.ts | 2 +- packages/core-cairo/src/print.ts | 2 +- .../src/utils/{strings.test.ts => convert-strings.test.ts} | 2 +- .../core-cairo/src/utils/{strings.ts => convert-strings.ts} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename packages/core-cairo/src/utils/{strings.test.ts => convert-strings.test.ts} (95%) rename packages/core-cairo/src/utils/{strings.ts => convert-strings.ts} (100%) diff --git a/packages/core-cairo/src/contract.ts b/packages/core-cairo/src/contract.ts index a7d484e2..a61cf35e 100644 --- a/packages/core-cairo/src/contract.ts +++ b/packages/core-cairo/src/contract.ts @@ -1,4 +1,4 @@ -import { toIdentifier } from './utils/strings'; +import { toIdentifier } from './utils/convert-strings'; export interface Contract { license: string; diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 2f2ce455..c19a9c70 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -1,6 +1,6 @@ import 'array.prototype.flatmap/auto'; -import { toPrintableShortString } from './utils/strings'; +import { toPrintableShortString } from './utils/convert-strings'; import type { Contract, Component, Argument, Value, Impl, ContractFunction, } from './contract'; import { formatLines, spaceBetween, Lines } from './utils/format-lines'; diff --git a/packages/core-cairo/src/utils/strings.test.ts b/packages/core-cairo/src/utils/convert-strings.test.ts similarity index 95% rename from packages/core-cairo/src/utils/strings.test.ts rename to packages/core-cairo/src/utils/convert-strings.test.ts index 4966ccb5..03bb4e68 100644 --- a/packages/core-cairo/src/utils/strings.test.ts +++ b/packages/core-cairo/src/utils/convert-strings.test.ts @@ -1,6 +1,6 @@ import test from 'ava'; -import { toIdentifier, toPrintableShortString } from './strings'; +import { toIdentifier, toPrintableShortString } from './convert-strings'; test('toIdentifier - unmodified', t => { t.is(toIdentifier('abc'), 'abc'); diff --git a/packages/core-cairo/src/utils/strings.ts b/packages/core-cairo/src/utils/convert-strings.ts similarity index 100% rename from packages/core-cairo/src/utils/strings.ts rename to packages/core-cairo/src/utils/convert-strings.ts From 2cac880b18ecfc7a1be2f54841b9ebfa1d43e2be Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Tue, 5 Dec 2023 17:26:24 -0500 Subject: [PATCH 12/29] Reimplement ERC721Impl and CamelOnly --- packages/core-cairo/src/erc721.test.ts.md | 234 ++++++++++++++++++-- packages/core-cairo/src/erc721.test.ts.snap | Bin 1581 -> 1986 bytes packages/core-cairo/src/erc721.ts | 222 ++++++++++++++++++- 3 files changed, 422 insertions(+), 34 deletions(-) diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index c52f942a..a13bf612 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -18,15 +18,15 @@ Generated by [AVA](https://avajs.dev). component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC721Impl = ERC721Component::ERC721Impl;␊ #[abi(embed_v0)]␊ impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ @@ -70,15 +70,15 @@ Generated by [AVA](https://avajs.dev). component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC721Impl = ERC721Component::ERC721Impl;␊ #[abi(embed_v0)]␊ impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ ␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ @@ -129,6 +129,8 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::token::erc721::interface::IERC721;␊ + use openzeppelin::token::erc721::interface::IERC721CamelOnly;␊ use starknet::ContractAddress;␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ @@ -136,13 +138,9 @@ Generated by [AVA](https://avajs.dev). component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC721Impl = ERC721Component::ERC721Impl;␊ #[abi(embed_v0)]␊ impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ @@ -187,6 +185,101 @@ Generated by [AVA](https://avajs.dev). self.erc721.initializer('MyToken', 'MTK');␊ self.ownable.initializer(owner);␊ }␊ + ␊ + #[external(v0)]␊ + impl ERC721Impl of IERC721 {␊ + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.erc721.balance_of(account)␊ + }␊ + ␊ + fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress {␊ + self.erc721.owner_of(token_id)␊ + }␊ + ␊ + fn safe_transfer_from(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.safe_transfer_from(from, to, token_id, data);␊ + }␊ + ␊ + fn transfer_from(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + token_id: u256,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.transfer_from(from, to, token_id);␊ + }␊ + ␊ + fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.approve(to, token_id);␊ + }␊ + ␊ + fn set_approval_for_all(ref self: ContractState, operator: ContractAddress, approved: bool) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.set_approval_for_all(operator, approved);␊ + }␊ + ␊ + fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress {␊ + self.erc721.get_approved(token_id)␊ + }␊ + ␊ + fn is_approved_for_all(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool {␊ + self.erc721.is_approved_for_all(owner, operator)␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl ERC721CamelOnlyImpl of IERC721CamelOnly {␊ + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.balance_of(account)␊ + }␊ + ␊ + fn ownerOf(self: @ContractState, tokenId: u256) -> ContractAddress {␊ + self.owner_of(tokenId)␊ + }␊ + ␊ + fn safeTransferFrom(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + tokenId: u256,␊ + data: Span,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.safe_transfer_from(from, to, tokenId, data);␊ + }␊ + ␊ + fn transferFrom(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + tokenId: u256,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.transfer_from(from, to, tokenId);␊ + }␊ + ␊ + fn setApprovalForAll(ref self: ContractState, operator: ContractAddress, approved: bool) {␊ + self.pausable.assert_not_paused();␊ + self.set_approval_for_all(operator, approved);␊ + }␊ + ␊ + fn getApproved(self: @ContractState, tokenId: u256) -> ContractAddress {␊ + self.get_approved(tokenId)␊ + }␊ + ␊ + fn isApprovedForAll(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool {␊ + self.is_approved_for_all(owner, operator)␊ + }␊ + }␊ ␊ #[generate_trait]␊ #[external(v0)]␊ @@ -221,15 +314,15 @@ Generated by [AVA](https://avajs.dev). component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC721Impl = ERC721Component::ERC721Impl;␊ #[abi(embed_v0)]␊ impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ @@ -305,15 +398,15 @@ Generated by [AVA](https://avajs.dev). component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC721Impl = ERC721Component::ERC721Impl;␊ #[abi(embed_v0)]␊ impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ #[abi(embed_v0)]␊ + impl ERC721Impl = ERC721Component::ERC721Impl;␊ + #[abi(embed_v0)]␊ + impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ + #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ #[abi(embed_v0)]␊ impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ @@ -384,6 +477,8 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ + use openzeppelin::token::erc721::interface::IERC721;␊ + use openzeppelin::token::erc721::interface::IERC721CamelOnly;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ @@ -395,13 +490,9 @@ Generated by [AVA](https://avajs.dev). component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ - #[abi(embed_v0)]␊ - impl ERC721Impl = ERC721Component::ERC721Impl;␊ #[abi(embed_v0)]␊ impl ERC721MetadataImpl = ERC721Component::ERC721MetadataImpl;␊ #[abi(embed_v0)]␊ - impl ERC721CamelOnly = ERC721Component::ERC721CamelOnlyImpl;␊ - #[abi(embed_v0)]␊ impl ERC721MetadataCamelOnly = ERC721Component::ERC721MetadataCamelOnlyImpl;␊ #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ @@ -451,6 +542,101 @@ Generated by [AVA](https://avajs.dev). self.erc721.initializer('MyToken', 'MTK');␊ self.ownable.initializer(owner);␊ }␊ + ␊ + #[external(v0)]␊ + impl ERC721Impl of IERC721 {␊ + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.erc721.balance_of(account)␊ + }␊ + ␊ + fn owner_of(self: @ContractState, token_id: u256) -> ContractAddress {␊ + self.erc721.owner_of(token_id)␊ + }␊ + ␊ + fn safe_transfer_from(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.safe_transfer_from(from, to, token_id, data);␊ + }␊ + ␊ + fn transfer_from(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + token_id: u256,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.transfer_from(from, to, token_id);␊ + }␊ + ␊ + fn approve(ref self: ContractState, to: ContractAddress, token_id: u256) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.approve(to, token_id);␊ + }␊ + ␊ + fn set_approval_for_all(ref self: ContractState, operator: ContractAddress, approved: bool) {␊ + self.pausable.assert_not_paused();␊ + self.erc721.set_approval_for_all(operator, approved);␊ + }␊ + ␊ + fn get_approved(self: @ContractState, token_id: u256) -> ContractAddress {␊ + self.erc721.get_approved(token_id)␊ + }␊ + ␊ + fn is_approved_for_all(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool {␊ + self.erc721.is_approved_for_all(owner, operator)␊ + }␊ + }␊ + ␊ + #[external(v0)]␊ + impl ERC721CamelOnlyImpl of IERC721CamelOnly {␊ + fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ + self.balance_of(account)␊ + }␊ + ␊ + fn ownerOf(self: @ContractState, tokenId: u256) -> ContractAddress {␊ + self.owner_of(tokenId)␊ + }␊ + ␊ + fn safeTransferFrom(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + tokenId: u256,␊ + data: Span,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.safe_transfer_from(from, to, tokenId, data);␊ + }␊ + ␊ + fn transferFrom(␊ + ref self: ContractState,␊ + from: ContractAddress,␊ + to: ContractAddress,␊ + tokenId: u256,␊ + ) {␊ + self.pausable.assert_not_paused();␊ + self.transfer_from(from, to, tokenId);␊ + }␊ + ␊ + fn setApprovalForAll(ref self: ContractState, operator: ContractAddress, approved: bool) {␊ + self.pausable.assert_not_paused();␊ + self.set_approval_for_all(operator, approved);␊ + }␊ + ␊ + fn getApproved(self: @ContractState, tokenId: u256) -> ContractAddress {␊ + self.get_approved(tokenId)␊ + }␊ + ␊ + fn isApprovedForAll(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool {␊ + self.is_approved_for_all(owner, operator)␊ + }␊ + }␊ ␊ #[generate_trait]␊ #[external(v0)]␊ diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index 3a22f3ee281f4e344751386051885ebd93bde108..e74af52918dddc1beb117c73a6867b7f6024337f 100644 GIT binary patch literal 1986 zcmV;z2R-;fRzVe zE_NsiftIO6h%5>eovtl%F$~yybPuyP*qiJDMoJ__N|by|YCG~pV$=M;|G=OBfnxH} z?}f-aN&fm9l7NH|_COMNK@x#DIYuP;<72-M2>A8d`>R*3UtzD$u3h=^^OI{2A6kbm zcYeA5Jn&$Y!26v(j7Z=I5Ifdhr@OXx?{z`|K8YZ491leV1CP8}8=$_m_pXahU}Sw* zv*>G>Knuk%dJp3mhC$>wgnjEc5PRQme(N~92ix@bHX6hzqC6f|Pz96)N@D1d0MU;L z_O=}7@L+pOp-f3V@%fG&19I$G1qLlEAqayb=vbKuEeoE~aWQe1eb{(p#?lxnNK71w z!zKxo6z1M*&&CPMmU4;BTE^x zG4!njhQ4EI>$Ras&%S<;nf*Z!1tb7r@E&4&okzv>mbJdu{b`*Cn6tIBH6EIedqe6D zy%3h8^YyD*bpG#)rHsykGMDTK64wJ^2(b(LeGHSNiQ!EQZ(?{8!yFucDIL7Fd?k^Ow4KW*3Vj+e0FQ8)1*$BKyQcx^3HLD{*LpKzZ*#mJdduo z7o4LJfp4b3JC&asefS!t1$kMbls zLxC$vxDRMFDYs%JTvhYt-6XAgc_mQTe1-BCgdp;ui+nrN^~Zv;w6sA(X4I0p_n)Li zaiJzwRad|{%!X2Ts$!%{Rtr%q!zt^6I5kp8Y+3zQ2$29kZ7rh2rvyGm16u>FatLh_ zBP$t8pF+^c397pKcPw?&?G=OQu@6JCxwZKupHOU2QZtAE^&sm%+z1hujlq7gK~b${ zFb4a<)*@ezRw|CxO{fN4WLwVBRHLj^X&>JC)wQ2x?MC#ZGw3128B6wrw!0Yt2wk7H zuC!;Z37Ii#+)+7dwuBL=Iz5EKd3vx(LLo@bw^G9+Nl*ElLtN7EN5v-foIvPemdTu* zYL*}so7uibRulV_QI4xhuE;+kSLvm5p0wonIN57|uE}e{tX0W8UDD2kzM&_pPHnF0 z^0@Q#6Gzw1r%6 zgCHX2qxT#CYDe$?+*qNb_X$qVSKtV{IdE)LdR*RAGfoQ(}L{mK5f5x-gVnM)IO1=O5_Bb)uKu!Cpim0DpEhLYfdDq3Az9kNQ`%TnFyQMu9_D_`lB zLu<7$=34dkp$~>3O>neCF`P&a(wm3pQWa}UuThGuQZdy%!XP3pE2Qjl8rM~-XR0D8 znOvydl;_qI<+*NRwMZ}8d11?Se;9_=Fs9zohvxIz+h1wr`pw%bbYA;uu1a%rvn%hp z;TP+Ib(O#>u_FAqf3a1bRo!;vQ$o74o`K|edAg28y4-DqGdZ3DsRRTGtB^DeQFCv6 ziO$&<^4_>aQ}$H>(X>e~Prr20x6$iSl!$1Ko|m9=yU4rkCh}qis#=Iudsfn1k#DZZ zH&^6mv1M~bzNANUMZUQrUm)9|4K8V->k+zu~CiJ z{C$B*nALlbxHR|t>O+Ehlqo7aWvsTk;|FZjp(28BU5`Bqa*siBOurV7h2~&U<#dnw UAD2XDXnczLKh%~s=`>dW0P~y3!T%HI00000000B+THS8jHWbcQWJTSZ?hV-XA`0dvTYzi;(-jCD4-J+yMdAS4 zia?+xDiI<}0!5`uid+l>_8#5C><#t=dxK#QFjArcNrTvyZmb`k?;L(SJp3f{ zqcijZ>ooe~PfT6vVLU{UYq^n+!ssNR(QhAZ8&UN0;>Cl7hYS4pY;obs&rcUuSHZ#C zt)E`(xEA&!{9@b2K6M=z69{&<2c6FIcM(P8)W;M;EAS~n7Cq{W0vqg}4}w$dgAX0R zjyS>~2(f>G!w`F}4c^HC8Tj5kw)js2i}$h*;|o z9_;tlCCkLr%C4UpA)+S`lpJ(HL<543F$8G{U4YNn{j6c1Uo3Cvu@r|A5)UWG;f*qs z1m^iWG;|F-8e-c#`+E5(x#^BVPq^IXr{9+Y&8Xo|U-ksW2NY5KYGW+eT}%-l-DY^X z)kJQ3XoS5z-#f4OkvF+YY zumd9OIS?r0wJb%?AFrgeueiQTUF5kJm>5f=;wiLY{|-iENwTC~9kXTf^HL-q!Hxs^P-*G4?TGSSEvY za}M#ZX^t4BDIsoyz{$@C+)fIFh0Yg+x|q8lDb}WILlCd6e=GNaA0DP4Ew3zhtF_h; z@n;8$B21_u_uh0P6NMoO&e-e8mJzmM;?i>nv;IT)R-9dFj4X?dH-v2X zQp>&cq;YZ1Qf>1dugqGM3M~>+MqZAVHEu*K(N8$m*|>+u zf9YV4uC1@V(iz9Zg+MeYp5KB*%RYP-JmkG9zN~hWFdNM=HScim_<^qg z2|OHWzN!AM2ta!EH`OGm+3A}>f8X5S+v(^0v3kj3$2{Gi8qcH_&$!B%KH-@DCb0${ zgqz7_FTI=;WUK$f=Hbr3+}vXPB;<^xLh~kZ$OZy_kjTB99*wGJP=Zs)%5fF5R<*XO zRR&a&Lm=z(tTcmf>MLR4Iu3J#J5sc2Z&k>;fagWss#Up`j+s}w)zVr|#;vMe8#^fW z*aF8SN>$|nE?hp5DprPGvCLMLnx^J4K|VFPkTR;vxZ0&=r!tbXl4sp+y_M@u?0Fy#S$5c1|GoCfzlvP{=gACxuf3}+5UQb|n{Q<)h`)waGGiTNF_+sC z!noTZtF7v_f6>Ha>HQi-C(|SS@6)CYEu3!jB}i#j=CG1U`&QDvm9+ao=663xjwaQF z5~8la%+CwgUGFk!Mv~Z#{c?*n6i!RGQ5sB(h`*q}hW*M)V', + tags: [ + '#[external(v0)]' + ], + } + c.addFunction(ERC721Impl, functions.balance_of); + c.addFunction(ERC721Impl, functions.owner_of); + setPausable(c, ERC721Impl, functions.safe_transfer_from); + setPausable(c, ERC721Impl, functions.transfer_from); + setPausable(c, ERC721Impl, functions.approve); + setPausable(c, ERC721Impl, functions.set_approval_for_all); + c.addFunction(ERC721Impl, functions.get_approved); + c.addFunction(ERC721Impl, functions.is_approved_for_all); + + c.addStandaloneImport('openzeppelin::token::erc721::interface::IERC721CamelOnly'); + const ERC721CamelOnlyImpl: BaseImplementedTrait = { + name: 'ERC721CamelOnlyImpl', + of: 'IERC721CamelOnly', + tags: [ + '#[external(v0)]' + ], + } + c.addFunction(ERC721CamelOnlyImpl, functions.balanceOf); + c.addFunction(ERC721CamelOnlyImpl, functions.ownerOf); + setPausable(c, ERC721CamelOnlyImpl, functions.safeTransferFrom); + setPausable(c, ERC721CamelOnlyImpl, functions.transferFrom); + setPausable(c, ERC721CamelOnlyImpl, functions.setApprovalForAll); + c.addFunction(ERC721CamelOnlyImpl, functions.getApproved); + c.addFunction(ERC721CamelOnlyImpl, functions.isApprovedForAll); + } else { + c.addImplToComponent(components.ERC721Component, { + name: 'ERC721Impl', + value: 'ERC721Component::ERC721Impl', + }); + c.addImplToComponent(components.ERC721Component, { + name: 'ERC721CamelOnly', + value: 'ERC721Component::ERC721CamelOnlyImpl', + }); + } +} + function addBase(c: ContractBuilder, name: string, symbol: string) { c.addComponent( components.ERC721Component, @@ -110,18 +157,10 @@ const components = defineComponents( { type: 'ERC721Component::Event', }, impls: [ - { - name: 'ERC721Impl', - value: 'ERC721Component::ERC721Impl', - }, { name: 'ERC721MetadataImpl', value: 'ERC721Component::ERC721MetadataImpl', }, - { - name: 'ERC721CamelOnly', - value: 'ERC721Component::ERC721CamelOnlyImpl', - }, { name: 'ERC721MetadataCamelOnly', value: 'ERC721Component::ERC721MetadataCamelOnlyImpl', @@ -158,5 +197,168 @@ const functions = defineFunctions({ 'self.erc721._safe_mint(recipient, token_id, data);', 'self.erc721._set_token_uri(token_id, token_uri);', ] - } + }, + + // Re-implements ERC721Impl + balance_of: { + args: [ + getSelfArg('view'), + { name: 'account', type: 'ContractAddress' }, + ], + returns: 'u256', + code: [ + 'self.erc721.balance_of(account)' + ] + }, + owner_of: { + args: [ + getSelfArg('view'), + { name: 'token_id', type: 'u256' }, + ], + returns: 'ContractAddress', + code: [ + 'self.erc721.owner_of(token_id)' + ] + }, + safe_transfer_from: { + args: [ + getSelfArg(), + { name: 'from', type: 'ContractAddress' }, + { name: 'to', type: 'ContractAddress' }, + { name: 'token_id', type: 'u256' }, + { name: 'data', type: 'Span' }, + ], + code: [ + 'self.erc721.safe_transfer_from(from, to, token_id, data)' + ] + }, + transfer_from: { + args: [ + getSelfArg(), + { name: 'from', type: 'ContractAddress' }, + { name: 'to', type: 'ContractAddress' }, + { name: 'token_id', type: 'u256' }, + ], + code: [ + 'self.erc721.transfer_from(from, to, token_id)' + ] + }, + approve: { + args: [ + getSelfArg(), + { name: 'to', type: 'ContractAddress' }, + { name: 'token_id', type: 'u256' }, + ], + code: [ + 'self.erc721.approve(to, token_id)' + ] + }, + set_approval_for_all: { + args: [ + getSelfArg(), + { name: 'operator', type: 'ContractAddress' }, + { name: 'approved', type: 'bool' }, + ], + code: [ + 'self.erc721.set_approval_for_all(operator, approved)' + ] + }, + get_approved: { + args: [ + getSelfArg('view'), + { name: 'token_id', type: 'u256' }, + ], + returns: 'ContractAddress', + code: [ + 'self.erc721.get_approved(token_id)' + ] + }, + is_approved_for_all: { + args: [ + getSelfArg('view'), + { name: 'owner', type: 'ContractAddress' }, + { name: 'operator', type: 'ContractAddress' }, + ], + returns: 'bool', + code: [ + 'self.erc721.is_approved_for_all(owner, operator)' + ] + }, + + // Re-implements ERC721CamelOnlyImpl + + balanceOf: { + args: [ + getSelfArg('view'), + { name: 'account', type: 'ContractAddress' }, + ], + returns: 'u256', + code: [ + 'self.balance_of(account)' + ] + }, + ownerOf: { + args: [ + getSelfArg('view'), + { name: 'tokenId', type: 'u256' }, + ], + returns: 'ContractAddress', + code: [ + 'self.owner_of(tokenId)' + ] + }, + safeTransferFrom: { + args: [ + getSelfArg(), + { name: 'from', type: 'ContractAddress' }, + { name: 'to', type: 'ContractAddress' }, + { name: 'tokenId', type: 'u256' }, + { name: 'data', type: 'Span' }, + ], + code: [ + 'self.safe_transfer_from(from, to, tokenId, data)' + ] + }, + transferFrom: { + args: [ + getSelfArg(), + { name: 'from', type: 'ContractAddress' }, + { name: 'to', type: 'ContractAddress' }, + { name: 'tokenId', type: 'u256' }, + ], + code: [ + 'self.transfer_from(from, to, tokenId)' + ] + }, + setApprovalForAll: { + args: [ + getSelfArg(), + { name: 'operator', type: 'ContractAddress' }, + { name: 'approved', type: 'bool' }, + ], + code: [ + 'self.set_approval_for_all(operator, approved)' + ] + }, + getApproved: { + args: [ + getSelfArg('view'), + { name: 'tokenId', type: 'u256' }, + ], + returns: 'ContractAddress', + code: [ + 'self.get_approved(tokenId)' + ] + }, + isApprovedForAll: { + args: [ + getSelfArg('view'), + { name: 'owner', type: 'ContractAddress' }, + { name: 'operator', type: 'ContractAddress' }, + ], + returns: 'bool', + code: [ + 'self.is_approved_for_all(owner, operator)' + ] + }, }); From 51ada359bb6ff1a6381c0aff8aff2ccfb95a0fb3 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Tue, 5 Dec 2023 17:31:30 -0500 Subject: [PATCH 13/29] Simplify reimplementing ERC20 impls --- packages/core-cairo/src/erc20.test.ts.md | 79 ++++++--------------- packages/core-cairo/src/erc20.test.ts.snap | Bin 2472 -> 2413 bytes packages/core-cairo/src/erc20.ts | 19 ++--- 3 files changed, 26 insertions(+), 72 deletions(-) diff --git a/packages/core-cairo/src/erc20.test.ts.md b/packages/core-cairo/src/erc20.test.ts.md index 0775f6a6..97717107 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -109,7 +109,6 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::token::erc20::interface::IERC20;␊ use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ - use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ @@ -172,9 +171,7 @@ Generated by [AVA](https://avajs.dev). ␊ fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._transfer(caller, recipient, amount);␊ - true␊ + self.erc20.transfer(recipient, amount)␊ }␊ ␊ fn transfer_from(␊ @@ -184,17 +181,12 @@ Generated by [AVA](https://avajs.dev). amount: u256,␊ ) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._spend_allowance(sender, caller, amount);␊ - self.erc20._transfer(sender, recipient, amount);␊ - true␊ + self.erc20.transfer_from(sender, recipient, amount)␊ }␊ ␊ fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._approve(caller, spender, amount);␊ - true␊ + self.erc20.approve(spender, amount)␊ }␊ }␊ ␊ @@ -252,7 +244,6 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::interface::IERC20;␊ use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ - use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ use super::{PAUSER_ROLE};␊ ␊ @@ -326,9 +317,7 @@ Generated by [AVA](https://avajs.dev). ␊ fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._transfer(caller, recipient, amount);␊ - true␊ + self.erc20.transfer(recipient, amount)␊ }␊ ␊ fn transfer_from(␊ @@ -338,17 +327,12 @@ Generated by [AVA](https://avajs.dev). amount: u256,␊ ) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._spend_allowance(sender, caller, amount);␊ - self.erc20._transfer(sender, recipient, amount);␊ - true␊ + self.erc20.transfer_from(sender, recipient, amount)␊ }␊ ␊ fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._approve(caller, spender, amount);␊ - true␊ + self.erc20.approve(spender, amount)␊ }␊ }␊ ␊ @@ -465,9 +449,7 @@ Generated by [AVA](https://avajs.dev). ␊ fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._transfer(caller, recipient, amount);␊ - true␊ + self.erc20.transfer(recipient, amount)␊ }␊ ␊ fn transfer_from(␊ @@ -477,17 +459,12 @@ Generated by [AVA](https://avajs.dev). amount: u256,␊ ) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._spend_allowance(sender, caller, amount);␊ - self.erc20._transfer(sender, recipient, amount);␊ - true␊ + self.erc20.transfer_from(sender, recipient, amount)␊ }␊ ␊ fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._approve(caller, spender, amount);␊ - true␊ + self.erc20.approve(spender, amount)␊ }␊ }␊ ␊ @@ -822,8 +799,8 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::interface::ISafeAllowance;␊ use openzeppelin::token::erc20::interface::ISafeAllowanceCamel;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ + use starknet::get_caller_address;␊ use starknet::ClassHash;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ @@ -894,9 +871,7 @@ Generated by [AVA](https://avajs.dev). ␊ fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._transfer(caller, recipient, amount);␊ - true␊ + self.erc20.transfer(recipient, amount)␊ }␊ ␊ fn transfer_from(␊ @@ -906,17 +881,12 @@ Generated by [AVA](https://avajs.dev). amount: u256,␊ ) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._spend_allowance(sender, caller, amount);␊ - self.erc20._transfer(sender, recipient, amount);␊ - true␊ + self.erc20.transfer_from(sender, recipient, amount)␊ }␊ ␊ fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._approve(caller, spender, amount);␊ - true␊ + self.erc20.approve(spender, amount)␊ }␊ }␊ ␊ @@ -945,12 +915,12 @@ Generated by [AVA](https://avajs.dev). impl SafeAllowanceImpl of ISafeAllowance {␊ fn increase_allowance(ref self: ContractState, spender: ContractAddress, added_value: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - self.erc20._increase_allowance(spender, added_value)␊ + self.erc20.increase_allowance(spender, added_value)␊ }␊ ␊ fn decrease_allowance(ref self: ContractState, spender: ContractAddress, subtracted_value: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - self.erc20._decrease_allowance(spender, subtracted_value)␊ + self.erc20.decrease_allowance(spender, subtracted_value)␊ }␊ }␊ ␊ @@ -1025,8 +995,8 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::interface::ISafeAllowanceCamel;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ + use starknet::get_caller_address;␊ use starknet::ClassHash;␊ use super::{PAUSER_ROLE, MINTER_ROLE, UPGRADER_ROLE};␊ ␊ @@ -1116,9 +1086,7 @@ Generated by [AVA](https://avajs.dev). ␊ fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._transfer(caller, recipient, amount);␊ - true␊ + self.erc20.transfer(recipient, amount)␊ }␊ ␊ fn transfer_from(␊ @@ -1128,17 +1096,12 @@ Generated by [AVA](https://avajs.dev). amount: u256,␊ ) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._spend_allowance(sender, caller, amount);␊ - self.erc20._transfer(sender, recipient, amount);␊ - true␊ + self.erc20.transfer_from(sender, recipient, amount)␊ }␊ ␊ fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._approve(caller, spender, amount);␊ - true␊ + self.erc20.approve(spender, amount)␊ }␊ }␊ ␊ @@ -1167,12 +1130,12 @@ Generated by [AVA](https://avajs.dev). impl SafeAllowanceImpl of ISafeAllowance {␊ fn increase_allowance(ref self: ContractState, spender: ContractAddress, added_value: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - self.erc20._increase_allowance(spender, added_value)␊ + self.erc20.increase_allowance(spender, added_value)␊ }␊ ␊ fn decrease_allowance(ref self: ContractState, spender: ContractAddress, subtracted_value: u256) -> bool {␊ self.pausable.assert_not_paused();␊ - self.erc20._decrease_allowance(spender, subtracted_value)␊ + self.erc20.decrease_allowance(spender, subtracted_value)␊ }␊ }␊ ␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 1272a4e20f5c3969881d31eaf5d162328bcd43c0..3e5b67323019adbfc59461d6650779e95eef6678 100644 GIT binary patch literal 2413 zcmV-z36l0fRzV5@eHC86vSRsjO2u!Djtw zrx@Ot#~+Ib00000000B+9m#IoHZ*P01{k0~f}n>0MIa{!kAX?z8g&nH8+2ehte83sZ--4%sG|P!@XV6yOHx&E{e5g1swBJG3g_dcnDk67PHKasUw+}YgRyUoV>)05>MkAc0$G?}F zEvvAYlf zB7hxo<@*#GN*p`pyG_dKAp!_K+o*!02==frH$e|td$x611e_a`!IGxZM$of?l>?By zEe1stB3zV+Rv&qRj+Ddb8dU~5F6hvq&4e}bi8LaEnu2JBdX{xGoVMjCf zqA#Trc}h*PmAgR40CqyEhn$v}7m;a?m8U&^yDkKj5h4RC7IgwH9$W}9EnEg5U4R50 z9a^J{8fiIVEa2JmmE0mWyI)CtOyrJTQTPtHFz9#e>T-T$l5= z7(!yyL;@KAPHf=>f~cQ2Aezcq7@;&u0I()SB!)41BP}9savr8^_V8XxGJ~!oHz!1v zc4zV&m&AX@o=bGv|40$GHlSr;U?d z{+KX|U&IH)O|gyQJ(k2+C6~*s*5QywYY=m_H&$y^-A=_C^n4+9%@F&A)3ZrD+K1#; z2}dMc#78&f*}+Pzg(hFfb0VThFiq|uo+Tu(r$PiLzbrRf+`# zJa@n1LTq2$l?6PrDc}*+W@bmpGN1X4DakS)S>_|ld}NuAEc1~83K^iFpLu-Lk^u@u z1}J2JVh#cnLwE2DD1gZ|{EQZES&*V7ht@24uty&14MErEms}X-^E!2XPB3OrgGX}N z@+n(B2Xugkdjb+xO0dZF@w&b88`n-whM<5?c}>~WY5f8c`LFZ zXG*To{5H_Y#+P~STL~lgi_o{ioT4$;*WAG@shnjP9;?HNB7f5dUDz)P5u|>8<6O<& z>{356Zd(gi2SNJhE5*!hg?27CS=vjVrqt-Tmz@=h)LD^0W0WxkQKZ@R@jQwlOuJvB7z$$q z#0H~|UX^I-G`l}U)6#}P`ZAQt_vux;)s2O*)P|HkP_aN}0);Hn9Y)Qi)4?1l3%DDHXfYAOH?W50AHUo}> zPwX&<7beZDfZBxFGz}wZOg|8uQJe5qCEaO{tU9kIBg|5rc~wPaMq;nOS`*^2nyO?N zpH0meI81{T~n7Tg4N(G4dVn1C@Eo zbl70&up!D~Yno3>Zf0MM-%_~BB5r@lm*$V709Xh`X82_JZ;i@-YyUoeq2DJ{i*+b= zE}k#bl=1Ir*ItVzPBPb-ASsOuR|)tQ*L`yvr!c^rQy|_-D`?)3=~j}L=UsE4PWzuF zRG6G!v0h;^=ZChEMUu&9nS7SX=enoSWb#>&$!D2-mdR(Ce3r>)nS7SXXPJDK|I|iE f+}yMm7w?D~C96xs!aaA7GkyI(le?cxLzMskO2&@E literal 2472 zcmV;Z30L+(RzV;#7{@`38Izz5#b6TlPw}{Ad4py;z3<;z0kG_qwh^_2u=yu3x)(4SzoP z=-RCh|G56>k#xAf_2a{*rUq;uJlxTN4Nb!Yo-FO|9JN{xUinbN~o$dvWBP0$Y05lF%pcf#kTrehXX|Sf(w@5Z{&MkP}(nKGf}Pm9JC75a#GMUu}}99zqp@#~W3~D55`5wAY<0u4%s(KVtBq+QS>P20)T@F&uU%+Q2HCv0~a4;HTYYw|@0 zo_Pk^Tb|=$-H7!v(uAlHu!Fu7USN1JEENto80b%yjqq}c38eVZJRL70V%QROt?dCr z@_}W@5+kx@iUoXoC7k(+X`9egE%Pn#+DpWWmO9eX?$P&4%Nu0m%N8+cJM1L&0<xzOZ~@`9+pbMn1-tk4Pzqs+q_E zyopw+ol+TcS#pfz|0CRw;sbGxok$+b9qCN90%UN(+WMC?|M+78C`ERRG$(7+ZNfZf z%1St9)SL`KHNMR8cCH%ud~bK_C&t_TaBJq?j_u-$9D_SdM?yQg6X2!G2(^>}iZ-E=#|7GjopanahY9|=BAYDZaQX*hx{!6)n?_7W3fF>;)d` zmO^Veo^(fw<$RgOpea zH$m>46A?v%X*1vl%}8L^$4Wd_5fby}Qx=Mm&P{kCd5#7AEGl#7gh6Fq-YG?8!hlrT z?>;}=K2Q$!o^H#M0W7$-zJ?qbVi(|0^sYef4Zm(iUrULY zxEXTI8Z;fukf*Jqho6JZ_2ytgm1e!Q{iOT+>5A+9} z3+ucudcDL&<5X9HZw1sNhhuoedk<85IvoQ=(#mc-8`a6zHQs z9|ig-(8v0vD$qxPKGN+3`dAI}V*?x-_)AAQwWE=fVyy}~dCs1SEjTcCdxe1}@7@*% z#>9a!abQdw7!wD^t{&JW4vdKdV*;`fkWI6mbp>Qov%m#pBOn_A+03=|Hx{xPxrVMj zLoF$}8xMe5kmGL-IsN8=K887TPTln<46yWZlj^Rgh@vzAq!2~dqUd_aM}pCwNqJoq z><`-19`yO@>T3398$8B;;5|kB9EyR( z)K#u+3X%IosBNNl(RkK#9$=Q7C8j1k(SQ?1@usgDU~ou=llu9Y2{rq(OZ^Dkwh^Jo zAySxbtS>o(WZH}~1|5PF4wN5yOfXWYaX)Xw?%4<=`YiHQMqpV|;G*3?2Yf{Ov;P=x z_3vj5L!@U@0YOBDx;`HWuQ_!SRr@o>K4$ljjdFR>{VCZ^mFFq#-u@w(Po z55w!8_MCartmzojj8auR+L@>8HToP>3BDl8b3}PgW9k}2c}~p&7v(vkJV%u0%(eAT zq&z1_&$3`DRx{>mp_ZAp<^k0Ql!qC`xOE*r`qA|~lam}VSq`TIs~wD=r)@fz#6;0E zM0jE9v*oax%r?!$SUNKR$1{o(-m0WM-LaMD#dM@usx&XE=*(Et8?4rp=2%TtG81Jq zMHK&u;y(^6+~Pl)nYleSS*+nS>=wI5>RO>sBydu`RBUjrXc(ebPE`K{-Hze<35bEh zve4=gPS^np&ye2Z=gA7slHUEDNtyk6cUtc=81V>d)b08Hw+G#=;*Lxk@dkyVj=qW% z;czL!5snHsG{>0S%)U^fBQd9~82b`0o0!C*Xf73z^%O^<8+0VP@$a$V#(g5)+Jpn( z#r;L Date: Tue, 5 Dec 2023 17:58:32 -0500 Subject: [PATCH 14/29] Update hover text and links --- packages/ui/src/HelpTooltip.svelte | 2 +- packages/ui/src/cairo/AccessControlSection.svelte | 4 ++-- packages/ui/src/cairo/CustomControls.svelte | 2 +- packages/ui/src/cairo/ERC20Controls.svelte | 8 ++++---- packages/ui/src/cairo/ERC721Controls.svelte | 6 +++--- packages/ui/src/cairo/UpgradeabilityField.svelte | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/ui/src/HelpTooltip.svelte b/packages/ui/src/HelpTooltip.svelte index 12f28ee7..064d8efd 100644 --- a/packages/ui/src/HelpTooltip.svelte +++ b/packages/ui/src/HelpTooltip.svelte @@ -6,7 +6,7 @@ export let placement: 'top' | 'bottom' | 'left' | 'right' = 'right'; - + assert_not_paused. + Privileged accounts will be able to pause the functionality marked with self.pausable.assert_not_paused(). Useful for emergency response. diff --git a/packages/ui/src/cairo/ERC20Controls.svelte b/packages/ui/src/cairo/ERC20Controls.svelte index 23eaa291..5ef1fbcc 100644 --- a/packages/ui/src/cairo/ERC20Controls.svelte +++ b/packages/ui/src/cairo/ERC20Controls.svelte @@ -52,7 +52,7 @@ @@ -69,7 +69,7 @@ Pausable - Privileged accounts will be able to pause the functionality marked with assert_not_paused. + Privileged accounts will be able to pause the functionality marked with self.pausable.assert_not_paused(). Useful for emergency response. @@ -77,8 +77,8 @@ diff --git a/packages/ui/src/cairo/ERC721Controls.svelte b/packages/ui/src/cairo/ERC721Controls.svelte index 553452a4..4ab8b366 100644 --- a/packages/ui/src/cairo/ERC721Controls.svelte +++ b/packages/ui/src/cairo/ERC721Controls.svelte @@ -39,14 +39,14 @@ @@ -54,7 +54,7 @@ Pausable - Privileged accounts will be able to pause the functionality marked with assert_not_paused. + Privileged accounts will be able to pause the functionality marked with self.pausable.assert_not_paused(). Useful for emergency response. diff --git a/packages/ui/src/cairo/UpgradeabilityField.svelte b/packages/ui/src/cairo/UpgradeabilityField.svelte index 5e839007..fe97fb42 100644 --- a/packages/ui/src/cairo/UpgradeabilityField.svelte +++ b/packages/ui/src/cairo/UpgradeabilityField.svelte @@ -9,7 +9,7 @@ From e6148f1bb7d7381f92b4b5be4f2d40831dc5b2ee Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Tue, 5 Dec 2023 18:07:16 -0500 Subject: [PATCH 15/29] Handle decimals in erc20 premint --- packages/core-cairo/src/erc20.test.ts | 19 ++++++++- packages/core-cairo/src/erc20.test.ts.md | 6 +-- packages/core-cairo/src/erc20.test.ts.snap | Bin 2413 -> 2415 bytes packages/core-cairo/src/erc20.ts | 47 ++++++++++++++++++++- 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/packages/core-cairo/src/erc20.test.ts b/packages/core-cairo/src/erc20.test.ts index 2b7efda0..27404f99 100644 --- a/packages/core-cairo/src/erc20.test.ts +++ b/packages/core-cairo/src/erc20.test.ts @@ -1,9 +1,9 @@ import test from 'ava'; -import { buildERC20, ERC20Options } from './erc20'; +import { buildERC20, ERC20Options, getInitialSupply } from './erc20'; import { printContract } from './print'; -import { erc20 } from '.'; +import { erc20, OptionsError } from '.'; function testERC20(title: string, opts: Partial) { test(title, t => { @@ -117,3 +117,18 @@ test('erc20 API isAccessControlRequired', async t => { t.is(erc20.isAccessControlRequired({ pausable: true }), true); t.is(erc20.isAccessControlRequired({ upgradeable: true }), true); }); + +test('erc20 getInitialSupply', async t => { + t.is(getInitialSupply('1000', 18), '1000000000000000000000'); + t.is(getInitialSupply('1000.1', 18), '1000100000000000000000'); + t.is(getInitialSupply('.1', 18), '100000000000000000'); + t.is(getInitialSupply('.01', 2), '1'); + + let error = t.throws(() => getInitialSupply('.01', 1)); + t.not(error, undefined); + t.is((error as OptionsError).messages.premint, 'Too many decimals'); + + error = t.throws(() => getInitialSupply('1.1.1', 18)); + t.not(error, undefined); + t.is((error as OptionsError).messages.premint, 'Not a valid number'); +}); \ 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 97717107..14a376c8 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -550,7 +550,7 @@ Generated by [AVA](https://avajs.dev). fn constructor(ref self: ContractState, recipient: ContractAddress) {␊ self.erc20.initializer('MyToken', 'MTK');␊ ␊ - self.erc20._mint(recipient, 1000);␊ + self.erc20._mint(recipient, 1000000000000000000000);␊ }␊ }␊ ` @@ -852,7 +852,7 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer('MyToken', 'MTK');␊ self.ownable.initializer(owner);␊ ␊ - self.erc20._mint(recipient, 2000);␊ + self.erc20._mint(recipient, 2000000000000000000000);␊ }␊ ␊ #[external(v0)]␊ @@ -1063,7 +1063,7 @@ Generated by [AVA](https://avajs.dev). self.erc20.initializer('MyToken', 'MTK');␊ self.accesscontrol.initializer();␊ ␊ - self.erc20._mint(recipient, 2000);␊ + self.erc20._mint(recipient, 2000000000000000000000);␊ self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊ self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 3e5b67323019adbfc59461d6650779e95eef6678..66cb7de854c96cea579005ab48aa35c5ab2397f9 100644 GIT binary patch delta 2242 zcmV;z2tD`h67Ld!K~_N^Q*L2!b7*gLAa*kf0|0(pa;cW`oGp*27BQaY(K2Q`bs!@K z`vYEI@Nv8Y>S`a02mk;800003?Hx;R+(fw0qDm_vwd#dRsB+pvHqy2Y5#iuK#VSc5 zqG_T$Do|Bfv-WIa#cNykIB8mPK;p=aBd2oY&OhL%@DKQZ1I*ZC?~FZu?Ax22y=2#( z`CjwQH=n0m^!q5_;|;FHZr>=^i*Yc=cv(m^x8+jJF_8DRo$_X z2XyqN(Q^!cW%u&PIfJ(HzM}@e9q7dPtM6~+I3v{F$M%Sn^&~ZVB4s9l^kx!%%8PpU+D;#$fBMVpj z4gFz2&pe0CEzfa@Zp3;SX+ksz+CfhVFL1PUEr9wI^z|o8MtC_z1XlcrPsfXZbZv#X z*7RV1SMj0MRTWNTD+~$b_LGqFC#G#86IkXu=rxz=E?RCW%ezNEEU#=(%vTM%q3v*z z(h2agbS#+N)3^TN_VnMkX11r}Ieq9S5NSHFEa+*#Fg)n{a_7sPFL!>?&Zn49$j-;0 zGz`^D{VSG!^06RNqJ4}t zC%dVelz0KlT8J|mPEjy}uX3!N3j$wk?d~)=Yj^+7%&i?i$A^00ndnkgV;)p>pMEQy z40Ih!Q&pV{JDRx{eJP#DQ)-f}+yy!YuoF@}jD1=+GJ+JTZq9d`3Ebts4S3WtYNE%PCRI;UT9_w_FrcJK?f|<$(zV zTn%0>!U&~N0)RCsA~B578)*@7lk+fT zvxoOmk{NUzxj7-Sv^$gMxFr5F_FSTWQzxbTya$6E1T4)DT-Um6My!6D^1L2D3tgC$ z2gC5k!B}B@5zbWt7O-`wIb9)|mV(b}Cm>6g5o##`3~UM|j|%KIITvJX4iVyY#d`uD z^M-K6ONr~F41p)G@<_zsZNCc(l+S~@>6%a=D=fucB*e(+#Kd(R#}W}28=fbB!1tkt zG}}QMxdx2_=aZq0k`QAo<3{UxPOr(q&EqeHTqyTe3R12>xN)p-`gbNLrikf?1!mdG zWCmQX?gi-t=J{WF_Z4~dZB*rSaTyC`vhcsG)n5(_9TC3`ID%POq z3$bg4*e{%(P2$l$B)3X9BHt$oEFpnCJyK#^MG=L! z_xX^5a$%xV#d9p^XQK=ER=McH(!J8?Lg;=e`|aby?E~##@5Q#NbfJaT*4MC?kI99^ zF1xJ!0fs0i~eb1=F)f|RS#B0xh<)oIt=B5=Q;537QOY|lI zM+PlQNQM&~#UNgV)Xp3gSGZ9IL6}S!5Gz?tiicbM$V|+WR0WHFKj%VhpWc-PJhLg_ z5!Gg9N69ju>l;&&Wj?aZN0#}>G9OvyBLfsNKtVs(@li_#C=?l>kO7Ko5TF>kgJ(bi zOs?T)v~bIU6fHTlX32v+@=$LGx;~e=Fv@3j>iV2u%%BF3cwtNog01x*BCYquV zd%*g+U#yBg**0>2kFzM`l##E8kQPH)j2T*talRgcY-(}7<@P4Gr@y>Cb4Ow5l*#O} z5_6qHsI&Pg#itCk7nEOP)g2nMC5xbzS>&W5bk)OqLTxlB4snAOlpSFd)M2!vZ z;B7T3_7d&xygVxIC1OU*pqFUI?Ld?5%V9)2`Mw<4MRTn?ycOA^GbPvP`nJ@_R+#JD z$r8r$7on4dIYncx=iI?8sikEY9;?HNB7f5dUDz)Y5hR0t=3LF*?2VW2 z!&8s@!mCf;K-Kx&W*>2SNJhE5*!hg?27CS=v@OEIKEU_DKV7JX2q8F;x-uXcQ;>jV zrqt-Tm%SE?)N7GIW0WxkQKZ@R@jQwlOuK`l7z$$q#0H~|UX^I-H2XnB)6O-7idI`gWE%8bNbf3+sWV>MODFv@9)Y=)D~Z~{_)gw1d)F>_lq zSghe}&?z>J%(X(BNP{W)QnBHMrjr1*b_)Dcd^-+Sk3kGfBnPh^rG!UVSV6fY&JqdOBnt7U{Y^oAF=>5ns&VZ-9dY+cp^7Oz6XAw!cUnX8!SOKM4@a=Gi=Gt?9208 z3Ri2y?JxOa{c)583!%t=oS!TRu2Dg7?cdoi^!sG8u@2?W#q(w2GX6d7YHZQONoGG2 zB&CtzDgoc(N^oxD6b6`cO2%7h1`iavOAD zJFU?;HoOEafbDhpWY&W>~<_iKl6Y86Cx8?@T>!TQ&*s;udSNC4P5`!LH>u2h5-=x_2yqUZ`{5? zKA(Jc4>s3UH=UmA*cih` zBb=nizn7XWK&Pt0k7_ACay)PX)rg;#0?+YfI&7PKU!jm5y#^h#340xAXy>adZ^Daa z&$XhlyAS~)fE{w>`xF{V96RQ_P0H#a0ti0asDh(^2==frH$e|td$x611e_a`!IGxZ zM$of?l>?ByEe1stB3zV+Rv&qRj+Ddb8dU~5F6hvq&4e}bi8LaEnu2JB5ug zu48Gcs&ipSGxwq|r4xBdO|q4{K*s=fLaK+HmY5fjX^)ksJ$}0`1e6gX11lDF0xlkZ zTnI5OTm~RrfCL^LTBCy}=8%HVNT;uLLjb4jQrKxZC2Bc5{H2f!<=#p`$`uGVjulS-&g8@tF&(kMEL)k( zfa`h=HpjUNkf)84UjCRcieJPB!%eY`;ysqcSS6Rst=8d?Mr#mrwKrC4Roza-8uWZ2 zcFhp`h10W1JlcokRtZNWT*OCzH|5#EO00z@U&wPJqDU}J?jfEfB(SGPN{p*0qVV=U zA5u^*OmwPvjs^W}bm87A7hPDoR~lUi-7jUoeSElmpdIYJ*jAM;w9wl68us!rxsW(! zOU;MOh==3}@)|}ZqQ4=rj-{&Y@aJaqvlNI)hG9djBhw)SdHOnb^$#{)*XtA8sKoWw z_Vf1fizBVQwY&2&T+T|tkz`2VV%1UKGwN`44MQj5wP(O`QcGZS(+UxAn!&&&dXs=7 zgBB$u!-Sk!>xW~Ca#lJ1&e>b;zDd++?549vnk*a z)n;Z#$ugh$jVZ}8A6e!j%Y0;+k1X?%0SXzQpr3hs)RF-TMFuEjfMN~;6hn9L3@Cuf zHT;YgZds6`C5P55d9X(w>J35H=a*a<$S65fFP2+zaXFtf9B3}j}?Sr%rGqexmd>I7U)Z*;Q?M-e^e{*~0Zo$wAlG)`T zu64$s&gQ2W%Oa;E<|}=0?Zf^H7PX&5q=GuCBL|B|e)7(7oN4f;Lg!F?+7@;WH8!|| zx7DcFIkda;@~F6Th#4`1&Y>AM|4gzqA}Ok+`%lVoMjjutHX&Rf71tD*e?kYq<((mT+QC>Qa_U!2SI#}P`ZAQt_vux;)s2O*)P|HkP z_aN}0);Hn9Y)Qi)4?1l3%DDHXfYAOH?W50AHUo}>PwX&<7beZDfZBxFGz}wZOg|8u zQJe5qCEaO{tU9kIBg|5rc~wPaMq;nOS`*^2nyO?NOZ>98TnVr!aDOKxUgjNekY z$|7!m$(QDjqX1Y4MP`5aWchE6%71JBK7OI!CsT`cD0VKMFVmFq?`hXwizZGo*O?$G zjSN=__!ifFa~r2Hz?@Sc-byQI-jL~5l9%UQbD&Q9pCwe7oL{kCVKV23wvt7X$!D2- zmdWS3r_p5cS&_+SnS7SXXPJDK$!D2-mdR(Ce3t*zMo8S;v=Dt4qYfJ$H{Y Oef>X^yPr%$l>h)#dq6w@ diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 58f76c2e..707eb1ea 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -194,12 +194,55 @@ function addPremint(c: ContractBuilder, amount: string) { throw new OptionsError({ premint: 'Not a valid number', }); - } + } + + const premintAbsolute = getInitialSupply(amount, 18); c.addStandaloneImport('starknet::ContractAddress'); c.addConstructorArgument({ name:'recipient', type:'ContractAddress' }); - c.addConstructorCode(`self.erc20._mint(recipient, ${amount})`); + c.addConstructorCode(`self.erc20._mint(recipient, ${premintAbsolute})`); + } +} + +/** + * Calculates the initial supply that would be used in an ERC20 contract based on a given premint amount and number of decimals. + * + * @param premint Premint amount in token units, may be fractional + * @param decimals The number of decimals in the token + * @returns `premint` with zeros padded or removed based on `decimals`. + * @throws OptionsError if `premint` has more than one decimal character or is more precise than allowed by the `decimals` argument. + */ +export function getInitialSupply(premint: string, decimals: number): string { + let result; + const premintSegments = premint.split("."); + if (premintSegments.length > 2) { + throw new OptionsError({ + premint: 'Not a valid number', + }); + } else { + let firstSegment = premintSegments[0] ?? ''; + let lastSegment = premintSegments[1] ?? ''; + if (decimals > lastSegment.length) { + try { + lastSegment += "0".repeat(decimals - lastSegment.length); + } catch (e) { + // .repeat gives an error if number is too large, although this should not happen since decimals is limited to 256 + throw new OptionsError({ + decimals: 'Number too large', + }); + } + } else if (decimals < lastSegment.length) { + throw new OptionsError({ + premint: 'Too many decimals', + }); + } + // concat segments without leading zeros + result = firstSegment.concat(lastSegment).replace(/^0+/, ''); + } + if (result.length === 0) { + result = '0'; } + return result; } function addMintable(c: ContractBuilder, access: Access) { From 47b1e68e8e613b2aa0aeecc298c5daf7660b3614 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 11:14:34 -0500 Subject: [PATCH 16/29] Import erc20 and erc721 interfaces --- packages/core-cairo/src/erc20.ts | 20 ++++++++++++-------- packages/core-cairo/src/erc721.ts | 12 ++++++++---- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 707eb1ea..50231b8f 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -92,12 +92,17 @@ export function buildERC20(opts: ERC20Options): Contract { return c; } +function addERC20Interface(c: ContractBuilder) { + c.addStandaloneImport('openzeppelin::token::erc20::interface'); +} + function addERC20ImplAndCamelOnlyImpl(c: ContractBuilder, pausable: boolean) { if (pausable) { - c.addStandaloneImport('openzeppelin::token::erc20::interface::IERC20'); + addERC20Interface(c); + const ERC20Impl: BaseImplementedTrait = { name: 'ERC20Impl', - of: 'IERC20', + of: 'interface::IERC20', tags: [ '#[external(v0)]' ], @@ -109,10 +114,9 @@ function addERC20ImplAndCamelOnlyImpl(c: ContractBuilder, pausable: boolean) { setPausable(c, ERC20Impl, functions.transfer_from); setPausable(c, ERC20Impl, functions.approve); - c.addStandaloneImport('openzeppelin::token::erc20::interface::IERC20CamelOnly'); const ERC20CamelOnlyImpl: BaseImplementedTrait = { name: 'ERC20CamelOnlyImpl', - of: 'IERC20CamelOnly', + of: 'interface::IERC20CamelOnly', tags: [ '#[external(v0)]' ], @@ -144,10 +148,11 @@ function addBase(c: ContractBuilder, name: string, symbol: string) { function addSafeAllowance(c: ContractBuilder, pausable: boolean) { if (pausable) { - c.addStandaloneImport('openzeppelin::token::erc20::interface::ISafeAllowance'); + addERC20Interface(c); + const SafeAllowanceImpl: BaseImplementedTrait = { name: 'SafeAllowanceImpl', - of: 'ISafeAllowance', + of: 'interface::ISafeAllowance', tags: [ '#[external(v0)]' ], @@ -155,10 +160,9 @@ function addSafeAllowance(c: ContractBuilder, pausable: boolean) { setPausable(c, SafeAllowanceImpl, functions.increase_allowance); setPausable(c, SafeAllowanceImpl, functions.decrease_allowance); - c.addStandaloneImport('openzeppelin::token::erc20::interface::ISafeAllowanceCamel'); const SafeAllowanceCamelImpl: BaseImplementedTrait = { name: 'SafeAllowanceCamelImpl', - of: 'ISafeAllowanceCamel', + of: 'interface::ISafeAllowanceCamel', tags: [ '#[external(v0)]' ], diff --git a/packages/core-cairo/src/erc721.ts b/packages/core-cairo/src/erc721.ts index 64381025..f78da44a 100644 --- a/packages/core-cairo/src/erc721.ts +++ b/packages/core-cairo/src/erc721.ts @@ -78,12 +78,17 @@ export function buildERC721(opts: ERC721Options): Contract { return c; } +function addERC721Interface(c: ContractBuilder) { + c.addStandaloneImport('openzeppelin::token::erc721::interface'); +} + function addERC721ImplAndCamelOnlyImpl(c: ContractBuilder, pausable: boolean) { if (pausable) { - c.addStandaloneImport('openzeppelin::token::erc721::interface::IERC721'); + addERC721Interface(c); + const ERC721Impl: BaseImplementedTrait = { name: 'ERC721Impl', - of: 'IERC721', + of: 'interface::IERC721', tags: [ '#[external(v0)]' ], @@ -97,10 +102,9 @@ function addERC721ImplAndCamelOnlyImpl(c: ContractBuilder, pausable: boolean) { c.addFunction(ERC721Impl, functions.get_approved); c.addFunction(ERC721Impl, functions.is_approved_for_all); - c.addStandaloneImport('openzeppelin::token::erc721::interface::IERC721CamelOnly'); const ERC721CamelOnlyImpl: BaseImplementedTrait = { name: 'ERC721CamelOnlyImpl', - of: 'IERC721CamelOnly', + of: 'interface::IERC721CamelOnly', tags: [ '#[external(v0)]' ], From 072644438391e3bcd26d6364ec028905fdc15744 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 11:26:01 -0500 Subject: [PATCH 17/29] Use ExternalImpl --- packages/core-cairo/src/external-trait.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-cairo/src/external-trait.ts b/packages/core-cairo/src/external-trait.ts index a89fea14..4645d78e 100644 --- a/packages/core-cairo/src/external-trait.ts +++ b/packages/core-cairo/src/external-trait.ts @@ -1,7 +1,7 @@ import type { BaseImplementedTrait } from "./contract"; export const externalTrait: BaseImplementedTrait = { - name: 'External', + name: 'ExternalImpl', of: 'ExternalTrait', tags: [ '#[generate_trait]', From 2de0194a6bca043e2e82bd22353d975d9f77ce0e Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 11:26:41 -0500 Subject: [PATCH 18/29] Update snapshots --- packages/core-cairo/src/custom.test.ts.md | 4 +- packages/core-cairo/src/custom.test.ts.snap | Bin 1133 -> 1131 bytes packages/core-cairo/src/erc20.test.ts.md | 63 +++++++++----------- packages/core-cairo/src/erc20.test.ts.snap | Bin 2415 -> 2415 bytes packages/core-cairo/src/erc721.test.ts.md | 24 ++++---- packages/core-cairo/src/erc721.test.ts.snap | Bin 1986 -> 1982 bytes 6 files changed, 40 insertions(+), 51 deletions(-) diff --git a/packages/core-cairo/src/custom.test.ts.md b/packages/core-cairo/src/custom.test.ts.md index 8f466a5e..57644e8b 100644 --- a/packages/core-cairo/src/custom.test.ts.md +++ b/packages/core-cairo/src/custom.test.ts.md @@ -67,7 +67,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn pause(ref self: ContractState) {␊ self.ownable.assert_only_owner();␊ self.pausable._pause();␊ @@ -292,7 +292,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn pause(ref self: ContractState) {␊ self.ownable.assert_only_owner();␊ self.pausable._pause();␊ diff --git a/packages/core-cairo/src/custom.test.ts.snap b/packages/core-cairo/src/custom.test.ts.snap index a79266f42a24b1590d29904e520a5b3d9273d4b7..ee4474cbd12edb6c36eabeb50edfcae57e07e327 100644 GIT binary patch literal 1131 zcmV-x1eE(hRzV6fuv$a4>3`IUn$4jz()~p%e(Fms0X-k-JRb$%G*EhOcG|o0EH3I4-iEV5Ng{D+$1La#I|!t zw*6ZD*9iwvNJX@jhRxV@fic?-k7%}YEBmKr;}BvFY1Q*$v3sSJ+PL|a`&NW`-$oS> zZKO(Uqa11*!J)V^G+vj>#g%%GWpJ89l|bQ7nda`)Eyg`!!Jr48bNFO2yU}D21x56( zTs*5HA68UaJk1NR%`u1PDIA|`5 zZcz)~sDSCN3iC{FV^68FOM1%GDvBmw#gNpcqa3xz@RLtWO&W%m(;Rr(n0spBK}-(8 zT8qP|txZC-%|WF?)dtN%1ApVlb#O*Mu3S8nvC#QtX$ zY|uNsp_Sz6Y*p$qQvg+~H0MC!$Z;jNIekHH;&RS&6ObgWPlYNeBxb;~H0mg0c$Df% z7$A?N0_WZ2Pm_lw%&K5jiJkvuNbJ}7tCiTR{CGIio(kfdpb|HO*Qb+^i+Sdyc@{sw zs?)si$C&0{3)eHv*IgKa zHR3c~w0|X^iPE+QK28F`2m`?`BiY-yV+M!kL)u{Khyy6)j-+s_%2g(esuCPO%)enl xM}+s$xQEl(Q-s-5gegDO&YmKS_H#2%+q0(#v!@6Xf^z0lgue^NcP!{1004wTF=zk) literal 1133 zcmV-z1d{tfRzV0;XKoo8*RoFYWf$7+WY3)Qos)CEZ?^gB_kz$p zWS_nPCp-Y(O&AXcgi#!^e#qH}ubziF-ut*PcV|w%<`?Jg&hv*4(ax*&z2!~f0%fq= z^?-8X6NqiJ)!l8i?!RLk$A=WSZMz}mF?RWWYY=*9>$IcR=zR-`moyDyd;t6DlJPhZ zpY3GVl+AhTyrm%aBb+eY3!nn>?d_jB%3I%WPZDOr0EH3IGl(Jx2(@hnZW0rIYTG#^ z+kU0qb;3auQW0&nVKa7JV9d6|W18*U&fe5)974jW^_SX|>*C8Jy-&B~bWNrnx(Hi*b)wFzA8j96egfZZsK0K@q(x z7f-9mhZU6;Px1onaLnP^>Imlwit=5~p(y#Ed+y)?1lu$?9Tmbbti-A*2jvh`95k0j zx2OegRKRpsg?XX3v8PnoB|T+o6-AS;Vo2)JQI6VU_{k@xCJn>Oc@8{n%zd@+ASOp( zt;b>1)+Q@!*USiLGC=7CBQHO|e2Bsro7$ApPuh(R^f{@^McZCvA}A^=d>Chre2TPd zRt!F35coDS?qOTjOmbd{KbExomth>mJM|og?{mVSMJloi$r99KvN1j)Cye87{uHO#e6v_Tub3Ktn>a`ak5C7jmk>_ zN$B-K$zvH{vfqW`9VXF1j6G-&y>mnK=oO2e!XlLG%@EZj)vhTVkrd@)S8VQTp=)I_ z5Vzq4X8pg=(7Nn2)zfZCp?unwe^>rC;PvSw@t$QjXP#=cs`^Jrj9s(Qtn6!x2jxa!l)|2$%Fhq zEa;f {␊ + impl ERC20Impl of interface::IERC20 {␊ fn total_supply(self: @ContractState) -> u256 {␊ self.erc20.total_supply()␊ }␊ @@ -191,7 +190,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly {␊ fn totalSupply(self: @ContractState) -> u256 {␊ self.total_supply()␊ }␊ @@ -213,7 +212,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn pause(ref self: ContractState) {␊ self.ownable.assert_only_owner();␊ self.pausable._pause();␊ @@ -241,8 +240,7 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc20::interface::IERC20;␊ - use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use starknet::ContractAddress;␊ use super::{PAUSER_ROLE};␊ @@ -302,7 +300,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20Impl of IERC20 {␊ + impl ERC20Impl of interface::IERC20 {␊ fn total_supply(self: @ContractState) -> u256 {␊ self.erc20.total_supply()␊ }␊ @@ -337,7 +335,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly {␊ fn totalSupply(self: @ContractState) -> u256 {␊ self.total_supply()␊ }␊ @@ -359,7 +357,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn pause(ref self: ContractState) {␊ self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ self.pausable._pause();␊ @@ -384,8 +382,7 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::interface::IERC20;␊ - use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ + use openzeppelin::token::erc20::interface;␊ use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ ␊ @@ -434,7 +431,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20Impl of IERC20 {␊ + impl ERC20Impl of interface::IERC20 {␊ fn total_supply(self: @ContractState) -> u256 {␊ self.erc20.total_supply()␊ }␊ @@ -469,7 +466,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly {␊ fn totalSupply(self: @ContractState) -> u256 {␊ self.total_supply()␊ }␊ @@ -491,7 +488,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn burn(ref self: ContractState, value: u256) {␊ self.pausable.assert_not_paused();␊ let caller = get_caller_address();␊ @@ -650,7 +647,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ self.ownable.assert_only_owner();␊ self.erc20._mint(recipient, amount);␊ @@ -728,7 +725,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ self.accesscontrol.assert_only_role(MINTER_ROLE);␊ self.erc20._mint(recipient, amount);␊ @@ -794,10 +791,7 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ - use openzeppelin::token::erc20::interface::IERC20;␊ - use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ - use openzeppelin::token::erc20::interface::ISafeAllowance;␊ - use openzeppelin::token::erc20::interface::ISafeAllowanceCamel;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ use starknet::get_caller_address;␊ @@ -856,7 +850,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20Impl of IERC20 {␊ + impl ERC20Impl of interface::IERC20 {␊ fn total_supply(self: @ContractState) -> u256 {␊ self.erc20.total_supply()␊ }␊ @@ -891,7 +885,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly {␊ fn totalSupply(self: @ContractState) -> u256 {␊ self.total_supply()␊ }␊ @@ -912,7 +906,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl SafeAllowanceImpl of ISafeAllowance {␊ + impl SafeAllowanceImpl of interface::ISafeAllowance {␊ fn increase_allowance(ref self: ContractState, spender: ContractAddress, added_value: u256) -> bool {␊ self.pausable.assert_not_paused();␊ self.erc20.increase_allowance(spender, added_value)␊ @@ -925,7 +919,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl SafeAllowanceCamelImpl of ISafeAllowanceCamel {␊ + impl SafeAllowanceCamelImpl of interface::ISafeAllowanceCamel {␊ fn increaseAllowance(ref self: ContractState, spender: ContractAddress, addedValue: u256) -> bool {␊ self.pausable.assert_not_paused();␊ self.increase_allowance(spender, addedValue)␊ @@ -939,7 +933,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn burn(ref self: ContractState, value: u256) {␊ self.pausable.assert_not_paused();␊ let caller = get_caller_address();␊ @@ -989,10 +983,7 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ - use openzeppelin::token::erc20::interface::IERC20;␊ - use openzeppelin::token::erc20::interface::IERC20CamelOnly;␊ - use openzeppelin::token::erc20::interface::ISafeAllowance;␊ - use openzeppelin::token::erc20::interface::ISafeAllowanceCamel;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ @@ -1071,7 +1062,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20Impl of IERC20 {␊ + impl ERC20Impl of interface::IERC20 {␊ fn total_supply(self: @ContractState) -> u256 {␊ self.erc20.total_supply()␊ }␊ @@ -1106,7 +1097,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC20CamelOnlyImpl of IERC20CamelOnly {␊ + impl ERC20CamelOnlyImpl of interface::IERC20CamelOnly {␊ fn totalSupply(self: @ContractState) -> u256 {␊ self.total_supply()␊ }␊ @@ -1127,7 +1118,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl SafeAllowanceImpl of ISafeAllowance {␊ + impl SafeAllowanceImpl of interface::ISafeAllowance {␊ fn increase_allowance(ref self: ContractState, spender: ContractAddress, added_value: u256) -> bool {␊ self.pausable.assert_not_paused();␊ self.erc20.increase_allowance(spender, added_value)␊ @@ -1140,7 +1131,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl SafeAllowanceCamelImpl of ISafeAllowanceCamel {␊ + impl SafeAllowanceCamelImpl of interface::ISafeAllowanceCamel {␊ fn increaseAllowance(ref self: ContractState, spender: ContractAddress, addedValue: u256) -> bool {␊ self.pausable.assert_not_paused();␊ self.increase_allowance(spender, addedValue)␊ @@ -1154,7 +1145,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn burn(ref self: ContractState, value: u256) {␊ self.pausable.assert_not_paused();␊ let caller = get_caller_address();␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 66cb7de854c96cea579005ab48aa35c5ab2397f9..01370f601d8a09df2d327085421e75e9174f3a2f 100644 GIT binary patch literal 2415 zcmV-#36S+(RXA>)4+p@<=(~<*s{sE_QjW=CGz>; z!%H7s{`ty-2g?5L#>;!pOdZ-jytidQ8<`ywdaAO$b$aG z>^4Mz2w;mm`6`8m6334Da-Fiej{t&?A63Co1ba}J>!1s*9osrD0?rM}U`bPHBk0+{ z$^pp!ECxjsB3zV+Rv&qRj+FiA8C3>4E@;!C&4e}bi8LaEnu2JB<1S)k;flYeUkvD( zr?9!+J1{$$ArAE$`GiXZXmcoC3}tuW7;9_%PS zv^uK7iENo6f&6?wn86o07S9ENFSdBs|Klv)U)QH@@%TAD)C12%=c*d>psKs{uhPjt*ReEJ z)j6}HnLE)Rr4xBdO|qRkK!+l;954FX=xwqPP=P1T4)DT-Q2pMqGcBa-i-#4!w|+6T+~{!B}S83C`OA z7O-`wIUOOImV%F4Cm^esk#8vh3~UM|j|%MhIA>&R4iVxd#@hoQ@P=^lONr~D41p)G z@<_zsZNCEx^w5L4>6%a=D=fusB*e&X#Kg57#}W}2+o1cv_o0V0+d&$628{y$k)e%} z5MwOkM(cP^x5>fH<1d9=DEC$hQm#O_ajbB9zl={z5z`S1%(9iq47jf6V9T7V0D0Ot z?&XgOqxeO9Fx(WIE8ck#*{x(mxdGcB(0=t}xpqcsxT>41Sec$I#0DB*>u@SJuFHBz za+M%M!byCnQ@$On$Xa*;2>DLL6bYxvUCUWQ0()|##JGxL1aEHgK?3E>M8}HfSkTYL z3qHBb#S8xVxHMi6I%dl5+Ts4@p0>C1Y*SS_&_b&ZSF!(($%VvayWPCQjJQMYmNOV< zi2e(Xhr>rJDp9+!`DE?z*@3pUvAy*? zT!u>Fj$}yS;w4w#G0S){gTWB-nlWHGsU@(vX@v;56=mR(^-jQ%L5mV(;Y3FSk!>xX_y=OL}!!HI8G*6z372V-2Y_3rHfEb<%87*3jNKw|t z=8LohRAOHI#p7ni2TIOR?Ff7CNF&Z)GwTrW z92FyFAu&Ed%(aY*$+(z|i_OrrUdF`~85fgrvB4E>e&S;MLC=Py(x?5z<7A^EtxDYN zjISmvD6+ZnHy1Sf95E}RQs46B};MUH%cT+abziuEX9$fIIFk2yqf%|6q6vFu0Y=#S*d_MJ5cFFvae(p;K#%Mwf zF6*+{QZ`%m=?@QfHxo_Kh&^E4-p^J~B*^sg6*HY(sI&Pg#U5&W=k!4b_G(82NueJ& zce6Xaq>zl?*1{dx#|pC+>q`!j%$Q+tux>~pqI~ybgxfMurC=!}#t42#slkU(RUF$Gbi+4VWDiy=(9F`^g>V+6zoqmHhK zXzC=}EJV}OmNQS96RHZDQl3WyJ98ynEiNl6xvI-P5ZMPJ`#@??#xDCnl#1p`_JPPg zkTLXu*NOV#H^73~>{z23r&iN|VMlVOxo z8rgX!JI``R5q6%j#LR4UUa^+5K`N@~Y^=M`F4EvjzEo^@rs*W0tsMjZ82=mxw?`lb zCh~(7&dV{}0I^JLScb003+jy4L^z literal 2415 zcmV-#36SV-S(zXo|;ov~UDoG)tX`(zT zP*qv8_H1IsYg_g>Xe97r*h=ZKj5eE5BLMj*kkXEJ$~%lo1ML6*Pi)a^UXJ( zzlZao+p!$|%>V6Ah)iU`vkvf0U4fpywrct|aQ#yU`M-QH41mB-H~+eMp(+0UtM_}@e9q7dPtM6~+I3v{F$M%Sn^&~ZVB4s9l^kx!%%8PpU+D;#$fBMVpj4gFz2&pe0C zEzfa@Zp3;SX+ksz+CfhVFL1PUEr9wI^z|o8MtC_z1XlcrPsfXZbZv#X*7RUk@uAgK z6;5O;3<>1+laTW#rfnh6g5o##`3~UM|j|%KIITvJX4iVyY#d`uD^M-K6ONr~F41p)G z@<_zsZNCc(l+S~@>6%a=D=fucB*e(+#Kd(R#}W}28=fb?_o0V0+d&$+28{yelc9~0 z5MwOkM(cV`ugSs9<1d9=DEC$hQm#O_ajbCqcP1yMi0Oz0X4%SQ23*&3usP0EfIMxS z^zz4qQT!r47;cJf6z{Pl#wxj7ZnX}FG+Kk0tG%&WtLkFe0lKiFKaPi&(S*IV1q+s7}CwD#8S&dYE) zD+NcAA%TlkM}5zz!_^#yPQ+`^faRo?z~-hEBH%QGflKrz0Y?TcN=Swi9mODCh1AX* z6<4@X20@ri7!WI2O^SzG{m4wrZTyE{3?68nJQph##9P>0p$q^qJY6zcv>0)vtc}eV zX$h#rzGh@O*5H%@yCAUeS=qzqZuS{5bnzwM$Dj>XvXb8lkLl4L_7Ju9N9&4t-KZ4 zqBAAe==!$Q$X1x^+{qHg@)x0#g*ioIuIJprEUBes7#^#`i6Vc~2VK}N5)mYWe&$@w z-t3Y=GHzQ7SL6^YOgq+>93+`Bqu^j&kU~WHuE!WXg(;rrwKzR%5s5yJY*ja~EG2O9 zX<$HcMEd@JoVEJ*e$67%v*`e!BEwUU`@*YF-$2#*+-4tfdPqjOyx94S>;`-OAG9sP z!al(Fz&~B6h6o`zk-9P<8B>seWv0~VxR<>ai_~k8Kx33K1yQ8g_3=E4Axyi2qZkTf z1jGiTj$V~$>NNX7MAOrjGf$dRDr}ljs!9Yq^K`vdTp3joagYrwvSCFwtjLBH*{~uT zR_0~bjM}i0qi5M*B2hE$YN3{yw(ddTL#=PZhuM;bK^}eB4wrH7O97$%E!sz)r)&ls z2cOu54lhiaSpl^PvuPSe(wKf|IHNYO-7idI`gWE%8bNbf3+sWV>MOD zFv@9)Y=)D~Z~{_<&2TI+b6Yf6tl@0XDK?GFwL+UngDLq^vEhZLlK{1L3j9-iI}TQl zK@3bJ2d^HbghyCdLAfN(5*1cbKKPwW82$QSQg3A+vH&xhcD(=HL3^usA~#092Y#T! zPnjSaEI~Fzp=?bvY{|{+%kx_bS8K%WFZp8qag+oLp~#${EC{YqL2&Kg*)R0_WU{di z<M%<-{MMeZsQaNm~%?TTWJN&8#3M6@?kQuIe4c1 zFBU3H&aY~(Fq!jATgkG?bhJ!I%XD+Gnh#IA@OT@xGcaJln{Xe_7%%6Fc001bYmoxwX diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index a13bf612..c644fec3 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -107,7 +107,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn burn(ref self: ContractState, token_id: u256) {␊ let caller = get_caller_address();␊ assert(self.erc721._is_approved_or_owner(caller, token_id), ERC721Component::Errors::UNAUTHORIZED);␊ @@ -129,8 +129,7 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc721::interface::IERC721;␊ - use openzeppelin::token::erc721::interface::IERC721CamelOnly;␊ + use openzeppelin::token::erc721::interface;␊ use starknet::ContractAddress;␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ @@ -187,7 +186,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC721Impl of IERC721 {␊ + impl ERC721Impl of interface::IERC721 {␊ fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ self.erc721.balance_of(account)␊ }␊ @@ -237,7 +236,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC721CamelOnlyImpl of IERC721CamelOnly {␊ + impl ERC721CamelOnlyImpl of interface::IERC721CamelOnly {␊ fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ self.balance_of(account)␊ }␊ @@ -283,7 +282,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn pause(ref self: ContractState) {␊ self.ownable.assert_only_owner();␊ self.pausable._pause();␊ @@ -361,7 +360,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn safe_mint(␊ ref self: ContractState,␊ recipient: ContractAddress,␊ @@ -448,7 +447,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn safe_mint(␊ ref self: ContractState,␊ recipient: ContractAddress,␊ @@ -477,8 +476,7 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ - use openzeppelin::token::erc721::interface::IERC721;␊ - use openzeppelin::token::erc721::interface::IERC721CamelOnly;␊ + use openzeppelin::token::erc721::interface;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ @@ -544,7 +542,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC721Impl of IERC721 {␊ + impl ERC721Impl of interface::IERC721 {␊ fn balance_of(self: @ContractState, account: ContractAddress) -> u256 {␊ self.erc721.balance_of(account)␊ }␊ @@ -594,7 +592,7 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[external(v0)]␊ - impl ERC721CamelOnlyImpl of IERC721CamelOnly {␊ + impl ERC721CamelOnlyImpl of interface::IERC721CamelOnly {␊ fn balanceOf(self: @ContractState, account: ContractAddress) -> u256 {␊ self.balance_of(account)␊ }␊ @@ -640,7 +638,7 @@ Generated by [AVA](https://avajs.dev). ␊ #[generate_trait]␊ #[external(v0)]␊ - impl External of ExternalTrait {␊ + impl ExternalImpl of ExternalTrait {␊ fn burn(ref self: ContractState, token_id: u256) {␊ self.pausable.assert_not_paused();␊ let caller = get_caller_address();␊ diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index e74af52918dddc1beb117c73a6867b7f6024337f..aef284369b887a3f7bf622154122c480c83c8a49 100644 GIT binary patch literal 1982 zcmV;v2SNBjRzVyA+aR>zkdAl|3NYN z;15FN9VNg22}wXg2nQeuyda4{oE##O{Ptlu1O)tY_1$Mzu3cfDPp)41;?tw6_wQT# z&$oWQ`!w)il)$^aA&f}i2M{~fPOrbRa_41206vN!aU2gt1Otz}S{b3Cwez-*j$mZH zU$N*XO`wHh7`=mW48tID9KxPD4#eK~>)$%g_TDD_y@^IKil~eSHBGC5N6`XtPbHW;=lmXVINaA=g}+^4#T&3@e651mXyUbpWW(&CJ*m z%ls=>EFn1ch_#>JAr6kA zy@gTC7K(@!`NGHt!6+SB*$vGaKLn(ZudGUgA=&*-EwNmR6$=zXsXvWlImig-Ed0n) z?%5dnRsuucv9$SGQ?zG~@8z)H3!;DoAPn9?Y_IaDxZ1H+cltlA@&I$PawCi3{Qwqhq?l5O&dPYNegCDWtD;4D*UH!inR&c-DQLQ%S;o zK%>c|l}p&VVzp=kX{jnp0J<3SC#7{*DqleeA`iOAw{x?9EZI#<6O=N1E0*7Vlohq5 znpQyL^7)>h`8(?9F`jl6*U7G z><62RVm>;VI$AfN0y@uF&Je0`DAnS_JGZ9xv1;9zp7IQK2z4gXJ)!MtP5?sJr>!UL zIUAy9%$jdh4WJzX0ySrVP&i8uHfbmnDdg5#cp&MioO6gv8vk*zN$vB6EoPm}iK<}= zGPN1@4Z51dXMzg8s^*IRW73vhMH};%95P8F+ns41n=*mb3eRS@H>I2Cd8^l$w)#8- zJ^sjnw)b&z*7#)An>1I=AA++0Xbd(@QNGJV=wpPta}(lc5Zk*Gg!XBdY&E3UFWVpy z8gOJUBAlNkj-S^KdN$3IZ2e0sM90K^1<~BVcfL)&B3&zYD7)4v(&*w;5waS0(nmBI zns?H#|E=w$|8;$dcG9QV3}1rH?RG1=ee->`ZS>2%)7|b&w>!$>`m${ZpI1eewNtG4 zI7K6bp%=sfG<4cC+T$#UQye%JA26m}nyyR}XC4Y1q*V=jpH*_&4MeY@wld;2t27p` zc+7uix}wl=y4mGsetB9ZTicJjFP`?@?iR%-181U2R1QgLhvhi$6>v`$r%p8^sIb$( zl6*C?wsLJNSCygW9GtV+&q^!!tgVn4X^~!@M(3grnKyG$BBD8ZUV@hEB9E+_$jce1ZX%ZLMMrz`y*>Hf zo_udlzPBge+mr9@$@li;yI6_s$@li;dwcS|J^8+%C*RNVzhkEKo#psfGb(uPpADFl zS-$sz3v+a@IV`A~oIEn9?~fWQJihf-A1WgF+V$8=BKHs^hxD;{VKf6om3=?ze_Rt? Qpz)>X|E$QA`rcLm05%oA4FCWD literal 1986 zcmV;z2R-;fRzVe zE_NsiftIO6h%5>eovtl%F$~yybPuyP*qiJDMoJ__N|by|YCG~pV$=M;|G=OBfnxH} z?}f-aN&fm9l7NH|_COMNK@x#DIYuP;<72-M2>A8d`>R*3UtzD$u3h=^^OI{2A6kbm zcYeA5Jn&$Y!26v(j7Z=I5Ifdhr@OXx?{z`|K8YZ491leV1CP8}8=$_m_pXahU}Sw* zv*>G>Knuk%dJp3mhC$>wgnjEc5PRQme(N~92ix@bHX6hzqC6f|Pz96)N@D1d0MU;L z_O=}7@L+pOp-f3V@%fG&19I$G1qLlEAqayb=vbKuEeoE~aWQe1eb{(p#?lxnNK71w z!zKxo6z1M*&&CPMmU4;BTE^x zG4!njhQ4EI>$Ras&%S<;nf*Z!1tb7r@E&4&okzv>mbJdu{b`*Cn6tIBH6EIedqe6D zy%3h8^YyD*bpG#)rHsykGMDTK64wJ^2(b(LeGHSNiQ!EQZ(?{8!yFucDIL7Fd?k^Ow4KW*3Vj+e0FQ8)1*$BKyQcx^3HLD{*LpKzZ*#mJdduo z7o4LJfp4b3JC&asefS!t1$kMbls zLxC$vxDRMFDYs%JTvhYt-6XAgc_mQTe1-BCgdp;ui+nrN^~Zv;w6sA(X4I0p_n)Li zaiJzwRad|{%!X2Ts$!%{Rtr%q!zt^6I5kp8Y+3zQ2$29kZ7rh2rvyGm16u>FatLh_ zBP$t8pF+^c397pKcPw?&?G=OQu@6JCxwZKupHOU2QZtAE^&sm%+z1hujlq7gK~b${ zFb4a<)*@ezRw|CxO{fN4WLwVBRHLj^X&>JC)wQ2x?MC#ZGw3128B6wrw!0Yt2wk7H zuC!;Z37Ii#+)+7dwuBL=Iz5EKd3vx(LLo@bw^G9+Nl*ElLtN7EN5v-foIvPemdTu* zYL*}so7uibRulV_QI4xhuE;+kSLvm5p0wonIN57|uE}e{tX0W8UDD2kzM&_pPHnF0 z^0@Q#6Gzw1r%6 zgCHX2qxT#CYDe$?+*qNb_X$qVSKtV{IdE)LdR*RAGfoQ(}L{mK5f5x-gVnM)IO1=O5_Bb)uKu!Cpim0DpEhLYfdDq3Az9kNQ`%TnFyQMu9_D_`lB zLu<7$=34dkp$~>3O>neCF`P&a(wm3pQWa}UuThGuQZdy%!XP3pE2Qjl8rM~-XR0D8 znOvydl;_qI<+*NRwMZ}8d11?Se;9_=Fs9zohvxIz+h1wr`pw%bbYA;uu1a%rvn%hp z;TP+Ib(O#>u_FAqf3a1bRo!;vQ$o74o`K|edAg28y4-DqGdZ3DsRRTGtB^DeQFCv6 ziO$&<^4_>aQ}$H>(X>e~Prr20x6$iSl!$1Ko|m9=yU4rkCh}qis#=Iudsfn1k#DZZ zH&^6mv1M~bzNANUMZUQrUm)9|4K8V->k+zu~CiJ z{C$B*nALlbxHR|t>O+Ehlqo7aWvsTk;|FZjp(28BU5`Bqa*siBOurV7h2~&U<#dnw UAD2XDXnczLKh%~s=`>dW0P~y3!T Date: Wed, 6 Dec 2023 11:39:06 -0500 Subject: [PATCH 19/29] Sort imports --- packages/core-cairo/src/erc20.test.ts.md | 10 +++++----- packages/core-cairo/src/erc20.test.ts.snap | Bin 2415 -> 2403 bytes packages/core-cairo/src/erc721.test.ts.md | 4 ++-- packages/core-cairo/src/erc721.test.ts.snap | Bin 1982 -> 1982 bytes packages/core-cairo/src/print.ts | 13 +++++++------ 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/core-cairo/src/erc20.test.ts.md b/packages/core-cairo/src/erc20.test.ts.md index e748c056..4e740b23 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -105,9 +105,9 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::interface;␊ use starknet::ContractAddress;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ @@ -237,10 +237,10 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::token::erc20::interface;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use starknet::ContractAddress;␊ use super::{PAUSER_ROLE};␊ @@ -380,9 +380,9 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc20::interface;␊ use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ ␊ @@ -788,10 +788,10 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ - use openzeppelin::token::erc20::interface;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ use starknet::get_caller_address;␊ @@ -979,11 +979,11 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ + use openzeppelin::token::erc20::interface;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ - use openzeppelin::token::erc20::interface;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 01370f601d8a09df2d327085421e75e9174f3a2f..5c3a326a4f78bd2409b0569da0810aa9984faca9 100644 GIT binary patch delta 2400 zcmV-m37_`w65|qoK~_N^Q*L2!b7*gLAa*kf0|4z9%s~A$W$UlCw`(K4qy0YeV zea}T09yQ`gM*97B)7RmVs<5M4N(j9`KLl#RPfGzO=rI|#f&X46knX;w2?F~BG}i;q$GVZ~WughmAmBz_C4RurVmUhOQP9($A{p`H91%$I6F$8l z0b;p-3iYfR080shW2p)wvSo?{{PX>o^ZT}ILtA(3w;*UPkzKUZQkJ&%zgt> z$cA>~NlGU|%hGW`aZg|Uo!QgBUA?e9ozCe&KLk)SbjJaKrkiE}!cgvfx%1`D7wvq4 z`4I1X1WH3t?Mx2fO|nYOoXWhR*4DGK@B4UvE=3EX9vhM}vRlfD?nG$QMXL`#r+L61 z2S6p+%Sd~Q8@ovu;IOU5IFsQ71vU7*#NzpS6!IvQ zG0!ChkVqnfM~2qu&`3EX;0w~}Eq?{zgk1tVFQ-gDszc77Or6iXmjyg(r|9;H0L8BZ&H)1&93fY zWHZP*GIL^Nc~_*&>BxLvz<;D@BP664`*EXLf!A#^aLf41A?M1ym4j3&5M~@LoZc^!6H~%;!UDBy z{bZ*5e&8X?T&e(N+BoUuPYEOVd3;dZh|Lx2yzuN+Hln`)+pB25hOu1RV>MiZo2*os zo-D)$s<3q!m7COMJtldOAVbD~NqVRgzCEPKT6_X<`Od_Y2&c(h%V|O)cY36xxI{66 zH#gZJfpTiYBPH-05EkPFpIm0*1^;~9H(n4sX39?cU~gkr+ueS)p(++|;OfIw0R&=nI0%5 zL$yQXy+aK_Jb5 zr1Gcz)Z=91B5jbk*(qC1C@8YI@i!AR`{RZzvKg+(hFAMo93@MW_XQq*GR!jMFk2yq z%6&6K3Sn|>Hlqbl7NoGqBXvaq=wf?ha{4Won83)Vb?UdAU^Jlymvz}}DVr^a^oOh6 z&3IEZY!7I+_p=q=r`W(9Fct-$GV;X?(qc%9ae)?NoG)g;o0^|Nx%QOV(_dV>a7SSV zTZd;lyHIEIBgV4Gsf+o4N;S-UieSMa{F91b5chTDi1Nty@e+5Mgmnh!`AJV)Vb4$F zYv%A>X$;u&v$gqrU)=LUjktiGpSkYCp+r0RJ{;LKGglsqY{{9Ddo;f-G_v(&o;z3K zc>W@Eu283F%Jm#LnSH8cDW=Ejbi%~v40Q|iYDYLpp&uA`vwLxWNg)}(t%WPrcd!kAHT&~AtjQMvmuMsHz?XL>D8&{{;KPZC>YMUJCHJ~|Ohz>iGde92g=&6_og zOxLuwpPfh~jHVv+WIeU^@TTW2XPGpoR26hV zc^)3@!j*JYTvpWQsxJFLWFLs^1F1n7yX*r|1~gZ)4@CBXOrQ^>MCFQcxtzu^1B41^ zyG8)?5NJKaUS*@2CcYcd{UhVvtsFvo8@GqPOz%uE4nC28j~zdlG_xFPGiLKNjHEoh zfU8J@;!y*sQF~-9dNCQf_En!3gJ{o4?DZCILOc$pH3dc)rIDRyvh%Ej6mI7kP0Y+z z=ZUqP4pI?Cr(@khyGVjB~=PK#W5<*7$!eR7qsTlK=ovT$S7a literal 2415 zcmV-#36S+(RXA>)4+p@<=(~<*s{sE_QjW=CGz>; z!%H7s{`ty-2g?5L#>;!pOdZ-jytidQ8<`ywdaAO$b$aG z>^4Mz2w;mm`6`8m6334Da-Fiej{t&?A63Co1ba}J>!1s*9osrD0?rM}U`bPHBk0+{ z$^pp!ECxjsB3zV+Rv&qRj+FiA8C3>4E@;!C&4e}bi8LaEnu2JB<1S)k;flYeUkvD( zr?9!+J1{$$ArAE$`GiXZXmcoC3}tuW7;9_%PS zv^uK7iENo6f&6?wn86o07S9ENFSdBs|Klv)U)QH@@%TAD)C12%=c*d>psKs{uhPjt*ReEJ z)j6}HnLE)Rr4xBdO|qRkK!+l;954FX=xwqPP=P1T4)DT-Q2pMqGcBa-i-#4!w|+6T+~{!B}S83C`OA z7O-`wIUOOImV%F4Cm^esk#8vh3~UM|j|%MhIA>&R4iVxd#@hoQ@P=^lONr~D41p)G z@<_zsZNCEx^w5L4>6%a=D=fusB*e&X#Kg57#}W}2+o1cv_o0V0+d&$628{y$k)e%} z5MwOkM(cP^x5>fH<1d9=DEC$hQm#O_ajbB9zl={z5z`S1%(9iq47jf6V9T7V0D0Ot z?&XgOqxeO9Fx(WIE8ck#*{x(mxdGcB(0=t}xpqcsxT>41Sec$I#0DB*>u@SJuFHBz za+M%M!byCnQ@$On$Xa*;2>DLL6bYxvUCUWQ0()|##JGxL1aEHgK?3E>M8}HfSkTYL z3qHBb#S8xVxHMi6I%dl5+Ts4@p0>C1Y*SS_&_b&ZSF!(($%VvayWPCQjJQMYmNOV< zi2e(Xhr>rJDp9+!`DE?z*@3pUvAy*? zT!u>Fj$}yS;w4w#G0S){gTWB-nlWHGsU@(vX@v;56=mR(^-jQ%L5mV(;Y3FSk!>xX_y=OL}!!HI8G*6z372V-2Y_3rHfEb<%87*3jNKw|t z=8LohRAOHI#p7ni2TIOR?Ff7CNF&Z)GwTrW z92FyFAu&Ed%(aY*$+(z|i_OrrUdF`~85fgrvB4E>e&S;MLC=Py(x?5z<7A^EtxDYN zjISmvD6+ZnHy1Sf95E}RQs46B};MUH%cT+abziuEX9$fIIFk2yqf%|6q6vFu0Y=#S*d_MJ5cFFvae(p;K#%Mwf zF6*+{QZ`%m=?@QfHxo_Kh&^E4-p^J~B*^sg6*HY(sI&Pg#U5&W=k!4b_G(82NueJ& zce6Xaq>zl?*1{dx#|pC+>q`!j%$Q+tux>~pqI~ybgxfMurC=!}#t42#slkU(RUF$Gbi+4VWDiy=(9F`^g>V+6zoqmHhK zXzC=}EJV}OmNQS96RHZDQl3WyJ98ynEiNl6xvI-P5ZMPJ`#@??#xDCnl#1p`_JPPg zkTLXu*NOV#H^73~>{z23r&iN|VMlVOxo z8rgX!JI``R5q6%j#LR4UUa^+5K`N@~Y^=M`F4EvjzEo^@rs*W0tsMjZ82=mxw?`lb zCh~(7&dV{}0I^JLScb003+jy4L^z diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index c644fec3..40118c98 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -126,10 +126,10 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::token::erc721::interface;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use openzeppelin::token::erc721::interface;␊ use starknet::ContractAddress;␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ @@ -472,11 +472,11 @@ Generated by [AVA](https://avajs.dev). #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc721::ERC721Component;␊ + use openzeppelin::token::erc721::interface;␊ use openzeppelin::introspection::src5::SRC5Component;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ - use openzeppelin::token::erc721::interface;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index aef284369b887a3f7bf622154122c480c83c8a49..6d82b598efd3ff44804a6e603a0e84b725c1742b 100644 GIT binary patch delta 1553 zcmV+s2JZR3555n7K~_N^Q*L2!b7*gLAa*kf0{|t=frcuX(UT%ue#uZ~rb4RLxI5

CcrZ%f-QEyJB=7@>9c!o8Us<{HG9dsTMUXg-ha!T3M_#Rr(9qg> z+eb$*vfi(MSoD)7&_Xec-oZGAVGubEVNV?gV( zNen#_AbOc#Z^Lo+_ck{a%8b+#*I(K(Acu}s640>{f-pFMj+Lv>vEVViF9vS2i?s)4 zUYbCK6H`a>VS@yhjLn^wU=Y}FG=M|*_?xv?+09^o6o*{o4kUn0Lyz71p{%fgNFDWX zlS95w0D+GlOeJO$j9|DMg>T2pl0#<}+HBLzY$vecG`h1XKpcUv z4gmGJnHgJRnSbSqB?PA)vG((Oe0lM4>3|Qlr5)_U*H~3JXVRH~N4C-`D5&%&Lfy>& zU-657A;iHkw6`#d*+LPqB3~H!AQ+`1E4!gtQ4WsRUTkY zR!&xUXg(aI)Ex#PtVZW+*R<&T-{(siodsooq1gc>t_Q*pViydD7$!*@!`m3%#_%?V zFINobq7PsMG3Dh_wt>VDzR7*WE-isKifbWXUiTTTq6}4^C5Ae^J60C3-C*cg>H5ZZ zsvYbTLSp41milis-rC#-@c~H!F|kzy+#qp59Ak7$R~W)BdQGjgb2f$awT@w4F-ACl zahw;=x-a@qcK3R}Zf}+3X@W94CBtIiNhMXrAWh7v^5$1ss=Rq~;ZkLZDqtbR2OgY9 zYSk$d=%qLyZyiVA)^QeC~4xR3tayS3dn9zl5b{9CC8@W_qQ8)?kBsVd* zkz*Myg&~Jj^5a9>a$}a1-ONx-6=zykndV|a%)p$_8|Ph~aJgb;=d3~5B%&GfxmGn* zXmxG|h$rJG(9+peO};oaS2Mkg*(OM*;3ERK0m=(i0h$Q4NNogi3r2ln& z;datz-xU5{RM=@?Nxm9cTe-HCtIAMw4$j%^XQdTIbj|MG&!j|lQ8irOHQx6$J^Ss_LlvexVo=(&g|3B!|n>E-ccS zZ6iC=>?*mByA_t9tU5dP4b024lcPV>#D@jv`8;cqjTPe%$vC=5z!nyFG0(7 zo=4VA}|Am!kgzZX_y(-c|qr DF74~w delta 1553 zcmV+s2JZR3555n7K~_N^Q*L2!b7*gLAa*kf0{}6Xj$~rd2`1@Mx19nH;S;#fO~X&% zqW2e(MXFc{GFBgp2mk;800003?Oe@n+cq5UHgrYP(@wqgptZoFU~anw$OfogF(XM) zV@*>eF0idA1X`vNA+jh?RQiP+cG;ezdz`(&_6B={9Y;!kBt=S;Y$r}?JMtm1B>umC z{PX`oG5O#RLgXDKzyAqIKtc!yAPKx6i9nnjB9i>}VK@W?{Brf(XIHLWVV_T~UisqF zqpSDtTl>$qe!lxO@L-g{yS*WdNZy@PQK!ys}T!k#(~#NPMo-#X6r-X{IMiAFJssEh|SQ~?!% zk{Eg`GC5N6`XtPbHW;=lmXVINaA=g}+^4#T&3@e651mXyU zbpWW(&CJ*m%ls=>EFn1ch_#>J75T!*2f-*ES=kNE8b1W2kgu#tgCW`dPA#!qiWLhKLa9HE zV>!qO=PdllQtsIp`c?u%-?6m$T2r)VkMHHM-wUFE1RxCFL2R$`sJPm(R(JY8t?~eK zvU0M*L-XMvrS32YVKq8myQW3w|2|*H=qxCI3(XE7aXk=*5W8SF#4t(P7~aP4Hiow` ze6eCU7kvODh$%0ZvJE7L@J;R`c4-N`QCti8^19Dx6=kUUEHTvS-LbNO?FK`~O4m2O zQ|(}%5E3g7vDAO7@z&-xh!02-h>5Kt;0B2c;uxc2y2224(Q9g@owF&VuXPObiZQ}} ziQ~L@)_u``vb)#&b$hEMPZN~cDH#?6Pb#T025DkWl{dfAQsvE?3!N%;$^?2T4#-=_ z5%xRIbN+2CG4MP(-;P74FQ?qizlSk4ftaVXW| z!#lU8_OWW+n4aX($var2ln& ziFVSb*bHBS&Fyw8x_$F~wr%vwz0=+9Ot(AA;`*{}2%lF)mbFu?_&7x)grOJ20W@^l zGn2IiT7MR=c+7uix}wl=y4mGsetB9ZTicJjFP`?@?iR%-181U2R1QgLhvhi$6>v`$ zr%p8^sIb$(l6*C?wsLJNSCygW9GtV+&q^!!tgOdj|MG&+?MQq8irOHQx6$J^SmrY=o5;%r8K`a|mXkjRC{~~+-_P>DW2W?-<@i@KDtPUm4VaW!zW0I)b9ApcEU25D zJTj>7j~XjHzV%igDkAvW_1H@y_Yfq9^s#thGy_DHeLw1dToYZO@ulehtjLu5-c|qr DC+gd_ diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index c19a9c70..4a40cb88 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -41,10 +41,8 @@ function printSuperVariables(contract: Contract) { function printImports(contract: Contract) { const lines: string[] = []; - const { ozImports, otherImports, superImports } = getCategorizedImports(contract); - ozImports.forEach(i => lines.push(`use ${i}`)); - otherImports.forEach(i => lines.push(`use ${i}`)); - superImports.forEach(i => lines.push(`use ${i}`)); + getCategorizedImports(contract) + .forEach(category => category.forEach(i => lines.push(`use ${i}`))); return withSemicolons(lines); } @@ -52,12 +50,15 @@ function getCategorizedImports(contract: Contract) { const componentImports = contract.components.flatMap(c => `${c.path}::${c.name}`); const combined = componentImports.concat(contract.standaloneImports); + const ozTokenImports = []; const ozImports = []; const otherImports = []; const superImports = []; for (const importStatement of combined) { - if (importStatement.startsWith('openzeppelin')) { + if (importStatement.startsWith('openzeppelin::token')) { + ozTokenImports.push(importStatement); + } else if (importStatement.startsWith('openzeppelin')) { ozImports.push(importStatement); } else { otherImports.push(importStatement); @@ -66,7 +67,7 @@ function getCategorizedImports(contract: Contract) { if (contract.superVariables.length > 0) { superImports.push(`super::{${contract.superVariables.map(v => v.name).join(', ')}}`); } - return { ozImports, otherImports, superImports }; + return [ ozTokenImports, ozImports, otherImports, superImports ]; } function printComponentDeclarations(contract: Contract) { From 23f129e0589e287ece574b11723d9d90b9f8bf08 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 11:39:54 -0500 Subject: [PATCH 20/29] Update Download text --- packages/ui/src/cairo/App.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/cairo/App.svelte b/packages/ui/src/cairo/App.svelte index 6a735050..e1886ebf 100644 --- a/packages/ui/src/cairo/App.svelte +++ b/packages/ui/src/cairo/App.svelte @@ -120,7 +120,7 @@

Single file

-

Requires installation of Python package (openzeppelin-cairo-contracts).

+

Requires installing Scarb with openzeppelin as a dependency.

From bd44ca34a591d77e2835e1baf10494cc83638a02 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 13:00:41 -0500 Subject: [PATCH 21/29] Fix hyperlink for interface import --- packages/ui/src/cairo/inject-hyperlinks.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/cairo/inject-hyperlinks.ts b/packages/ui/src/cairo/inject-hyperlinks.ts index 5dea15e5..abf26095 100644 --- a/packages/ui/src/cairo/inject-hyperlinks.ts +++ b/packages/ui/src/cairo/inject-hyperlinks.ts @@ -12,7 +12,9 @@ export function injectHyperlinks(code: string) { let libraryPathSegments = libraryPath.split('::'); // Remove the component name - libraryPathSegments.pop(); + if (libraryPathSegments.length > 0 && libraryPathSegments[libraryPathSegments.length - 1] !== 'interface') { + libraryPathSegments.pop(); + } if (libraryPathSegments !== undefined && libraryPathSegments.length > 0) { const replacedImportLine = `use<\/span> ${libraryPrefix}::${libraryPath};`; From 6126031561181ba017a731bdb21568ccf36a7ebd Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 14:10:22 -0500 Subject: [PATCH 22/29] Update Download message --- packages/ui/src/cairo/App.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/cairo/App.svelte b/packages/ui/src/cairo/App.svelte index e1886ebf..07292621 100644 --- a/packages/ui/src/cairo/App.svelte +++ b/packages/ui/src/cairo/App.svelte @@ -120,7 +120,7 @@

Single file

-

Requires installing Scarb with openzeppelin as a dependency.

+

Requires a Scarb project with openzeppelin as a dependency.

From 50b85f55b29a150bb4a34c0fda6fb9fe44be0606 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 22:29:36 -0500 Subject: [PATCH 23/29] Use snake case for default admin --- packages/core-cairo/src/custom.test.ts.md | 4 ++-- packages/core-cairo/src/custom.test.ts.snap | Bin 1131 -> 1132 bytes packages/core-cairo/src/erc20.test.ts.md | 12 ++++++------ packages/core-cairo/src/erc20.test.ts.snap | Bin 2403 -> 2401 bytes packages/core-cairo/src/erc721.test.ts.md | 4 ++-- packages/core-cairo/src/erc721.test.ts.snap | Bin 1982 -> 1984 bytes packages/core-cairo/src/set-access-control.ts | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/core-cairo/src/custom.test.ts.md b/packages/core-cairo/src/custom.test.ts.md index 57644e8b..47234ec1 100644 --- a/packages/core-cairo/src/custom.test.ts.md +++ b/packages/core-cairo/src/custom.test.ts.md @@ -235,10 +235,10 @@ Generated by [AVA](https://avajs.dev). }␊ ␊ #[constructor]␊ - fn constructor(ref self: ContractState, defaultAdmin: ContractAddress) {␊ + fn constructor(ref self: ContractState, default_admin: ContractAddress) {␊ self.accesscontrol.initializer();␊ ␊ - self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin);␊ + self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin);␊ }␊ }␊ ` diff --git a/packages/core-cairo/src/custom.test.ts.snap b/packages/core-cairo/src/custom.test.ts.snap index ee4474cbd12edb6c36eabeb50edfcae57e07e327..bd8639bca8cb61a82b2e80a8e1ef269c4597063c 100644 GIT binary patch delta 152 zcmV;J0B8T}2sn^RmrM^ zqpAhR5A*L>&=KK%H16?q_8ejM9AV1OwX^34qy5~B^Y-jH!t6Q1grJ=H9N{mGPL?6+ G9{>QeNk|C* delta 151 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 T+&z7qdE@^9qr&29%aZ^ANMLyd literal 2403 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 Q#+Rc118yWLhTc{H0RL3ZG5`Po diff --git a/packages/core-cairo/src/set-access-control.ts b/packages/core-cairo/src/set-access-control.ts index 712d4803..26be1e80 100644 --- a/packages/core-cairo/src/set-access-control.ts +++ b/packages/core-cairo/src/set-access-control.ts @@ -24,10 +24,10 @@ export type Access = typeof accessOptions[number]; addSRC5Component(c); c.addStandaloneImport('starknet::ContractAddress'); - c.addConstructorArgument({ name: 'defaultAdmin', type: 'ContractAddress'}); + c.addConstructorArgument({ name: 'default_admin', type: 'ContractAddress'}); c.addStandaloneImport('openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE'); - c.addConstructorCode('self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, defaultAdmin)'); + c.addConstructorCode('self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin)'); } break; } From a8e3d2f6ba9343e370eebca34088cafcf2407215 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Wed, 6 Dec 2023 23:21:15 -0500 Subject: [PATCH 24/29] Improve error handling --- packages/core-cairo/src/erc20.ts | 7 +-- packages/core-cairo/src/erc721.ts | 3 +- packages/core-cairo/src/print.ts | 3 +- .../src/utils/convert-strings.test.ts | 54 ++++++++++++------- .../core-cairo/src/utils/convert-strings.ts | 27 ++++++++-- packages/ui/src/cairo/App.svelte | 7 +-- packages/ui/src/cairo/CustomControls.svelte | 7 ++- packages/ui/src/cairo/ERC20Controls.svelte | 4 +- packages/ui/src/cairo/ERC721Controls.svelte | 9 ++-- 9 files changed, 78 insertions(+), 43 deletions(-) diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 50231b8f..9c65d7f1 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -10,6 +10,7 @@ import { defineComponents } from './utils/define-components'; import { defaults as commonDefaults } from './common-options'; import { printContract } from './print'; import { externalTrait } from './external-trait'; +import { toShortString } from './utils/convert-strings'; export const defaults: Required = { name: 'MyToken', @@ -59,7 +60,7 @@ export function buildERC20(opts: ERC20Options): Contract { const allOpts = withDefaults(opts); - addBase(c, allOpts.name, allOpts.symbol); + addBase(c, toShortString(allOpts.name, 'name'), toShortString(allOpts.symbol, 'symbol')); addERC20ImplAndCamelOnlyImpl(c, allOpts.pausable); if (allOpts.safeAllowance) { @@ -230,9 +231,9 @@ export function getInitialSupply(premint: string, decimals: number): string { try { lastSegment += "0".repeat(decimals - lastSegment.length); } catch (e) { - // .repeat gives an error if number is too large, although this should not happen since decimals is limited to 256 + // .repeat gives an error if decimals number is too large throw new OptionsError({ - decimals: 'Number too large', + premint: 'Decimals number too large', }); } } else if (decimals < lastSegment.length) { diff --git a/packages/core-cairo/src/erc721.ts b/packages/core-cairo/src/erc721.ts index f78da44a..15e5be50 100644 --- a/packages/core-cairo/src/erc721.ts +++ b/packages/core-cairo/src/erc721.ts @@ -10,6 +10,7 @@ import { defaults as commonDefaults } from './common-options'; import { printContract } from './print'; import { addSRC5Component } from './common-components'; import { externalTrait } from './external-trait'; +import { toShortString } from './utils/convert-strings'; export const defaults: Required = { name: 'MyToken', @@ -53,7 +54,7 @@ export function buildERC721(opts: ERC721Options): Contract { const allOpts = withDefaults(opts); - addBase(c, allOpts.name, allOpts.symbol); + addBase(c, toShortString(allOpts.name, 'name'), toShortString(allOpts.symbol, 'symbol')); addERC721ImplAndCamelOnlyImpl(c, allOpts.pausable); if (allOpts.burnable) { diff --git a/packages/core-cairo/src/print.ts b/packages/core-cairo/src/print.ts index 4a40cb88..37e370b7 100644 --- a/packages/core-cairo/src/print.ts +++ b/packages/core-cairo/src/print.ts @@ -1,6 +1,5 @@ import 'array.prototype.flatmap/auto'; -import { toPrintableShortString } from './utils/convert-strings'; import type { Contract, Component, Argument, Value, Impl, ContractFunction, } from './contract'; import { formatLines, spaceBetween, Lines } from './utils/format-lines'; @@ -223,7 +222,7 @@ export function printValue(value: Value): string { throw new Error(`Number not representable (${value})`); } } else { - return `'${toPrintableShortString(value)}'`; + return `'${value}'`; } } diff --git a/packages/core-cairo/src/utils/convert-strings.test.ts b/packages/core-cairo/src/utils/convert-strings.test.ts index 03bb4e68..75aeb7a2 100644 --- a/packages/core-cairo/src/utils/convert-strings.test.ts +++ b/packages/core-cairo/src/utils/convert-strings.test.ts @@ -1,56 +1,70 @@ import test from 'ava'; -import { toIdentifier, toPrintableShortString } from './convert-strings'; +import { toIdentifier, toShortString } from './convert-strings'; +import type { OptionsError } from '../error'; -test('toIdentifier - unmodified', t => { +test('identifier - unmodified', t => { t.is(toIdentifier('abc'), 'abc'); }); -test('toIdentifier - remove leading specials', t => { +test('identifier - remove leading specials', t => { t.is(toIdentifier('--abc'), 'abc'); }); -test('toIdentifier - remove specials and upcase next char', t => { +test('identifier - remove specials and upcase next char', t => { t.is(toIdentifier('abc-def'), 'abcDef'); t.is(toIdentifier('abc--def'), 'abcDef'); }); -test('toIdentifier - capitalize', t => { +test('identifier - capitalize', t => { t.is(toIdentifier('abc', true), 'Abc'); }); -test('toIdentifier - remove accents', t => { +test('identifier - remove accents', t => { t.is(toIdentifier('ábc'), 'abc'); }); -test('toIdentifier - underscores', t => { +test('identifier - underscores', t => { t.is(toIdentifier('_abc_'), '_abc_'); }); -test('toIdentifier - remove starting numbers', t => { +test('identifier - remove starting numbers', t => { t.is(toIdentifier('123abc456'), 'abc456'); }); -test('toPrintableShortString - unmodified', t => { - t.is(toPrintableShortString('abc'), 'abc'); +test('identifier - empty string', t => { + let error: OptionsError | undefined = t.throws(() => toIdentifier('')); + t.is(error?.messages.name, 'Identifier is empty or does not have valid characters'); }); -test('toPrintableShortString - remove accents', t => { - t.is(toPrintableShortString('ábc'), 'abc'); +test('identifier - no valid chars', t => { + let error: OptionsError | undefined = t.throws(() => toIdentifier('123')); + t.is(error?.messages.name, 'Identifier is empty or does not have valid characters'); }); -test('toPrintableShortString - remove non-ascii-printable characters', t => { - t.is(toPrintableShortString('abc😀'), 'abc'); +test('short string - unmodified', t => { + t.is(toShortString('abc', 'foo'), 'abc'); }); -test('toPrintableShortString - escape single quote', t => { - t.is(toPrintableShortString("abc'def"), "abc\\'def"); +test('short string - remove accents', t => { + t.is(toShortString('ábc', 'foo'), 'abc'); }); -test('toPrintableShortString - escape backslash', t => { - t.is(toPrintableShortString('abc\\def'), 'abc\\\\def'); +test('short string - remove non-ascii-printable characters', t => { + t.is(toShortString('abc😀', 'foo'), 'abc'); }); -test('toPrintableShortString - limit to 31 characters', t => { - t.is(toPrintableShortString('A123456789B123456789C123456789D123456789'), 'A123456789B123456789C123456789D'); +test('short string - escape single quote', t => { + t.is(toShortString("abc'def", 'foo'), "abc\\'def"); +}); + +test('short string - escape backslash', t => { + t.is(toShortString('abc\\def', 'foo'), 'abc\\\\def'); +}); + +test('short string - max 31 characters', t => { + t.is(toShortString('A234567890123456789012345678901', 'foo'), 'A234567890123456789012345678901'); + + let error: OptionsError | undefined = t.throws(() => toShortString('A2345678901234567890123456789012', 'foo')); + t.is(error?.messages.foo, 'String is longer than 31 characters'); }); \ No newline at end of file diff --git a/packages/core-cairo/src/utils/convert-strings.ts b/packages/core-cairo/src/utils/convert-strings.ts index e0cceb0a..e0966e9e 100644 --- a/packages/core-cairo/src/utils/convert-strings.ts +++ b/packages/core-cairo/src/utils/convert-strings.ts @@ -1,21 +1,38 @@ +import { OptionsError } from "../error"; + /** * Converts to an identifier according to the rules in https://docs.cairo-lang.org/language_constructs/identifiers.html */ export function toIdentifier(str: string, capitalize = false): string { - return str + const result = str .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents .replace(/^[^a-zA-Z_]+/, '') .replace(/^(.)/, c => capitalize ? c.toUpperCase() : c) .replace(/[^\w]+(.?)/g, (_, c) => c.toUpperCase()); + + if (result.length === 0) { + throw new OptionsError({ + name: 'Identifier is empty or does not have valid characters', + }); + } else { + return result; + } } /** * Converts to a felt252-compatible short string according to the rules in https://docs.cairo-lang.org/language_constructs/literal-expressions.html#short_string_literals */ -export function toPrintableShortString(str: string): string { - return str +export function toShortString(str: string, field: string): string { + const result = str .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents .replace(/[^\x20-\x7E]+/g, '') // remove non-ascii-printable characters - .replace(/(\\|')/g, (_, c) => '\\' + c) // escape backslash or single quote - .slice(0, 31); // limit to 31 characters + .replace(/(\\|')/g, (_, c) => '\\' + c); // escape backslash or single quote + + if (result.length > 31) { + throw new OptionsError({ + [field]: 'String is longer than 31 characters', + }); + } else { + return result; + } } \ No newline at end of file diff --git a/packages/ui/src/cairo/App.svelte b/packages/ui/src/cairo/App.svelte index 07292621..4d042faf 100644 --- a/packages/ui/src/cairo/App.svelte +++ b/packages/ui/src/cairo/App.svelte @@ -133,13 +133,10 @@
- +
-
- +
diff --git a/packages/ui/src/cairo/CustomControls.svelte b/packages/ui/src/cairo/CustomControls.svelte index 6ac1cc43..1770f093 100644 --- a/packages/ui/src/cairo/CustomControls.svelte +++ b/packages/ui/src/cairo/CustomControls.svelte @@ -1,12 +1,13 @@ @@ -22,7 +25,7 @@ diff --git a/packages/ui/src/cairo/ERC20Controls.svelte b/packages/ui/src/cairo/ERC20Controls.svelte index 5ef1fbcc..a6e3e0eb 100644 --- a/packages/ui/src/cairo/ERC20Controls.svelte +++ b/packages/ui/src/cairo/ERC20Controls.svelte @@ -27,12 +27,12 @@
diff --git a/packages/ui/src/cairo/ERC721Controls.svelte b/packages/ui/src/cairo/ERC721Controls.svelte index 4ab8b366..f66fa34e 100644 --- a/packages/ui/src/cairo/ERC721Controls.svelte +++ b/packages/ui/src/cairo/ERC721Controls.svelte @@ -1,12 +1,13 @@ @@ -23,11 +26,11 @@
From 0894e65adc057ab8284c310f166843f79bd08cb7 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Thu, 7 Dec 2023 15:23:21 -0500 Subject: [PATCH 25/29] Make mintable pausable --- packages/core-cairo/src/erc20.test.ts.md | 66 ++++++++++---------- packages/core-cairo/src/erc20.test.ts.snap | Bin 2401 -> 2437 bytes packages/core-cairo/src/erc20.ts | 11 ++-- packages/core-cairo/src/erc721.test.ts.md | 45 ++++++------- packages/core-cairo/src/erc721.test.ts.snap | Bin 1984 -> 2011 bytes packages/core-cairo/src/erc721.ts | 11 ++-- 6 files changed, 71 insertions(+), 62 deletions(-) diff --git a/packages/core-cairo/src/erc20.test.ts.md b/packages/core-cairo/src/erc20.test.ts.md index 8c6a35cb..a0af71ea 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -789,8 +789,8 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::token::erc20::interface;␊ - use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ @@ -798,22 +798,22 @@ Generated by [AVA](https://avajs.dev). use starknet::ClassHash;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ - component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ - impl PausableImpl = PausableComponent::PausableImpl;␊ - #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ #[abi(embed_v0)]␊ impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ - impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -821,10 +821,10 @@ Generated by [AVA](https://avajs.dev). #[substorage(v0)]␊ erc20: ERC20Component::Storage,␊ #[substorage(v0)]␊ - pausable: PausableComponent::Storage,␊ - #[substorage(v0)]␊ ownable: OwnableComponent::Storage,␊ #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ upgradeable: UpgradeableComponent::Storage,␊ }␊ ␊ @@ -834,10 +834,10 @@ Generated by [AVA](https://avajs.dev). #[flat]␊ ERC20Event: ERC20Component::Event,␊ #[flat]␊ - PausableEvent: PausableComponent::Event,␊ - #[flat]␊ OwnableEvent: OwnableComponent::Event,␊ #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ UpgradeableEvent: UpgradeableComponent::Event,␊ }␊ ␊ @@ -934,6 +934,12 @@ Generated by [AVA](https://avajs.dev). #[generate_trait]␊ #[external(v0)]␊ impl ExternalImpl of ExternalTrait {␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + self.ownable.assert_only_owner();␊ + self.pausable.assert_not_paused();␊ + self.erc20._mint(recipient, amount);␊ + }␊ + ␊ fn burn(ref self: ContractState, value: u256) {␊ self.pausable.assert_not_paused();␊ let caller = get_caller_address();␊ @@ -949,11 +955,6 @@ Generated by [AVA](https://avajs.dev). self.ownable.assert_only_owner();␊ self.pausable._unpause();␊ }␊ - ␊ - fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ - self.ownable.assert_only_owner();␊ - self.erc20._mint(recipient, amount);␊ - }␊ }␊ ␊ #[external(v0)]␊ @@ -972,45 +973,45 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - const PAUSER_ROLE: felt252 = selector!("PAUSER_ROLE");␊ const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊ + const PAUSER_ROLE: felt252 = selector!("PAUSER_ROLE");␊ const UPGRADER_ROLE: felt252 = selector!("UPGRADER_ROLE");␊ ␊ #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::token::erc20::interface;␊ - use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ + use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ use starknet::get_caller_address;␊ use starknet::ClassHash;␊ - use super::{PAUSER_ROLE, MINTER_ROLE, UPGRADER_ROLE};␊ + use super::{MINTER_ROLE, PAUSER_ROLE, UPGRADER_ROLE};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ - component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ - impl PausableImpl = PausableComponent::PausableImpl;␊ - #[abi(embed_v0)]␊ impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ #[abi(embed_v0)]␊ impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ - impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -1018,12 +1019,12 @@ Generated by [AVA](https://avajs.dev). #[substorage(v0)]␊ erc20: ERC20Component::Storage,␊ #[substorage(v0)]␊ - pausable: PausableComponent::Storage,␊ - #[substorage(v0)]␊ accesscontrol: AccessControlComponent::Storage,␊ #[substorage(v0)]␊ src5: SRC5Component::Storage,␊ #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ upgradeable: UpgradeableComponent::Storage,␊ }␊ ␊ @@ -1033,12 +1034,12 @@ Generated by [AVA](https://avajs.dev). #[flat]␊ ERC20Event: ERC20Component::Event,␊ #[flat]␊ - PausableEvent: PausableComponent::Event,␊ - #[flat]␊ AccessControlEvent: AccessControlComponent::Event,␊ #[flat]␊ SRC5Event: SRC5Component::Event,␊ #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ UpgradeableEvent: UpgradeableComponent::Event,␊ }␊ ␊ @@ -1047,8 +1048,8 @@ Generated by [AVA](https://avajs.dev). ref self: ContractState,␊ recipient: ContractAddress,␊ default_admin: ContractAddress,␊ - pauser: ContractAddress,␊ minter: ContractAddress,␊ + pauser: ContractAddress,␊ upgrader: ContractAddress,␊ ) {␊ self.erc20.initializer('MyToken', 'MTK');␊ @@ -1056,8 +1057,8 @@ Generated by [AVA](https://avajs.dev). ␊ self.erc20._mint(recipient, 2000000000000000000000);␊ self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin);␊ - self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊ self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ + self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ ␊ @@ -1146,6 +1147,12 @@ Generated by [AVA](https://avajs.dev). #[generate_trait]␊ #[external(v0)]␊ impl ExternalImpl of ExternalTrait {␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + self.accesscontrol.assert_only_role(MINTER_ROLE);␊ + self.pausable.assert_not_paused();␊ + self.erc20._mint(recipient, amount);␊ + }␊ + ␊ fn burn(ref self: ContractState, value: u256) {␊ self.pausable.assert_not_paused();␊ let caller = get_caller_address();␊ @@ -1161,11 +1168,6 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ self.pausable._unpause();␊ }␊ - ␊ - fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ - self.accesscontrol.assert_only_role(MINTER_ROLE);␊ - self.erc20._mint(recipient, amount);␊ - }␊ }␊ ␊ #[external(v0)]␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 0415413dd8d983008fcbe908452572a702f3e19e..8665e15bd0388ed8ed36959d548f33e81164fa25 100644 GIT binary patch literal 2437 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 T+&z7qdE@^9qr&29%aZ^ANMLyd diff --git a/packages/core-cairo/src/erc20.ts b/packages/core-cairo/src/erc20.ts index 9c65d7f1..3564e37c 100644 --- a/packages/core-cairo/src/erc20.ts +++ b/packages/core-cairo/src/erc20.ts @@ -71,6 +71,10 @@ export function buildERC20(opts: ERC20Options): Contract { addPremint(c, allOpts.premint); } + if (allOpts.mintable) { + addMintable(c, allOpts.access); + } + if (allOpts.burnable) { addBurnable(c); } @@ -80,10 +84,9 @@ export function buildERC20(opts: ERC20Options): Contract { if (allOpts.burnable) { setPausable(c, externalTrait, functions.burn); } - } - - if (allOpts.mintable) { - addMintable(c, allOpts.access); + if (allOpts.mintable) { + setPausable(c, externalTrait, functions.mint); + } } setAccessControl(c, allOpts.access); diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index cf8072e5..1b8c0f8f 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -474,18 +474,18 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc721::ERC721Component;␊ use openzeppelin::token::erc721::interface;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ + use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ - use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ + use starknet::get_caller_address;␊ use starknet::ClassHash;␊ ␊ component!(path: ERC721Component, storage: erc721, event: ERC721Event);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ - component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ #[abi(embed_v0)]␊ @@ -495,15 +495,15 @@ Generated by [AVA](https://avajs.dev). #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ #[abi(embed_v0)]␊ - impl PausableImpl = PausableComponent::PausableImpl;␊ - #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ #[abi(embed_v0)]␊ impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ + #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ ␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ - impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ + impl PausableInternalImpl = PausableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -513,10 +513,10 @@ Generated by [AVA](https://avajs.dev). #[substorage(v0)]␊ src5: SRC5Component::Storage,␊ #[substorage(v0)]␊ - pausable: PausableComponent::Storage,␊ - #[substorage(v0)]␊ ownable: OwnableComponent::Storage,␊ #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ upgradeable: UpgradeableComponent::Storage,␊ }␊ ␊ @@ -528,10 +528,10 @@ Generated by [AVA](https://avajs.dev). #[flat]␊ SRC5Event: SRC5Component::Event,␊ #[flat]␊ - PausableEvent: PausableComponent::Event,␊ - #[flat]␊ OwnableEvent: OwnableComponent::Event,␊ #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ UpgradeableEvent: UpgradeableComponent::Event,␊ }␊ ␊ @@ -639,6 +639,19 @@ Generated by [AVA](https://avajs.dev). #[generate_trait]␊ #[external(v0)]␊ impl ExternalImpl of ExternalTrait {␊ + fn safe_mint(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + token_uri: felt252,␊ + ) {␊ + self.ownable.assert_only_owner();␊ + self.pausable.assert_not_paused();␊ + self.erc721._safe_mint(recipient, token_id, data);␊ + self.erc721._set_token_uri(token_id, token_uri);␊ + }␊ + ␊ fn burn(ref self: ContractState, token_id: u256) {␊ self.pausable.assert_not_paused();␊ let caller = get_caller_address();␊ @@ -655,18 +668,6 @@ Generated by [AVA](https://avajs.dev). self.ownable.assert_only_owner();␊ self.pausable._unpause();␊ }␊ - ␊ - fn safe_mint(␊ - ref self: ContractState,␊ - recipient: ContractAddress,␊ - token_id: u256,␊ - data: Span,␊ - token_uri: felt252,␊ - ) {␊ - self.ownable.assert_only_owner();␊ - self.erc721._safe_mint(recipient, token_id, data);␊ - self.erc721._set_token_uri(token_id, token_uri);␊ - }␊ }␊ ␊ #[external(v0)]␊ diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index aeb98c53809e6944be80a02bd7e1038e3580ecdb..1115ea6a226723ae8c7e348bdb3f58e74c0a9603 100644 GIT binary patch literal 2011 zcmV<12PF7GRzV`itYDUlK>QSz6PI@+QA#YYkXlU%d@1tWF7#~&* z`iUcGpb!S9FbtvZ1(rqFQ_F(b`ElcW%i7uBqQAG$C`193@u-5zqasigLWg*WUPjp2 zw5)^utxbtCA$7#{9Ww;v$TA87Iz~hg28YlxQWZJ|JfZi+z#Vq6{z%VD5h!tD>STP_ zAi*VJbMG}6cqSYT;Ltw#Zv9Pi(;J087r6@wVAIfJw|*)rEFh9cJ>KGw9}qy`lSfmD z*#aZz?*;z*@v^d^GYhS^X=b()*f5XoYzn#N%9N)|PRp=lct9WyfL{fG{9MnBZLws1 zrHVxa#||+L(tCV+@p18h4>dD8*oW`2vT)9%GXalerCc3^$@+i8FNP3%C(zu+ zC}bN&_=c>)$5l&gSfg#;9 zF?5Xx`mSXt^R+H%&mKQWVSnHS9`S(hokDD`aj&@6G1hkbzpQZwbGCZ6%3br(Ag0S< z;KQ&k? z%l_8nHi!?1B8Z78BVc=x4Z;wk6S~6?w$WQ^rJ1tHrLT81^NKOTk!8Jl(S6l_wzuE= zeP_EMPZ5;ZnK8@@2>W?;_ejq@%}c(!9^=d3_kC!!wnMzfkSv?@0Z#FOz8XsPVV zCSRSLtDZjd**Zw4;3FKk2Ffdy0qO`9Ppt)V3kw=(1ML_|W|iONL3EDHG$Y|_ zK%q&b6;s%%WHm1XX{wr~EOaxbPYV06kiG&R1P-*3Yo=!ZT(Fy_8YpJ?mMp*jBuQ!u zIjxL>#GJEPm-0qgjl|w+C5mY@6&(tY|-na4^%Z% zkf_bDuhCT}J`t4jl{J_29}~9JELt1CvLTZMvb{#**pvaRQg|}Ey(yQ88n=42VXMzw z(9=)sXnUU~W{nS4y-8!$;vv`sKx43}^YUHpLZ2esT^JYNfN$?k;M%9%vSpWEy=}cn zXuy%Z2zNe@A3v`SdNR$EwEi|R~+7mDQ1 z_}0M4hfz5Ry!n@s1fJd;n*=5cn|^)K-`ThK_nz-$_)(upb%$)p-!bn>BkrF-2W=dvv zz6x2Jxwe_B%urbzoU?wN6?X8vvJw=g5ttENP*$s2tFo+8cv&)B)hk!Rapkk!vTLmd zqtVQF2wf2S#0Eo}qi9-_qvRdVxunL*+$)qKtW*rO4>1Uc%`z#o9LEbb)k~FGNwHkm z-6rV@@f1nA3bUN57qMR0q}`2u--tuHLWWS^xxM|hlC-bfUbxQf#hrnkqSM>p;b}fS z?Cg6!QBzRKZ>S{>)71jCe`cj&`P3gU7YciNZMLv zc{|zlvgSP2em(_7BW?1si47eum-bbGrEZfhPpLC$GryioQ-{?hkEr*aOHg!8@rpr5 zKKGgTVg#z1h^zLhqdoiHo_%l6zPD%J+q3WO+4uJBdwcd>?8Nr$dwcf1J^S9CeZQn< z->=?FoEZ^mMM($4YUex@||YW#B`8NBunJ%lonN|jzj?ul|oBEN2`O$d3X tu6m^g@U88zcS`mVh>qxE@qVcR+od)kHJ@vu3e>(s{U2e?jI0k=000lC@h|`Y literal 1984 zcmV;x2S4~hRzV?s4`8+Z*f+b{r{@6e&^iN1W77C;ba0m$aVtM~6) zdoMPBzWXfjV3feSy&;T9;0F*p)^@MIvU2BDLI6IDAaNWIMFaznyj~fhp|$<4j}BpE zy# znPBgM`bGu0qFxNA$iJxWz8k9-4V+0u@e7 z9m$6c5?nGicV2-(V8hV>4&9?~)?Q~fgHarEk=u{}HVr*?>xZ(!0wQ(PqYV!E9svYC zemIqw4KRY?P87ZyFG~)cS!lCOGqat*hSTWIrjTo{O?mEeMuru`BLZ;*!a4xd=VoSX ziDmwkE0z$Pdc@kx@A2iu$E5>4)RuOz4_{+d;hafl0v_2)tDvCLp9pm`|9{Odh7bow z(B8x-W(!5cihN<@gJ6`7tn7wnjUNJ1$X8aS!I12JrX?^xP=ttr~G$MAaE*K6mOp-Q+w=ukp;cX0Gt{Bcm@52aU z%FCr}1BoGgoBN1eS^{qs*FwI$?lW3N8LB=@40U>UtSn%=!O*eN^#|XncCb$fiIs;~ z>c7=^YjYdK2P6r^#8we-gTw`KjL{KYVF(I)-`07~#ZmUOw->>_6Sv z?fts7S(2v-%IuU3i-9MVR2hRbF{jF#UumiG=FNpml_jcxg%BTja2}~ur%a%i;()w! z9D$ePyx`x)5(Cep{^2-ux^v2%{7Yj(7p~b|;B0Q>Qh`O`B*2s0#NbAbWw;cE98$@T z4{ghhSyFa0LorpHX=R#=1u+A2K5v|NdBWw2nVqu+Ws`_z%;#FwRH43*jumLf$||ekE>EJTs7xgZ z_W_M2lU6Qa>x$K)4Wy;2ELrGc%%7CjVX1rtA&5NaBHzx<{;^~?Ej3We@U2*W_iLIsv4QS^-7e>Xezp-PJV@KrTe^dFP9^eWnzzvPff64}mN^VpOLtX6n7yS*vhM9*8j#4B4xpjap3@#@L7d{ivG{;7?b38*nmF@N;2^DP*!!%K({4a&Y8Q0!UQ_WG zi{j7v+QKM=Nwo;P@rPCf9^V*S1ZIv+zdrA8?Yg@=&$c9fG-guWA#?dJ?c2(T+pN-9 zzTz?eo#~1~$LVI58~Np|Og6WkbYDK}yWLHSPX^9Jm8cw&(hkdU-YejqEKi+kMo?j= zfhGBBWNqczR<0^T%{e${v!9h#@M&dbC`=({q z<-+c^NY{v`DAIM9)l$8T^}-hIej0{W8dDD$Li5h;t$($m{hwP4w{v^(&Oqyge0tc~ z_hO=^pi;H4`i`L(64K@H6eI`B(=aU3scj=W)9foOl~pX+DkN<$(;f(4 zqHXepJPb}Ppfm@$IP3#C=t;dJugAib)JXTP2}YaR5uY9?Nvv6_Pss( z-kyDL&%U>3-`lhA?b-MC?7LWr?b-MC?0b9my*>NBq-Wnx^WS5p^qq_G&t_Ec+CLmH zDRc4O3ogy!z2>l>ZgTR-puRt9tnm2OTYadA;2YOtFNxd(kQ~s*;)T&15LNd5sQ+ Date: Thu, 7 Dec 2023 15:31:22 -0500 Subject: [PATCH 26/29] Update changelog --- packages/core-cairo/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/core-cairo/CHANGELOG.md b/packages/core-cairo/CHANGELOG.md index 52057a38..7d6cb218 100644 --- a/packages/core-cairo/CHANGELOG.md +++ b/packages/core-cairo/CHANGELOG.md @@ -7,6 +7,8 @@ - Remove functions for `getInitialSupply` and `toUint256`. - Remove ERC1155. - Role-Based Access Control adds separate constructor arguments to assign different users for different roles. + - Throws error if `name` results in an identifer that is empty or does not have valid characters. + - Throws error if `name` or `symbol` result in strings longer than 31 characters. ## 0.6.0 (2023-01-11) From f1f70856e4ce087a3a5d56f3aa87d096eb755688 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Thu, 7 Dec 2023 16:34:06 -0500 Subject: [PATCH 27/29] Add safeMint --- packages/core-cairo/src/erc721.test.ts.md | 30 ++++++++++++++++++++ packages/core-cairo/src/erc721.test.ts.snap | Bin 2011 -> 2032 bytes packages/core-cairo/src/erc721.ts | 15 ++++++++++ 3 files changed, 45 insertions(+) diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index 1b8c0f8f..3506911e 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -372,6 +372,16 @@ Generated by [AVA](https://avajs.dev). self.erc721._safe_mint(recipient, token_id, data);␊ self.erc721._set_token_uri(token_id, token_uri);␊ }␊ + ␊ + fn safeMint(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + token_uri: felt252,␊ + ) {␊ + self.safe_mint(recipient, token_id, data, token_uri);␊ + }␊ }␊ }␊ ` @@ -459,6 +469,16 @@ Generated by [AVA](https://avajs.dev). self.erc721._safe_mint(recipient, token_id, data);␊ self.erc721._set_token_uri(token_id, token_uri);␊ }␊ + ␊ + fn safeMint(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + token_uri: felt252,␊ + ) {␊ + self.safe_mint(recipient, token_id, data, token_uri);␊ + }␊ }␊ }␊ ` @@ -651,6 +671,16 @@ Generated by [AVA](https://avajs.dev). self.erc721._safe_mint(recipient, token_id, data);␊ self.erc721._set_token_uri(token_id, token_uri);␊ }␊ + ␊ + fn safeMint(␊ + ref self: ContractState,␊ + recipient: ContractAddress,␊ + token_id: u256,␊ + data: Span,␊ + token_uri: felt252,␊ + ) {␊ + self.safe_mint(recipient, token_id, data, token_uri);␊ + }␊ ␊ fn burn(ref self: ContractState, token_id: u256) {␊ self.pausable.assert_not_paused();␊ diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index 1115ea6a226723ae8c7e348bdb3f58e74c0a9603..1a4e46c80c0a873502e0d7c79fcf420950179d8b 100644 GIT binary patch literal 2032 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 diff --git a/packages/core-cairo/src/erc721.ts b/packages/core-cairo/src/erc721.ts index 1e756b88..4a7e8bbf 100644 --- a/packages/core-cairo/src/erc721.ts +++ b/packages/core-cairo/src/erc721.ts @@ -151,6 +151,9 @@ function addBurnable(c: ContractBuilder) { function addMintable(c: ContractBuilder, access: Access) { c.addStandaloneImport('starknet::ContractAddress'); requireAccessControl(c, externalTrait, functions.safe_mint, access, 'MINTER', 'minter'); + + // Camel case version of safe_mint. Access control and pausable are already set on safe_mint. + c.addFunction(externalTrait, functions.safeMint); } const components = defineComponents( { @@ -206,6 +209,18 @@ const functions = defineFunctions({ 'self.erc721._set_token_uri(token_id, token_uri);', ] }, + safeMint: { + args: [ + getSelfArg(), + { name: 'recipient', type: 'ContractAddress' }, + { name: 'token_id', type: 'u256' }, + { name: 'data', type: 'Span' }, + { name: 'token_uri', type: 'felt252' }, + ], + code: [ + 'self.safe_mint(recipient, token_id, data, token_uri);', + ] + }, // Re-implements ERC721Impl balance_of: { From 8324fcf8a4314e1fb43b2c29848636002b80d29a Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Thu, 7 Dec 2023 16:41:37 -0500 Subject: [PATCH 28/29] Reorder functions to make output more stable --- packages/core-cairo/src/erc20.test.ts.md | 102 ++++++++++---------- packages/core-cairo/src/erc20.test.ts.snap | Bin 2437 -> 2408 bytes packages/core-cairo/src/erc20.ts | 16 +-- packages/core-cairo/src/erc721.test.ts.md | 52 +++++----- packages/core-cairo/src/erc721.test.ts.snap | Bin 2032 -> 2004 bytes packages/core-cairo/src/erc721.ts | 16 +-- 6 files changed, 93 insertions(+), 93 deletions(-) diff --git a/packages/core-cairo/src/erc20.test.ts.md b/packages/core-cairo/src/erc20.test.ts.md index a0af71ea..f9ce8e88 100644 --- a/packages/core-cairo/src/erc20.test.ts.md +++ b/packages/core-cairo/src/erc20.test.ts.md @@ -383,8 +383,8 @@ Generated by [AVA](https://avajs.dev). use openzeppelin::token::erc20::interface;␊ use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::ownable::OwnableComponent;␊ - use starknet::get_caller_address;␊ use starknet::ContractAddress;␊ + use starknet::get_caller_address;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ @@ -489,12 +489,6 @@ Generated by [AVA](https://avajs.dev). #[generate_trait]␊ #[external(v0)]␊ impl ExternalImpl of ExternalTrait {␊ - fn burn(ref self: ContractState, value: u256) {␊ - self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._burn(caller, value);␊ - }␊ - ␊ fn pause(ref self: ContractState) {␊ self.ownable.assert_only_owner();␊ self.pausable._pause();␊ @@ -504,6 +498,12 @@ Generated by [AVA](https://avajs.dev). self.ownable.assert_only_owner();␊ self.pausable._unpause();␊ }␊ + ␊ + fn burn(ref self: ContractState, value: u256) {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._burn(caller, value);␊ + }␊ }␊ }␊ ` @@ -789,8 +789,8 @@ Generated by [AVA](https://avajs.dev). mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::token::erc20::interface;␊ - use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::security::pausable::PausableComponent;␊ + use openzeppelin::access::ownable::OwnableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ @@ -798,22 +798,22 @@ Generated by [AVA](https://avajs.dev). use starknet::ClassHash;␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ - component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ + component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ #[abi(embed_v0)]␊ impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ - #[abi(embed_v0)]␊ - impl PausableImpl = PausableComponent::PausableImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ - impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -821,10 +821,10 @@ Generated by [AVA](https://avajs.dev). #[substorage(v0)]␊ erc20: ERC20Component::Storage,␊ #[substorage(v0)]␊ - ownable: OwnableComponent::Storage,␊ - #[substorage(v0)]␊ pausable: PausableComponent::Storage,␊ #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + #[substorage(v0)]␊ upgradeable: UpgradeableComponent::Storage,␊ }␊ ␊ @@ -834,10 +834,10 @@ Generated by [AVA](https://avajs.dev). #[flat]␊ ERC20Event: ERC20Component::Event,␊ #[flat]␊ - OwnableEvent: OwnableComponent::Event,␊ - #[flat]␊ PausableEvent: PausableComponent::Event,␊ #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + #[flat]␊ UpgradeableEvent: UpgradeableComponent::Event,␊ }␊ ␊ @@ -934,10 +934,14 @@ Generated by [AVA](https://avajs.dev). #[generate_trait]␊ #[external(v0)]␊ impl ExternalImpl of ExternalTrait {␊ - fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + fn pause(ref self: ContractState) {␊ self.ownable.assert_only_owner();␊ - self.pausable.assert_not_paused();␊ - self.erc20._mint(recipient, amount);␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ }␊ ␊ fn burn(ref self: ContractState, value: u256) {␊ @@ -946,14 +950,10 @@ Generated by [AVA](https://avajs.dev). self.erc20._burn(caller, value);␊ }␊ ␊ - fn pause(ref self: ContractState) {␊ - self.ownable.assert_only_owner();␊ - self.pausable._pause();␊ - }␊ - ␊ - fn unpause(ref self: ContractState) {␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ self.ownable.assert_only_owner();␊ - self.pausable._unpause();␊ + self.pausable.assert_not_paused();␊ + self.erc20._mint(recipient, amount);␊ }␊ }␊ ␊ @@ -973,45 +973,45 @@ Generated by [AVA](https://avajs.dev). `// SPDX-License-Identifier: MIT␊ ␊ - const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊ const PAUSER_ROLE: felt252 = selector!("PAUSER_ROLE");␊ + const MINTER_ROLE: felt252 = selector!("MINTER_ROLE");␊ const UPGRADER_ROLE: felt252 = selector!("UPGRADER_ROLE");␊ ␊ #[starknet::contract]␊ mod MyToken {␊ use openzeppelin::token::erc20::ERC20Component;␊ use openzeppelin::token::erc20::interface;␊ + use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::access::accesscontrol::AccessControlComponent;␊ use openzeppelin::introspection::src5::SRC5Component;␊ - use openzeppelin::security::pausable::PausableComponent;␊ use openzeppelin::upgrades::UpgradeableComponent;␊ use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE;␊ use openzeppelin::upgrades::interface::IUpgradeable;␊ use starknet::ContractAddress;␊ use starknet::get_caller_address;␊ use starknet::ClassHash;␊ - use super::{MINTER_ROLE, PAUSER_ROLE, UPGRADER_ROLE};␊ + use super::{PAUSER_ROLE, MINTER_ROLE, UPGRADER_ROLE};␊ ␊ component!(path: ERC20Component, storage: erc20, event: ERC20Event);␊ + component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);␊ component!(path: SRC5Component, storage: src5, event: SRC5Event);␊ - component!(path: PausableComponent, storage: pausable, event: PausableEvent);␊ component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);␊ ␊ #[abi(embed_v0)]␊ impl ERC20MetadataImpl = ERC20Component::ERC20MetadataImpl;␊ #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ impl AccessControlImpl = AccessControlComponent::AccessControlImpl;␊ #[abi(embed_v0)]␊ impl AccessControlCamelImpl = AccessControlComponent::AccessControlCamelImpl;␊ #[abi(embed_v0)]␊ impl SRC5Impl = SRC5Component::SRC5Impl;␊ - #[abi(embed_v0)]␊ - impl PausableImpl = PausableComponent::PausableImpl;␊ ␊ impl ERC20InternalImpl = ERC20Component::InternalImpl;␊ - impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl AccessControlInternalImpl = AccessControlComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -1019,12 +1019,12 @@ Generated by [AVA](https://avajs.dev). #[substorage(v0)]␊ erc20: ERC20Component::Storage,␊ #[substorage(v0)]␊ + pausable: PausableComponent::Storage,␊ + #[substorage(v0)]␊ accesscontrol: AccessControlComponent::Storage,␊ #[substorage(v0)]␊ src5: SRC5Component::Storage,␊ #[substorage(v0)]␊ - pausable: PausableComponent::Storage,␊ - #[substorage(v0)]␊ upgradeable: UpgradeableComponent::Storage,␊ }␊ ␊ @@ -1034,12 +1034,12 @@ Generated by [AVA](https://avajs.dev). #[flat]␊ ERC20Event: ERC20Component::Event,␊ #[flat]␊ + PausableEvent: PausableComponent::Event,␊ + #[flat]␊ AccessControlEvent: AccessControlComponent::Event,␊ #[flat]␊ SRC5Event: SRC5Component::Event,␊ #[flat]␊ - PausableEvent: PausableComponent::Event,␊ - #[flat]␊ UpgradeableEvent: UpgradeableComponent::Event,␊ }␊ ␊ @@ -1048,8 +1048,8 @@ Generated by [AVA](https://avajs.dev). ref self: ContractState,␊ recipient: ContractAddress,␊ default_admin: ContractAddress,␊ - minter: ContractAddress,␊ pauser: ContractAddress,␊ + minter: ContractAddress,␊ upgrader: ContractAddress,␊ ) {␊ self.erc20.initializer('MyToken', 'MTK');␊ @@ -1057,8 +1057,8 @@ Generated by [AVA](https://avajs.dev). ␊ self.erc20._mint(recipient, 2000000000000000000000);␊ self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin);␊ - self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ self.accesscontrol._grant_role(PAUSER_ROLE, pauser);␊ + self.accesscontrol._grant_role(MINTER_ROLE, minter);␊ self.accesscontrol._grant_role(UPGRADER_ROLE, upgrader);␊ }␊ ␊ @@ -1147,18 +1147,6 @@ Generated by [AVA](https://avajs.dev). #[generate_trait]␊ #[external(v0)]␊ impl ExternalImpl of ExternalTrait {␊ - fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ - self.accesscontrol.assert_only_role(MINTER_ROLE);␊ - self.pausable.assert_not_paused();␊ - self.erc20._mint(recipient, amount);␊ - }␊ - ␊ - fn burn(ref self: ContractState, value: u256) {␊ - self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - self.erc20._burn(caller, value);␊ - }␊ - ␊ fn pause(ref self: ContractState) {␊ self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ self.pausable._pause();␊ @@ -1168,6 +1156,18 @@ Generated by [AVA](https://avajs.dev). self.accesscontrol.assert_only_role(PAUSER_ROLE);␊ self.pausable._unpause();␊ }␊ + ␊ + fn burn(ref self: ContractState, value: u256) {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + self.erc20._burn(caller, value);␊ + }␊ + ␊ + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) {␊ + self.accesscontrol.assert_only_role(MINTER_ROLE);␊ + self.pausable.assert_not_paused();␊ + self.erc20._mint(recipient, amount);␊ + }␊ }␊ ␊ #[external(v0)]␊ diff --git a/packages/core-cairo/src/erc20.test.ts.snap b/packages/core-cairo/src/erc20.test.ts.snap index 8665e15bd0388ed8ed36959d548f33e81164fa25..becbd01c4f07977fd6b56be5ca21e26870bb9066 100644 GIT binary patch literal 2408 zcmV-u377UkRzV-4?)BN^3K2IHR5+5v{4E! z*_tT1kspf)00000000B+9m{UpMlfws1kfdEdue(InB-s?P!iXGi-Ku`3bvCPjbp=) zphXc7D{^HMrbvQZ`jOO!o_gsY^pqa^2mOQoML(cGZ@u)?U2;k7l1qxB9;T$#C6=^1 zubr74&O>?E?O2X};{Wm+L?*J}NeB3*u0T&;T`_$dxc;$&{GZ+#20-BZ>%U*WcJmr} zz4yVj58waw`s2sS{_e(i4_}x%w0-z+%YZgAyC(EhWqa$O(RlEKkAQb#L!_#@VFdrcRhV^!f-wG~)}_ovtju4nH(| zt`)7_h6oS=Y>`jCN}-{|v1`6ur>yQHfZ)?7WpEV1t_pJ<^q{q4TNg#ZxkVW)X)0|5 zJsVg#0NJm_pol_*hZ521BQMaAvLAg$m4U7cI&^6>VU4^ZjmV&;AX?$N%NSXB;;-o& z1A68uY;JgtOLQaF%SaQVMbHjRR`lHY-$A{h?zfTqd%5cNLig`}J#fu9ernzJQQb{E6=+YWp z8Zn0yd`3F`U}1W~`6T(p(*FhXez0KmEwkr>7pNwkQ#$vu|x+0`SAWCuM*Zcm6T9g5@y z9ZBqqBaY;j!`2Xfk+K6m2tf`4mgWbpYh5%WuD?zNP!FGmQAjEXVOZs0EHmK*7wrHG z*gDjlt`JR2!S|;VkWp@%fvK^plC8U^tqLmMR_ z#yE%@t?N0xCI>fI~xdP$VvBK$pGdVFuOh+s*$2Lf2z;!(bd*)mP$kWD2 zAAd|3#V_K6;ilMK@xhD8ZzU@RJFxwV{%aV|wKG=7Ro-RA%Jgg@45)(Xa4I*chxL%; zGD(JnllW4nd^=c?weSWI@|}n&5>AtQEN2M`?CFsb<0{G#oZsP-1j?C-jup?bpr6eb ze0+n;7ySFtzye*2Ldt4GVI26WIBW(PhZ2&414QqRnc#3K5HMoIMCV~+gmTgV)WM)ie#%AcjUS`G=nHiIrvFeI8KbbN9qGyv*>DzwlnX++_Rwi?H#`hBz zwAtMLhfACNbz8RCjM!$AT{77QNg*KFj3b+IW-)amn{i|_jtGEk#*rxpnR1XRhq^p5 z$&`a4Qw}oaP+igHC*?4&%{ZKCRGlXpQZ=SFe&o>3A`kY6KQaUpmrGn?-SZPAE7V8hqW1sh_!?#9>4``AHl(H#1ieiyX?C zQg}4KLo{;uWv*ve!i4@p%&su^Xw3E;gqZ{SWErN%8g`;6>hwVu_Pa*}WuYIrfU|dX zWg(fttwlhxj}@jJ>q`!j%$iYfuz^S+qWl14jPb%0Z}nQ-p|!|KpGLl_8(5YSxcEje zpg1>u=V#7ao!_ZhZn~!3{rpBMVZ8OQFY6(8u?$(`iv_~U~p)gKB>@eyWiioyObI?Mx zJ?%O3q&cO&pew5Mh+t zVP?-*Zfet?SIOs=ud5at1)I~NcEP5`3*9Kq)#MA&hG&{i^55Dq@Q?A=aV~reQezTD zSam5SJi@}>#(Uz*O<|AY-DR$b^Xc75{jzz**2rkv;qLRj_D1nWZjJmc^+|ScRx4Un z==-c`)hqcj`|Iy5g=?JQlv4gO{5U#Xg-~Q2PWHFfsK2%LKRPcAmSh324&A)P`(-gP zen0KzV$sG)RwNT71M{+F(yap;n>ouV%qd9n{{(l6N*qq;_ zU1BpAo3@g3lSN`#B$h?u8LDx~BC#Ti#Ii_SUD0HbSQd$8kysXqWsz9^pC|&-WD&U@ a)3>syTuO@EWBoYG%>M(kps=_plmGyf4U>of literal 2437 zcmV;033~QHRzVP)3)wgh5|feZPoG}z2~2}(EsV3Y3fk_{`&9Nuid{VqU|Wu=Li|=$14>kNYky;Hb;IrUTnAxz zvJ^}*qVM+_JsqB?3OlN)_|WzAW1xooG!<}$9+P2P`0o`0>A??r+iHMr8<^VJ>dNcj zq1El#;n*Djbu55w{N$?y8bTaB=F1Jj>H*Xtc>1IW4iW5OVQ%PMVDCEir3g4PD1{|S zr2~QI=ynD``ZXUER)}CxLRx+3^$n;TgwKdFka7Js8QO?h!=F$iQm6@tW-#t5LKdv} zYx2beo^=Kqo1WXlx)JGRs0ra9;Pksn@PMJEW9x80!9ah~WCV{BL?Fcv`EMNP_Vgb&rnaY}IRog&0BVMA+rZOw)AWGv%bhQGzTEkuolh_y6pwE$;0oS>ivUu9Ulp5FKQ7Vp-7jK%x=*3>PYXpV(9R!28L)^Hyfeb0iI zsv5DZs(a+GTwJ%tRA2{@6d;RvFBCpm8_V_~?`$N@l`6rLC=^dy>C-1re9HOGY-eg;f| z|47kBNQf}zaieuSx7%RgX7QIm&Xs#J0Vz`;%s5&&gE!+7Q^<740<~;;GShoK&qbCw zQvtHHaoo!v5k~Oy_@KBEn=96N;n}TtM7{w#7}9=~v0S^A8m{6dD^jLs3$cNQ*gA~L zjq9==kX$6l5OWe8>V$6>DY6!v09?LfF@?fuFxPULkiIiHQX*WU7{SFIHb|hHTku5j zTpRf5c)`avn0UdzALYgi0>@0*YaJbI?Q8qHFSb;r18lgqzJ~mNL@vNC+r7qpYQ%kf zx19etL-=pNn`^6TEBLw*e$549;bF*(8_;qwL7uUW?hN}I>%*eo+eRxn!#WQe-S9KjMQS-%rqeaW{D`ccmZQ@c+jE*Ss2j~4E$9{ zY>`oM1>Q*+gzB1LH% zn=R5DP_cbY$+FULlLAYxla#$;qnM#g67VlN|Oij0iO$k_0THb0Ru_MoSOQpwYP;*qkdNGlRK zJ7?<&1!Xq3|6#&rf8Ca4Hs#7}c-4>TQL-3ke&a;47)KW4$YLB>j3bM2WXM5=9AwBr zh8$$bA;v624zm?<7`k(&q!7l}Xfs*>WkE`dTvA!&fiAX3Ca2?anF)-1Qm2l~F-8+= za9Nk_ma^Tlq(3~|-HbOy!}fr7dp}#{ebO!59%E7PDI7bs$u3+1Pd17A6NW>xUVBelt;dgXSmZO ztW%)tCpvM3T|Y}L=I~uxD%kb2v;Fc=-1S3^m_pajTzBG7q8)!Hj_jM6E00AsXLe<6BTsB<)8dk);poH|*G=}O&B70bElwDz40Ff}ldo+-BiCJ{P69u8%)wyiHfsGE%Z*>2p#*uq2 zxau1hc#B2>rS?w@mzq+eGjdjf^T{pjanmX(W~*uHCKIJ z715rN*c&X|n0PFvH7Q0JrJ2E`+K|0eW%gr{oEvk<%1*mE?z9tc3Oc4m_5~dp7n)HL ztI1X!2b^mLj(=+>x_^RRN3rk13}h56A}MkyDu9+eA4=HX-s zYMByLF~Axo{VK0-O*1PKfHkYa70;K+#3|PX^Cs3hBN-#fjms7Zx8@W!$Kx^zoSTdy z3kMJl%^EVOQhlSyKkB$i3y8Om|VB(Wls#4<@d zyrRh@u}l)nB(Y2q%Or7aJ1=F@cmhe|#s2?o#G9x_N#z__FxUDj)6D+^G;␊ #[abi(embed_v0)]␊ + impl PausableImpl = PausableComponent::PausableImpl;␊ + #[abi(embed_v0)]␊ impl OwnableImpl = OwnableComponent::OwnableImpl;␊ #[abi(embed_v0)]␊ impl OwnableCamelOnlyImpl = OwnableComponent::OwnableCamelOnlyImpl;␊ - #[abi(embed_v0)]␊ - impl PausableImpl = PausableComponent::PausableImpl;␊ ␊ impl ERC721InternalImpl = ERC721Component::InternalImpl;␊ - impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl PausableInternalImpl = PausableComponent::InternalImpl;␊ + impl OwnableInternalImpl = OwnableComponent::InternalImpl;␊ impl UpgradeableInternalImpl = UpgradeableComponent::InternalImpl;␊ ␊ #[storage]␊ @@ -533,10 +533,10 @@ Generated by [AVA](https://avajs.dev). #[substorage(v0)]␊ src5: SRC5Component::Storage,␊ #[substorage(v0)]␊ - ownable: OwnableComponent::Storage,␊ - #[substorage(v0)]␊ pausable: PausableComponent::Storage,␊ #[substorage(v0)]␊ + ownable: OwnableComponent::Storage,␊ + #[substorage(v0)]␊ upgradeable: UpgradeableComponent::Storage,␊ }␊ ␊ @@ -548,10 +548,10 @@ Generated by [AVA](https://avajs.dev). #[flat]␊ SRC5Event: SRC5Component::Event,␊ #[flat]␊ - OwnableEvent: OwnableComponent::Event,␊ - #[flat]␊ PausableEvent: PausableComponent::Event,␊ #[flat]␊ + OwnableEvent: OwnableComponent::Event,␊ + #[flat]␊ UpgradeableEvent: UpgradeableComponent::Event,␊ }␊ ␊ @@ -659,6 +659,23 @@ Generated by [AVA](https://avajs.dev). #[generate_trait]␊ #[external(v0)]␊ impl ExternalImpl of ExternalTrait {␊ + fn pause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._pause();␊ + }␊ + ␊ + fn unpause(ref self: ContractState) {␊ + self.ownable.assert_only_owner();␊ + self.pausable._unpause();␊ + }␊ + ␊ + fn burn(ref self: ContractState, token_id: u256) {␊ + self.pausable.assert_not_paused();␊ + let caller = get_caller_address();␊ + assert(self.erc721._is_approved_or_owner(caller, token_id), ERC721Component::Errors::UNAUTHORIZED);␊ + self.erc721._burn(token_id);␊ + }␊ + ␊ fn safe_mint(␊ ref self: ContractState,␊ recipient: ContractAddress,␊ @@ -681,23 +698,6 @@ Generated by [AVA](https://avajs.dev). ) {␊ self.safe_mint(recipient, token_id, data, token_uri);␊ }␊ - ␊ - fn burn(ref self: ContractState, token_id: u256) {␊ - self.pausable.assert_not_paused();␊ - let caller = get_caller_address();␊ - assert(self.erc721._is_approved_or_owner(caller, token_id), ERC721Component::Errors::UNAUTHORIZED);␊ - self.erc721._burn(token_id);␊ - }␊ - ␊ - fn pause(ref self: ContractState) {␊ - self.ownable.assert_only_owner();␊ - self.pausable._pause();␊ - }␊ - ␊ - fn unpause(ref self: ContractState) {␊ - self.ownable.assert_only_owner();␊ - self.pausable._unpause();␊ - }␊ }␊ ␊ #[external(v0)]␊ diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index 1a4e46c80c0a873502e0d7c79fcf420950179d8b..53536312f5424e213e2f51d1fbc0fc7aaa34d45c 100644 GIT binary patch delta 1951 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 O{{ubBha^{80096vSJ{&Q diff --git a/packages/core-cairo/src/erc721.ts b/packages/core-cairo/src/erc721.ts index 4a7e8bbf..0177c4d0 100644 --- a/packages/core-cairo/src/erc721.ts +++ b/packages/core-cairo/src/erc721.ts @@ -57,20 +57,20 @@ export function buildERC721(opts: ERC721Options): Contract { addBase(c, toShortString(allOpts.name, 'name'), toShortString(allOpts.symbol, 'symbol')); addERC721ImplAndCamelOnlyImpl(c, allOpts.pausable); - if (allOpts.mintable) { - addMintable(c, allOpts.access); + if (allOpts.pausable) { + addPausable(c, allOpts.access); } if (allOpts.burnable) { addBurnable(c); - } - - if (allOpts.pausable) { - addPausable(c, allOpts.access); - if (allOpts.burnable) { + if (allOpts.pausable) { setPausable(c, externalTrait, functions.burn); } - if (allOpts.mintable) { + } + + if (allOpts.mintable) { + addMintable(c, allOpts.access); + if (allOpts.pausable) { setPausable(c, externalTrait, functions.safe_mint); } } From 4d9dce518af109742d29713f5430b706039ae34d Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Fri, 8 Dec 2023 10:56:52 -0500 Subject: [PATCH 29/29] Use camel case for safeMint params --- packages/core-cairo/src/erc721.test.ts.md | 18 +++++++++--------- packages/core-cairo/src/erc721.test.ts.snap | Bin 2004 -> 2017 bytes packages/core-cairo/src/erc721.ts | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/core-cairo/src/erc721.test.ts.md b/packages/core-cairo/src/erc721.test.ts.md index 2d9587eb..dccc4c34 100644 --- a/packages/core-cairo/src/erc721.test.ts.md +++ b/packages/core-cairo/src/erc721.test.ts.md @@ -376,11 +376,11 @@ Generated by [AVA](https://avajs.dev). fn safeMint(␊ ref self: ContractState,␊ recipient: ContractAddress,␊ - token_id: u256,␊ + tokenId: u256,␊ data: Span,␊ - token_uri: felt252,␊ + tokenURI: felt252,␊ ) {␊ - self.safe_mint(recipient, token_id, data, token_uri);␊ + self.safe_mint(recipient, tokenId, data, tokenURI);␊ }␊ }␊ }␊ @@ -473,11 +473,11 @@ Generated by [AVA](https://avajs.dev). fn safeMint(␊ ref self: ContractState,␊ recipient: ContractAddress,␊ - token_id: u256,␊ + tokenId: u256,␊ data: Span,␊ - token_uri: felt252,␊ + tokenURI: felt252,␊ ) {␊ - self.safe_mint(recipient, token_id, data, token_uri);␊ + self.safe_mint(recipient, tokenId, data, tokenURI);␊ }␊ }␊ }␊ @@ -692,11 +692,11 @@ Generated by [AVA](https://avajs.dev). fn safeMint(␊ ref self: ContractState,␊ recipient: ContractAddress,␊ - token_id: u256,␊ + tokenId: u256,␊ data: Span,␊ - token_uri: felt252,␊ + tokenURI: felt252,␊ ) {␊ - self.safe_mint(recipient, token_id, data, token_uri);␊ + self.safe_mint(recipient, tokenId, data, tokenURI);␊ }␊ }␊ ␊ diff --git a/packages/core-cairo/src/erc721.test.ts.snap b/packages/core-cairo/src/erc721.test.ts.snap index 53536312f5424e213e2f51d1fbc0fc7aaa34d45c..549562d886df78dc69b5cba7592a62441ca553a2 100644 GIT binary patch literal 2017 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' }, - { name: 'token_uri', type: 'felt252' }, + { name: 'tokenURI', type: 'felt252' }, ], code: [ - 'self.safe_mint(recipient, token_id, data, token_uri);', + 'self.safe_mint(recipient, tokenId, data, tokenURI);', ] },