diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4b5ab7d6c..99c10659b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,19 @@ on: pull_request: {} jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18.x + cache: 'yarn' + - name: Install dependencies + run: yarn install --network-concurrency 1 + - name: Run linter + run: yarn lint + build: strategy: matrix: diff --git a/.gitignore b/.gitignore index c61302beb..bb1d9b041 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ node_modules .env .env.local +.vscode/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..b62b39794 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "arrowParens": "avoid", + "trailingComma": "all", + "printWidth": 120, + "bracketSpacing": true +} diff --git a/README.md b/README.md index f8d6bb93d..d92bb86ef 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ Install dependencies with `yarn install`. `packages/core` contains the code generation logic for each language under separately named subfolders. From each language's subfolder: - Run `yarn test` to run the tests. - Run `yarn test:update-snapshots` to update AVA snapshots and run the tests. +- Run `yarn lint` to run the linter across the codebase (optionally `yarn lint --fix` will automatically fix fixable issues, like formatting issues). `packages/ui` is the interface built in Svelte. From the `packages/ui` directory, run `yarn dev` to spin up a local server to develop the UI. diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..aa9b737bf --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,49 @@ +// @ts-check + +import eslint from '@eslint/js'; +import prettierPluginRecommended from 'eslint-plugin-prettier/recommended'; +import unicornPlugin from 'eslint-plugin-unicorn'; +import typescriptEslint from 'typescript-eslint'; + +export default typescriptEslint.config( + eslint.configs.recommended, + typescriptEslint.configs.strict, + prettierPluginRecommended, + { + plugins: { + unicorn: unicornPlugin, + }, + rules: { + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/consistent-type-imports': 'error', + 'prettier/prettier': [ + 'error', + { singleQuote: true, arrowParens: 'avoid', trailingComma: 'all', printWidth: 120, bracketSpacing: true }, + ], + }, + }, + { + ignores: ['node_modules/', '*.sol', 'packages/*/node_modules/', 'packages/**/dist/', 'packages/**/build/'], + }, + { + files: ['**/*.config.js'], + languageOptions: { + sourceType: 'commonjs', + }, + }, + { + files: ['**/*.mjs', '**/*.js'], + languageOptions: { + sourceType: 'commonjs', + globals: { + process: 'readonly', + global: 'readonly', + console: 'readonly', + }, + }, + rules: { + '@typescript-eslint/no-require-imports': 'off', + }, + }, +); diff --git a/package.json b/package.json index 47a1d58d0..b203f527f 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "private": true, "scripts": { "prepare": "wsrun -m prepare", + "lint": "eslint", "dev:ui": "yarn --cwd ./packages/ui dev", "run:core": "node ./scripts/run-command.mjs" }, @@ -17,6 +18,14 @@ ] }, "devDependencies": { + "@eslint/js": "^9.21.0", + "eslint": "^9.21.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-unicorn": "^57.0.0", + "prettier": "^3.5.1", + "typescript": "^5.7.3", + "typescript-eslint": "^8.24.1", "wsrun": "^5.2.4" } } \ No newline at end of file diff --git a/packages/core/cairo/ava.config.js b/packages/core/cairo/ava.config.js index 77a9117a9..e39146f7a 100644 --- a/packages/core/cairo/ava.config.js +++ b/packages/core/cairo/ava.config.js @@ -2,11 +2,7 @@ module.exports = { extensions: ['ts'], require: ['ts-node/register'], watchmode: { - ignoreChanges: [ - 'contracts', - 'artifacts', - 'cache', - ], + ignoreChanges: ['contracts', 'artifacts', 'cache'], }, timeout: '10m', workerThreads: false, diff --git a/packages/core/cairo/package.json b/packages/core/cairo/package.json index 659340299..41a8a4bad 100644 --- a/packages/core/cairo/package.json +++ b/packages/core/cairo/package.json @@ -31,4 +31,4 @@ "typescript": "^5.0.0", "semver": "^7.6.0" } -} +} \ No newline at end of file diff --git a/packages/core/cairo/src/account.test.ts b/packages/core/cairo/src/account.test.ts index 217e1d813..cad307c75 100644 --- a/packages/core/cairo/src/account.test.ts +++ b/packages/core/cairo/src/account.test.ts @@ -1,6 +1,7 @@ import test from 'ava'; -import { buildAccount, AccountOptions } from './account'; +import type { AccountOptions } from './account'; +import { buildAccount } from './account'; import { printContract } from './print'; import { account } from '.'; @@ -32,22 +33,27 @@ function testEthAccount(title: string, opts: Partial) { */ function testAPIEquivalence(title: string, opts?: AccountOptions) { test(title, t => { - t.is(account.print(opts), printContract(buildAccount({ - name: 'MyAccount', - type: 'stark', - declare: true, - deploy: true, - pubkey: true, - outsideExecution: true, - ...opts, - }))); + t.is( + account.print(opts), + printContract( + buildAccount({ + name: 'MyAccount', + type: 'stark', + declare: true, + deploy: true, + pubkey: true, + outsideExecution: true, + ...opts, + }), + ), + ); }); } testAccount('default full account, mixin + upgradeable', {}); testAccount('default full account, mixin + non-upgradeable', { - upgradeable: false + upgradeable: false, }); testAccount('explicit full account, mixin + upgradeable', { @@ -57,7 +63,7 @@ testAccount('explicit full account, mixin + upgradeable', { deploy: true, pubkey: true, outsideExecution: true, - upgradeable: true + upgradeable: true, }); testAccount('explicit full account, mixin + non-upgradeable', { @@ -67,7 +73,7 @@ testAccount('explicit full account, mixin + non-upgradeable', { deploy: true, pubkey: true, outsideExecution: true, - upgradeable: false + upgradeable: false, }); testAccount('basic account, upgradeable', { @@ -82,7 +88,7 @@ testAccount('basic account, non-upgradeable', { deploy: false, pubkey: false, outsideExecution: false, - upgradeable: false + upgradeable: false, }); testAccount('account outside execution', { @@ -127,7 +133,7 @@ testAccount('account deployable, public key', { testEthAccount('default full ethAccount, mixin + upgradeable', {}); testEthAccount('default full ethAccount, mixin + non-upgradeable', { - upgradeable: false + upgradeable: false, }); testEthAccount('explicit full ethAccount, mixin + upgradeable', { @@ -137,7 +143,7 @@ testEthAccount('explicit full ethAccount, mixin + upgradeable', { deploy: true, pubkey: true, outsideExecution: true, - upgradeable: true + upgradeable: true, }); testEthAccount('explicit full ethAccount, mixin + non-upgradeable', { @@ -147,7 +153,7 @@ testEthAccount('explicit full ethAccount, mixin + non-upgradeable', { deploy: true, pubkey: true, outsideExecution: true, - upgradeable: false + upgradeable: false, }); testEthAccount('basic ethAccount, upgradeable', { @@ -162,7 +168,7 @@ testEthAccount('basic ethAccount, non-upgradeable', { deploy: false, pubkey: false, outsideExecution: false, - upgradeable: false + upgradeable: false, }); testEthAccount('ethAccount outside execution', { diff --git a/packages/core/cairo/src/account.ts b/packages/core/cairo/src/account.ts index 68914729e..f07293ede 100644 --- a/packages/core/cairo/src/account.ts +++ b/packages/core/cairo/src/account.ts @@ -1,5 +1,7 @@ -import { Contract, ContractBuilder } from './contract'; -import { CommonOptions, withCommonDefaults } from './common-options'; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; +import type { CommonOptions } from './common-options'; +import { withCommonDefaults } from './common-options'; import { defaults as commonDefaults } from './common-options'; import { setAccountUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; @@ -7,9 +9,8 @@ import { defineComponents } from './utils/define-components'; import { printContract } from './print'; import { addSRC5Component } from './common-components'; - export const accountTypes = ['stark', 'eth'] as const; -export type Account = typeof accountTypes[number]; +export type Account = (typeof accountTypes)[number]; export const defaults: Required = { name: 'MyAccount', @@ -19,7 +20,7 @@ export const defaults: Required = { pubkey: true, outsideExecution: true, upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info + info: commonDefaults.info, } as const; export function printAccount(opts: AccountOptions = defaults): string { @@ -42,8 +43,8 @@ function withDefaults(opts: AccountOptions): Required { declare: opts.declare ?? defaults.declare, deploy: opts.deploy ?? defaults.deploy, pubkey: opts.pubkey ?? defaults.pubkey, - outsideExecution: opts.outsideExecution ?? defaults.outsideExecution - } + outsideExecution: opts.outsideExecution ?? defaults.outsideExecution, + }; } export function buildAccount(opts: AccountOptions): Contract { @@ -157,11 +158,14 @@ function addAccountMixin(c: ContractBuilder, accountType: Account) { } function getBaseCompAndCompType(accountType: Account): [string, typeof componentType] { - const [baseComponent, componentType] = accountType === 'stark' ? ['AccountComponent', components.AccountComponent] : ['EthAccountComponent', components.EthAccountComponent]; + const [baseComponent, componentType] = + accountType === 'stark' + ? ['AccountComponent', components.AccountComponent] + : ['EthAccountComponent', components.EthAccountComponent]; return [baseComponent, componentType]; } -const components = defineComponents( { +const components = defineComponents({ AccountComponent: { path: 'openzeppelin::account', substorage: { @@ -172,11 +176,13 @@ const components = defineComponents( { name: 'AccountEvent', type: 'AccountComponent::Event', }, - impls: [{ - name: 'AccountInternalImpl', - embed: false, - value: 'AccountComponent::InternalImpl', - }], + impls: [ + { + name: 'AccountInternalImpl', + embed: false, + value: 'AccountComponent::InternalImpl', + }, + ], }, EthAccountComponent: { path: 'openzeppelin::account::eth_account', @@ -188,11 +194,13 @@ const components = defineComponents( { name: 'EthAccountEvent', type: 'EthAccountComponent::Event', }, - impls: [{ - name: 'EthAccountInternalImpl', - embed: false, - value: 'EthAccountComponent::InternalImpl', - }] + impls: [ + { + name: 'EthAccountInternalImpl', + embed: false, + value: 'EthAccountComponent::InternalImpl', + }, + ], }, SRC9Component: { path: 'openzeppelin::account::extensions', @@ -204,13 +212,16 @@ const components = defineComponents( { name: 'SRC9Event', type: 'SRC9Component::Event', }, - impls: [{ - name: 'OutsideExecutionV2Impl', - value: 'SRC9Component::OutsideExecutionV2Impl', - }, { - name: 'OutsideExecutionInternalImpl', - embed: false, - value: 'SRC9Component::InternalImpl', - }] - } + impls: [ + { + name: 'OutsideExecutionV2Impl', + value: 'SRC9Component::OutsideExecutionV2Impl', + }, + { + name: 'OutsideExecutionInternalImpl', + embed: false, + value: 'SRC9Component::InternalImpl', + }, + ], + }, }); diff --git a/packages/core/cairo/src/add-pausable.ts b/packages/core/cairo/src/add-pausable.ts index 1e950f98e..6d4f1c3c4 100644 --- a/packages/core/cairo/src/add-pausable.ts +++ b/packages/core/cairo/src/add-pausable.ts @@ -1,6 +1,7 @@ import { getSelfArg } from './common-options'; import type { ContractBuilder } from './contract'; -import { Access, requireAccessControl } from './set-access-control'; +import type { Access } from './set-access-control'; +import { requireAccessControl } from './set-access-control'; import { defineFunctions } from './utils/define-functions'; import { defineComponents } from './utils/define-components'; import { externalTrait } from './external-trait'; @@ -14,7 +15,7 @@ export function addPausable(c: ContractBuilder, access: Access) { requireAccessControl(c, externalTrait, functions.unpause, access, 'PAUSER', 'pauser'); } -const components = defineComponents( { +const components = defineComponents({ PausableComponent: { path: 'openzeppelin::security::pausable', substorage: { @@ -25,34 +26,27 @@ const components = defineComponents( { name: 'PausableEvent', type: 'PausableComponent::Event', }, - impls: [{ + impls: [ + { name: 'PausableImpl', value: 'PausableComponent::PausableImpl', - }, { + }, + { name: 'PausableInternalImpl', embed: false, value: 'PausableComponent::InternalImpl', - } + }, ], }, }); const functions = defineFunctions({ pause: { - args: [ - getSelfArg(), - ], - code: [ - 'self.pausable.pause()' - ] + args: [getSelfArg()], + code: ['self.pausable.pause()'], }, unpause: { - args: [ - getSelfArg(), - ], - code: [ - 'self.pausable.unpause()' - ] + args: [getSelfArg()], + code: ['self.pausable.unpause()'], }, }); - diff --git a/packages/core/cairo/src/api.ts b/packages/core/cairo/src/api.ts index a70fc497d..dd8daf73e 100644 --- a/packages/core/cairo/src/api.ts +++ b/packages/core/cairo/src/api.ts @@ -1,13 +1,36 @@ import type { CommonOptions, CommonContractOptions } from './common-options'; -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 { printAccount, defaults as accountDefaults, AccountOptions } from './account'; -import { printGovernor, defaults as governorDefaults, GovernorOptions } from './governor'; -import { printCustom, defaults as customDefaults, isAccessControlRequired as customIsAccessControlRequired, CustomOptions } from './custom'; -import { printVesting, defaults as vestingDefaults, VestingOptions } from './vesting'; +import type { ERC20Options } from './erc20'; +import { + printERC20, + defaults as erc20defaults, + isAccessControlRequired as erc20IsAccessControlRequired, +} from './erc20'; +import type { ERC721Options } from './erc721'; +import { + printERC721, + defaults as erc721defaults, + isAccessControlRequired as erc721IsAccessControlRequired, +} from './erc721'; +import type { ERC1155Options } from './erc1155'; +import { + printERC1155, + defaults as erc1155defaults, + isAccessControlRequired as erc1155IsAccessControlRequired, +} from './erc1155'; +import type { AccountOptions } from './account'; +import { printAccount, defaults as accountDefaults } from './account'; +import type { GovernorOptions } from './governor'; +import { printGovernor, defaults as governorDefaults } from './governor'; +import type { CustomOptions } from './custom'; +import { + printCustom, + defaults as customDefaults, + isAccessControlRequired as customIsAccessControlRequired, +} from './custom'; +import type { VestingOptions } from './vesting'; +import { printVesting, defaults as vestingDefaults } from './vesting'; -export interface WizardAccountAPI{ +export interface WizardAccountAPI { /** * Returns a string representation of a contract generated using the provided options. If opts is not provided, uses `defaults`. */ @@ -33,7 +56,7 @@ export interface WizardContractAPI { export interface AccessControlAPI { /** - * Whether any of the provided options require access control to be enabled. If this returns `true`, then calling `print` with the + * Whether any of the provided options require access control to be enabled. If this returns `true`, then calling `print` with the * same options would cause the `access` option to default to `'ownable'` if it was `undefined` or `false`. */ isAccessControlRequired: (opts: Partial) => boolean; @@ -51,31 +74,31 @@ export const erc20: ERC20 = { print: printERC20, defaults: erc20defaults, isAccessControlRequired: erc20IsAccessControlRequired, -} +}; export const erc721: ERC721 = { print: printERC721, defaults: erc721defaults, - isAccessControlRequired: erc721IsAccessControlRequired -} + isAccessControlRequired: erc721IsAccessControlRequired, +}; export const erc1155: ERC1155 = { print: printERC1155, defaults: erc1155defaults, - isAccessControlRequired: erc1155IsAccessControlRequired -} + isAccessControlRequired: erc1155IsAccessControlRequired, +}; export const account: Account = { print: printAccount, defaults: accountDefaults, -} +}; export const governor: Governor = { print: printGovernor, defaults: governorDefaults, -} +}; export const vesting: Vesting = { print: printVesting, defaults: vestingDefaults, -} +}; export const custom: Custom = { print: printCustom, defaults: customDefaults, - isAccessControlRequired: customIsAccessControlRequired -} + isAccessControlRequired: customIsAccessControlRequired, +}; diff --git a/packages/core/cairo/src/build-generic.ts b/packages/core/cairo/src/build-generic.ts index fc04c30dc..a956ed94f 100644 --- a/packages/core/cairo/src/build-generic.ts +++ b/packages/core/cairo/src/build-generic.ts @@ -1,19 +1,26 @@ -import { ERC20Options, buildERC20 } from './erc20'; -import { ERC721Options, buildERC721 } from './erc721'; -import { ERC1155Options, buildERC1155 } from './erc1155'; -import { CustomOptions, buildCustom } from './custom'; -import { AccountOptions, buildAccount } from './account'; -import { GovernorOptions, buildGovernor } from './governor'; -import { VestingOptions, buildVesting } from './vesting'; +import type { ERC20Options } from './erc20'; +import { buildERC20 } from './erc20'; +import type { ERC721Options } from './erc721'; +import { buildERC721 } from './erc721'; +import type { ERC1155Options } from './erc1155'; +import { buildERC1155 } from './erc1155'; +import type { CustomOptions } from './custom'; +import { buildCustom } from './custom'; +import type { AccountOptions } from './account'; +import { buildAccount } from './account'; +import type { GovernorOptions } from './governor'; +import { buildGovernor } from './governor'; +import type { VestingOptions } from './vesting'; +import { buildVesting } from './vesting'; export interface KindedOptions { - ERC20: { kind: 'ERC20' } & ERC20Options; - ERC721: { kind: 'ERC721' } & ERC721Options; - ERC1155: { kind: 'ERC1155' } & ERC1155Options; - Account: { kind: 'Account' } & AccountOptions; + ERC20: { kind: 'ERC20' } & ERC20Options; + ERC721: { kind: 'ERC721' } & ERC721Options; + ERC1155: { kind: 'ERC1155' } & ERC1155Options; + Account: { kind: 'Account' } & AccountOptions; Governor: { kind: 'Governor' } & GovernorOptions; Vesting: { kind: 'Vesting' } & VestingOptions; - Custom: { kind: 'Custom' } & CustomOptions; + Custom: { kind: 'Custom' } & CustomOptions; } export type GenericOptions = KindedOptions[keyof KindedOptions]; @@ -41,8 +48,9 @@ export function buildGeneric(opts: GenericOptions) { case 'Custom': return buildCustom(opts); - default: + default: { const _: never = opts; throw new Error('Unknown ERC'); + } } } diff --git a/packages/core/cairo/src/common-components.ts b/packages/core/cairo/src/common-components.ts index a05776fdd..bdfcef0e8 100644 --- a/packages/core/cairo/src/common-components.ts +++ b/packages/core/cairo/src/common-components.ts @@ -1,10 +1,10 @@ import type { BaseImplementedTrait, ContractBuilder } from './contract'; -import { defineComponents } from "./utils/define-components"; +import { defineComponents } from './utils/define-components'; export const tokenTypes = ['ERC20', 'ERC721'] as const; -export type Token = typeof tokenTypes[number]; +export type Token = (typeof tokenTypes)[number]; -const components = defineComponents( { +const components = defineComponents({ SRC5Component: { path: 'openzeppelin::introspection::src5', substorage: { @@ -28,11 +28,13 @@ const components = defineComponents( { name: 'VotesEvent', type: 'VotesComponent::Event', }, - impls: [{ - name: 'VotesInternalImpl', - embed: false, - value: 'VotesComponent::InternalImpl', - }], + impls: [ + { + name: 'VotesInternalImpl', + embed: false, + value: 'VotesComponent::InternalImpl', + }, + ], }, NoncesComponent: { @@ -52,7 +54,7 @@ const components = defineComponents( { }, ], }, -}) +}); export function addSRC5Component(c: ContractBuilder, section?: string) { c.addComponent(components.SRC5Component, [], false); @@ -93,17 +95,13 @@ export function addSNIP12Metadata(c: ContractBuilder, name: string, version: str name: 'name', args: [], returns: 'felt252', - code: [ - `'${name}'`, - ], + code: [`'${name}'`], }); c.addFunction(SNIP12Metadata, { name: 'version', args: [], returns: 'felt252', - code: [ - `'${version}'`, - ], + code: [`'${version}'`], }); } diff --git a/packages/core/cairo/src/common-options.ts b/packages/core/cairo/src/common-options.ts index 067ea317a..5cdee43e0 100644 --- a/packages/core/cairo/src/common-options.ts +++ b/packages/core/cairo/src/common-options.ts @@ -1,8 +1,8 @@ -import type { Argument } from "./contract"; -import type { Access } from "./set-access-control"; -import type { Info } from "./set-info"; -import { defaults as infoDefaults } from "./set-info"; -import type { Upgradeable } from "./set-upgradeable"; +import type { Argument } from './contract'; +import type { Access } from './set-access-control'; +import type { Info } from './set-info'; +import { defaults as infoDefaults } from './set-info'; +import type { Upgradeable } from './set-upgradeable'; export const defaults: Required = { upgradeable: true, @@ -43,4 +43,4 @@ export function getSelfArg(scope: 'external' | 'view' = 'external'): Argument { } else { 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 2dcaae2aa..a7675a25f 100644 --- a/packages/core/cairo/src/contract.test.ts +++ b/packages/core/cairo/src/contract.test.ts @@ -1,6 +1,7 @@ import test from 'ava'; -import { ContractBuilder, BaseFunction, BaseImplementedTrait, Component } from './contract'; +import type { BaseFunction, BaseImplementedTrait, Component } from './contract'; +import { ContractBuilder } from './contract'; import { printContract } from './print'; const FOO_COMPONENT: Component = { @@ -14,14 +15,16 @@ const FOO_COMPONENT: Component = { name: 'FooEvent', type: 'FooComponent::Event', }, - impls: [{ + impls: [ + { name: 'FooImpl', value: 'FooComponent::FooImpl', - }, { + }, + { name: 'FooInternalImpl', embed: false, value: 'FooComponent::InternalImpl', - } + }, ], }; @@ -47,19 +50,14 @@ test('contract with function code before', t => { const trait: BaseImplementedTrait = { name: 'External', of: 'ExternalTrait', - tags: [ - 'generate_trait', - 'abi(per_item)', - ], + tags: ['generate_trait', 'abi(per_item)'], perItemTag: 'external(v0)', }; Foo.addImplementedTrait(trait); const fn: BaseFunction = { name: 'someFunction', args: [], - code: [ - 'someFunction()' - ] + code: ['someFunction()'], }; Foo.addFunction(trait, fn); Foo.addFunctionCodeBefore(trait, fn, 'before()'); @@ -71,19 +69,14 @@ test('contract with function code before with semicolons', t => { const trait: BaseImplementedTrait = { name: 'External', of: 'ExternalTrait', - tags: [ - 'generate_trait', - 'abi(per_item)', - ], + tags: ['generate_trait', 'abi(per_item)'], perItemTag: 'external(v0)', }; Foo.addImplementedTrait(trait); const fn: BaseFunction = { name: 'someFunction', args: [], - code: [ - 'someFunction();' - ] + code: ['someFunction();'], }; Foo.addFunction(trait, fn); Foo.addFunctionCodeBefore(trait, fn, 'before();'); @@ -93,31 +86,23 @@ test('contract with function code before with semicolons', t => { test('contract with initializer params', t => { const Foo = new ContractBuilder('Foo'); - Foo.addComponent( - FOO_COMPONENT, - ['param1'], - true - ); + Foo.addComponent(FOO_COMPONENT, ['param1'], true); t.snapshot(printContract(Foo)); }); test('contract with standalone import', t => { const Foo = new ContractBuilder('Foo'); - Foo.addComponent( - FOO_COMPONENT, - ); + Foo.addComponent(FOO_COMPONENT); Foo.addUseClause('some::library', 'SomeLibrary'); t.snapshot(printContract(Foo)); }); test('contract with sorted use clauses', t => { const Foo = new ContractBuilder('Foo'); - Foo.addComponent( - FOO_COMPONENT, - ); + Foo.addComponent(FOO_COMPONENT); Foo.addUseClause('some::library', 'SomeLibrary'); Foo.addUseClause('another::library', 'AnotherLibrary'); Foo.addUseClause('another::library', 'Foo', { alias: 'Custom2' }); Foo.addUseClause('another::library', 'Foo', { alias: 'Custom1' }); t.snapshot(printContract(Foo)); -}); \ No newline at end of file +}); diff --git a/packages/core/cairo/src/contract.ts b/packages/core/cairo/src/contract.ts index b7f77d6a6..05ef6778b 100644 --- a/packages/core/cairo/src/contract.ts +++ b/packages/core/cairo/src/contract.ts @@ -14,7 +14,7 @@ export interface Contract { superVariables: Variable[]; } -export type Value = string | number | bigint | { lit: string } | { note: string, value: Value }; +export type Value = string | number | bigint | { lit: string } | { note: string; value: Value }; export interface UseClause { containerPath: string; @@ -145,14 +145,19 @@ export class ContractBuilder implements Contract { return this.interfaceFlagsSet; } - addUseClause(containerPath: string, name: string, options?: { groupable?: boolean, alias?: string }): void { + addUseClause(containerPath: string, name: string, options?: { groupable?: boolean; alias?: string }): void { // groupable defaults to true const groupable = options?.groupable ?? true; const alias = options?.alias ?? ''; const uniqueName = alias.length > 0 ? alias : name; const present = this.useClausesMap.has(uniqueName); if (!present) { - this.useClausesMap.set(uniqueName, { containerPath, name, groupable, alias }); + this.useClausesMap.set(uniqueName, { + containerPath, + name, + groupable, + alias, + }); } } @@ -162,7 +167,11 @@ export class ContractBuilder implements Contract { 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 + const cp: Component = { + initializer, + ...component, + impls: [...component.impls], + }; // spread impls to deep copy from original component this.componentsMap.set(key, cp); } return !present; @@ -208,7 +217,7 @@ export class ContractBuilder implements Contract { const t: ImplementedTrait = { name: baseTrait.name, of: baseTrait.of, - tags: [ ...baseTrait.tags ], + tags: [...baseTrait.tags], superVariables: [], functions: [], section: baseTrait.section, @@ -225,12 +234,12 @@ export class ContractBuilder implements Contract { if (existingVar.name === newVar.name) { if (existingVar.type !== newVar.type) { throw new Error( - `Tried to add duplicate super var ${newVar.name} with different type: ${newVar.type} instead of ${existingVar.type}.` + `Tried to add duplicate super var ${newVar.name} with different type: ${newVar.type} instead of ${existingVar.type}.`, ); } if (existingVar.value !== newVar.value) { throw new Error( - `Tried to add duplicate super var ${newVar.name} with different value: ${newVar.value} instead of ${existingVar.value}.` + `Tried to add duplicate super var ${newVar.name} with different value: ${newVar.value} instead of ${existingVar.value}.`, ); } return false; // No need to add, already exists @@ -270,7 +279,7 @@ export class ContractBuilder implements Contract { addFunctionCodeBefore(baseTrait: BaseImplementedTrait, fn: BaseFunction, codeBefore: string): void { this.addImplementedTrait(baseTrait); const existingFn = this.addFunction(baseTrait, fn); - existingFn.codeBefore = [ ...existingFn.codeBefore ?? [], codeBefore ]; + existingFn.codeBefore = [...(existingFn.codeBefore ?? []), codeBefore]; } addConstructorArgument(arg: Argument): void { diff --git a/packages/core/cairo/src/custom.test.ts b/packages/core/cairo/src/custom.test.ts index ae5b28cf0..9b3059094 100644 --- a/packages/core/cairo/src/custom.test.ts +++ b/packages/core/cairo/src/custom.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { custom } from '.'; -import { buildCustom, CustomOptions } from './custom'; +import type { CustomOptions } from './custom'; +import { buildCustom } from './custom'; import { printContract } from './print'; function testCustom(title: string, opts: Partial) { @@ -17,12 +18,17 @@ function testCustom(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: CustomOptions) { +function testAPIEquivalence(title: string, opts?: CustomOptions) { test(title, t => { - t.is(custom.print(opts), printContract(buildCustom({ - name: 'MyContract', - ...opts, - }))); + t.is( + custom.print(opts), + printContract( + buildCustom({ + name: 'MyContract', + ...opts, + }), + ), + ); }); } @@ -76,4 +82,4 @@ 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 }), true); -}); \ No newline at end of file +}); diff --git a/packages/core/cairo/src/custom.ts b/packages/core/cairo/src/custom.ts index 7f361415f..3fe6bc86a 100644 --- a/packages/core/cairo/src/custom.ts +++ b/packages/core/cairo/src/custom.ts @@ -1,7 +1,9 @@ -import { Contract, ContractBuilder } from './contract'; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; import { setAccessControl } from './set-access-control'; import { addPausable } from './add-pausable'; -import { CommonContractOptions, withCommonContractDefaults } from './common-options'; +import type { CommonContractOptions } from './common-options'; +import { withCommonContractDefaults } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { contractDefaults as commonDefaults } from './common-options'; @@ -12,7 +14,7 @@ export const defaults: Required = { pausable: false, access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info + info: commonDefaults.info, } as const; export function printCustom(opts: CustomOptions = defaults): string { @@ -51,4 +53,3 @@ export function buildCustom(opts: CustomOptions): Contract { return c; } - diff --git a/packages/core/cairo/src/erc1155.test.ts b/packages/core/cairo/src/erc1155.test.ts index 9923de2d5..066e86c4b 100644 --- a/packages/core/cairo/src/erc1155.test.ts +++ b/packages/core/cairo/src/erc1155.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { erc1155 } from '.'; -import { buildERC1155, ERC1155Options } from './erc1155'; +import type { ERC1155Options } from './erc1155'; +import { buildERC1155 } from './erc1155'; import { printContract } from './print'; import { royaltyInfoOptions } from './set-royalty-info'; @@ -14,7 +15,7 @@ const allFeaturesON: Partial = { burnable: true, pausable: true, royaltyInfo: royaltyInfoOptions.enabledDefault, - upgradeable: true + upgradeable: true, } as const; function testERC1155(title: string, opts: Partial) { @@ -33,11 +34,16 @@ function testERC1155(title: string, opts: Partial) { */ function testAPIEquivalence(title: string, opts?: ERC1155Options) { test(title, t => { - t.is(erc1155.print(opts), printContract(buildERC1155({ - name: NAME, - baseUri: '', - ...opts, - }))); + t.is( + erc1155.print(opts), + printContract( + buildERC1155({ + name: NAME, + baseUri: '', + ...opts, + }), + ), + ); }); } @@ -73,27 +79,27 @@ testERC1155('mintable + roles', { }); testERC1155('royalty info disabled', { - royaltyInfo: royaltyInfoOptions.disabled + royaltyInfo: royaltyInfoOptions.disabled, }); testERC1155('royalty info enabled default + ownable', { royaltyInfo: royaltyInfoOptions.enabledDefault, - access: 'ownable' + access: 'ownable', }); testERC1155('royalty info enabled default + roles', { royaltyInfo: royaltyInfoOptions.enabledDefault, - access: 'roles' + access: 'roles', }); testERC1155('royalty info enabled custom + ownable', { royaltyInfo: royaltyInfoOptions.enabledCustom, - access: 'ownable' + access: 'ownable', }); testERC1155('royalty info enabled custom + roles', { royaltyInfo: royaltyInfoOptions.enabledCustom, - access: 'roles' + access: 'roles', }); testERC1155('full non-upgradeable', { @@ -129,8 +135,18 @@ test('API isAccessControlRequired', async t => { t.is(erc1155.isAccessControlRequired({ updatableUri: false, pausable: true }), true); t.is(erc1155.isAccessControlRequired({ updatableUri: false, upgradeable: true }), true); t.is(erc1155.isAccessControlRequired({ updatableUri: true }), true); - t.is(erc1155.isAccessControlRequired({ royaltyInfo: royaltyInfoOptions.enabledDefault }), true); - t.is(erc1155.isAccessControlRequired({ royaltyInfo: royaltyInfoOptions.enabledCustom }), true); + t.is( + erc1155.isAccessControlRequired({ + royaltyInfo: royaltyInfoOptions.enabledDefault, + }), + true, + ); + t.is( + erc1155.isAccessControlRequired({ + royaltyInfo: royaltyInfoOptions.enabledCustom, + }), + 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.ts b/packages/core/cairo/src/erc1155.ts index d17cb8f3c..78788a7f6 100644 --- a/packages/core/cairo/src/erc1155.ts +++ b/packages/core/cairo/src/erc1155.ts @@ -1,8 +1,11 @@ -import { BaseImplementedTrait, Contract, ContractBuilder } from './contract'; -import { Access, requireAccessControl, setAccessControl } from './set-access-control'; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; +import type { Access } from './set-access-control'; +import { requireAccessControl, setAccessControl } from './set-access-control'; import { addPausable } from './add-pausable'; import { defineFunctions } from './utils/define-functions'; -import { CommonContractOptions, withCommonContractDefaults, getSelfArg } from './common-options'; +import type { CommonContractOptions } from './common-options'; +import { withCommonContractDefaults, getSelfArg } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { defineComponents } from './utils/define-components'; @@ -11,7 +14,8 @@ import { printContract } from './print'; import { addSRC5Component } from './common-components'; import { externalTrait } from './external-trait'; import { toByteArray } from './utils/convert-strings'; -import { RoyaltyInfoOptions, setRoyaltyInfo, defaults as royaltyInfoDefaults } from './set-royalty-info'; +import type { RoyaltyInfoOptions } from './set-royalty-info'; +import { setRoyaltyInfo, defaults as royaltyInfoDefaults } from './set-royalty-info'; export const defaults: Required = { name: 'MyToken', @@ -23,7 +27,7 @@ export const defaults: Required = { royaltyInfo: royaltyInfoDefaults, access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info + info: commonDefaults.info, } as const; export function printERC1155(opts: ERC1155Options = defaults): string { @@ -53,7 +57,13 @@ function withDefaults(opts: ERC1155Options): Required { } export function isAccessControlRequired(opts: Partial): boolean { - return opts.mintable === true || opts.pausable === true || opts.updatableUri !== false || opts.upgradeable === true || opts.royaltyInfo?.enabled === true; + return ( + opts.mintable === true || + opts.pausable === true || + opts.updatableUri !== false || + opts.upgradeable === true || + opts.royaltyInfo?.enabled === true + ); } export function buildERC1155(opts: ERC1155Options): Contract { @@ -84,7 +94,7 @@ export function buildERC1155(opts: ERC1155Options): Contract { setUpgradeable(c, allOpts.upgradeable, allOpts.access); setInfo(c, allOpts.info); setRoyaltyInfo(c, allOpts.royaltyInfo, allOpts.access); - + addHooks(c, allOpts); return c; @@ -105,16 +115,16 @@ function addHooks(c: ContractBuilder, allOpts: Required) { c.addFunction(hooksTrait, { name: 'before_update', args: [ - { name: 'ref self', type: `ERC1155Component::ComponentState` }, + { + name: 'ref self', + type: `ERC1155Component::ComponentState`, + }, { name: 'from', type: 'ContractAddress' }, { name: 'to', type: 'ContractAddress' }, { name: 'token_ids', type: 'Span' }, { name: 'values', type: 'Span' }, ], - code: [ - 'let contract_state = self.get_contract()', - 'contract_state.pausable.assert_not_paused()', - ], + code: ['let contract_state = self.get_contract()', 'contract_state.pausable.assert_not_paused()'], }); } else { c.addUseClause('openzeppelin::token::erc1155', 'ERC1155HooksEmptyImpl'); @@ -131,13 +141,7 @@ function addERC1155Mixin(c: ContractBuilder) { } function addBase(c: ContractBuilder, baseUri: string) { - c.addComponent( - components.ERC1155Component, - [ - baseUri, - ], - true, - ); + c.addComponent(components.ERC1155Component, [baseUri], true); } function addBurnable(c: ContractBuilder) { @@ -164,7 +168,7 @@ function addSetBaseUri(c: ContractBuilder, access: Access) { c.addFunction(externalTrait, functions.setBaseUri); } -const components = defineComponents( { +const components = defineComponents({ ERC1155Component: { path: 'openzeppelin::token::erc1155', substorage: { @@ -175,11 +179,13 @@ const components = defineComponents( { name: 'ERC1155Event', type: 'ERC1155Component::Event', }, - impls: [{ - name: 'ERC1155InternalImpl', - embed: false, - value: 'ERC1155Component::InternalImpl', - }], + impls: [ + { + name: 'ERC1155InternalImpl', + embed: false, + value: 'ERC1155Component::InternalImpl', + }, + ], }, }); @@ -196,8 +202,8 @@ const functions = defineFunctions({ 'if account != caller {', ' assert(self.erc1155.is_approved_for_all(account, caller), ERC1155Component::Errors::UNAUTHORIZED)', '}', - 'self.erc1155.burn(account, token_id, value);' - ] + 'self.erc1155.burn(account, token_id, value);', + ], }, batch_burn: { args: [ @@ -211,8 +217,8 @@ const functions = defineFunctions({ 'if account != caller {', ' assert(self.erc1155.is_approved_for_all(account, caller), ERC1155Component::Errors::UNAUTHORIZED)', '}', - 'self.erc1155.batch_burn(account, token_ids, values);' - ] + 'self.erc1155.batch_burn(account, token_ids, values);', + ], }, batchBurn: { args: [ @@ -221,9 +227,7 @@ const functions = defineFunctions({ { name: 'tokenIds', type: 'Span' }, { name: 'values', type: 'Span' }, ], - code: [ - 'self.batch_burn(account, tokenIds, values);' - ] + code: ['self.batch_burn(account, tokenIds, values);'], }, mint: { args: [ @@ -233,9 +237,7 @@ const functions = defineFunctions({ { name: 'value', type: 'u256' }, { name: 'data', type: 'Span' }, ], - code: [ - 'self.erc1155.mint_with_acceptance_check(account, token_id, value, data);', - ] + code: ['self.erc1155.mint_with_acceptance_check(account, token_id, value, data);'], }, batch_mint: { args: [ @@ -245,9 +247,7 @@ const functions = defineFunctions({ { name: 'values', type: 'Span' }, { name: 'data', type: 'Span' }, ], - code: [ - 'self.erc1155.batch_mint_with_acceptance_check(account, token_ids, values, data);', - ] + code: ['self.erc1155.batch_mint_with_acceptance_check(account, token_ids, values, data);'], }, batchMint: { args: [ @@ -257,26 +257,14 @@ const functions = defineFunctions({ { name: 'values', type: 'Span' }, { name: 'data', type: 'Span' }, ], - code: [ - 'self.batch_mint(account, tokenIds, values, data);', - ] + code: ['self.batch_mint(account, tokenIds, values, data);'], }, set_base_uri: { - args: [ - getSelfArg(), - { name: 'base_uri', type: 'ByteArray' }, - ], - code: [ - 'self.erc1155._set_base_uri(base_uri);' - ] + args: [getSelfArg(), { name: 'base_uri', type: 'ByteArray' }], + code: ['self.erc1155._set_base_uri(base_uri);'], }, setBaseUri: { - args: [ - getSelfArg(), - { name: 'baseUri', type: 'ByteArray' }, - ], - code: [ - 'self.set_base_uri(baseUri);' - ] + args: [getSelfArg(), { name: 'baseUri', type: 'ByteArray' }], + code: ['self.set_base_uri(baseUri);'], }, }); diff --git a/packages/core/cairo/src/erc20.test.ts b/packages/core/cairo/src/erc20.test.ts index 69f4cdd3d..45fb5bf87 100644 --- a/packages/core/cairo/src/erc20.test.ts +++ b/packages/core/cairo/src/erc20.test.ts @@ -1,9 +1,11 @@ import test from 'ava'; -import { buildERC20, ERC20Options, getInitialSupply } from './erc20'; +import type { ERC20Options } from './erc20'; +import { buildERC20, getInitialSupply } from './erc20'; import { printContract } from './print'; -import { erc20, OptionsError } from '.'; +import type { OptionsError } from '.'; +import { erc20 } from '.'; function testERC20(title: string, opts: Partial) { test(title, t => { @@ -21,11 +23,16 @@ function testERC20(title: string, opts: Partial) { */ function testAPIEquivalence(title: string, opts?: ERC20Options) { test(title, t => { - t.is(erc20.print(opts), printContract(buildERC20({ - name: 'MyToken', - symbol: 'MTK', - ...opts, - }))); + t.is( + erc20.print(opts), + printContract( + buildERC20({ + name: 'MyToken', + symbol: 'MTK', + ...opts, + }), + ), + ); }); } @@ -84,22 +91,26 @@ testERC20('erc20 votes, version', { }); test('erc20 votes, no name', async t => { - let error = t.throws(() => buildERC20({ - name: 'MyToken', - symbol: 'MTK', - votes: true, - })); + const error = t.throws(() => + buildERC20({ + name: 'MyToken', + symbol: 'MTK', + votes: true, + }), + ); t.is((error as OptionsError).messages.appName, 'Application Name is required when Votes are enabled'); }); test('erc20 votes, empty version', async t => { - let error = t.throws(() => buildERC20({ - name: 'MyToken', - symbol: 'MTK', - votes: true, - appName: 'MY_DAPP_NAME', - appVersion: '', // avoids default value of v1 - })); + const error = t.throws(() => + buildERC20({ + name: 'MyToken', + symbol: 'MTK', + votes: true, + appName: 'MY_DAPP_NAME', + appVersion: '', // avoids default value of v1 + }), + ); t.is((error as OptionsError).messages.appVersion, 'Application Version is required when Votes are enabled'); }); @@ -174,9 +185,9 @@ test('erc20 API isAccessControlRequired', async t => { }); test('erc20 getInitialSupply', async t => { - t.is(getInitialSupply('1000', 18), '1000000000000000000000'); + t.is(getInitialSupply('1000', 18), '1000000000000000000000'); t.is(getInitialSupply('1000.1', 18), '1000100000000000000000'); - t.is(getInitialSupply('.1', 18), '100000000000000000'); + t.is(getInitialSupply('.1', 18), '100000000000000000'); t.is(getInitialSupply('.01', 2), '1'); let error = t.throws(() => getInitialSupply('.01', 1)); @@ -186,4 +197,4 @@ test('erc20 getInitialSupply', async t => { 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.ts b/packages/core/cairo/src/erc20.ts index 57cfe8d86..e780f48ad 100644 --- a/packages/core/cairo/src/erc20.ts +++ b/packages/core/cairo/src/erc20.ts @@ -1,8 +1,11 @@ -import { Contract, ContractBuilder } from './contract'; -import { Access, requireAccessControl, setAccessControl } from './set-access-control'; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; +import type { Access } from './set-access-control'; +import { requireAccessControl, setAccessControl } from './set-access-control'; import { addPausable } from './add-pausable'; import { defineFunctions } from './utils/define-functions'; -import { CommonContractOptions, withCommonContractDefaults, getSelfArg } from './common-options'; +import type { CommonContractOptions } from './common-options'; +import { withCommonContractDefaults, getSelfArg } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { OptionsError } from './error'; @@ -13,7 +16,6 @@ import { externalTrait } from './external-trait'; import { toByteArray, toFelt252, toUint } from './utils/convert-strings'; import { addVotesComponent } from './common-components'; - export const defaults: Required = { name: 'MyToken', symbol: 'MTK', @@ -26,7 +28,7 @@ export const defaults: Required = { appVersion: 'v1', access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info + info: commonDefaults.info, } as const; export function printERC20(opts: ERC20Options = defaults): string { @@ -55,7 +57,7 @@ function withDefaults(opts: ERC20Options): Required { mintable: opts.mintable ?? defaults.mintable, votes: opts.votes ?? defaults.votes, appName: opts.appName ?? defaults.appName, - appVersion: opts.appVersion ?? defaults.appVersion + appVersion: opts.appVersion ?? defaults.appVersion, }; } @@ -111,7 +113,10 @@ function addHooks(c: ContractBuilder, allOpts: Required) { const beforeUpdateFn = c.addFunction(hooksTrait, { name: 'before_update', args: [ - { name: 'ref self', type: 'ERC20Component::ComponentState' }, + { + name: 'ref self', + type: 'ERC20Component::ComponentState', + }, { name: 'from', type: 'ContractAddress' }, { name: 'recipient', type: 'ContractAddress' }, { name: 'amount', type: 'u256' }, @@ -148,7 +153,10 @@ function addHooks(c: ContractBuilder, allOpts: Required) { const afterUpdateFn = c.addFunction(hooksTrait, { name: 'after_update', args: [ - { name: 'ref self', type: 'ERC20Component::ComponentState' }, + { + name: 'ref self', + type: 'ERC20Component::ComponentState', + }, { name: 'from', type: 'ContractAddress' }, { name: 'recipient', type: 'ContractAddress' }, { name: 'amount', type: 'u256' }, @@ -174,13 +182,7 @@ function addERC20Mixin(c: ContractBuilder) { } function addBase(c: ContractBuilder, name: string, symbol: string) { - c.addComponent( - components.ERC20Component, - [ - name, symbol - ], - true, - ); + c.addComponent(components.ERC20Component, [name, symbol], true); } function addBurnable(c: ContractBuilder) { @@ -201,7 +203,7 @@ function addPremint(c: ContractBuilder, amount: string) { const premintAbsolute = toUint(getInitialSupply(amount, 18), 'premint', 'u256'); c.addUseClause('starknet', 'ContractAddress'); - c.addConstructorArgument({ name:'recipient', type:'ContractAddress' }); + c.addConstructorArgument({ name: 'recipient', type: 'ContractAddress' }); c.addConstructorCode(`self.erc20.mint(recipient, ${premintAbsolute})`); } } @@ -216,18 +218,18 @@ function addPremint(c: ContractBuilder, amount: string) { */ export function getInitialSupply(premint: string, decimals: number): string { let result; - const premintSegments = premint.split("."); + const premintSegments = premint.split('.'); if (premintSegments.length > 2) { throw new OptionsError({ premint: 'Not a valid number', }); } else { - let firstSegment = premintSegments[0] ?? ''; + const firstSegment = premintSegments[0] ?? ''; let lastSegment = premintSegments[1] ?? ''; if (decimals > lastSegment.length) { try { - lastSegment += "0".repeat(decimals - lastSegment.length); - } catch (e) { + lastSegment += '0'.repeat(decimals - lastSegment.length); + } catch { // .repeat gives an error if decimals number is too large throw new OptionsError({ premint: 'Decimals number too large', @@ -252,7 +254,7 @@ function addMintable(c: ContractBuilder, access: Access) { requireAccessControl(c, externalTrait, functions.mint, access, 'MINTER', 'minter'); } -const components = defineComponents( { +const components = defineComponents({ ERC20Component: { path: 'openzeppelin::token::erc20', substorage: { @@ -263,32 +265,23 @@ const components = defineComponents( { name: 'ERC20Event', type: 'ERC20Component::Event', }, - impls: [{ - name: 'ERC20InternalImpl', - embed: false, - value: 'ERC20Component::InternalImpl', - }], + impls: [ + { + name: 'ERC20InternalImpl', + embed: false, + value: 'ERC20Component::InternalImpl', + }, + ], }, }); const functions = defineFunctions({ burn: { - args: [ - getSelfArg(), - { name: 'value', type: 'u256' } - ], - code: [ - 'self.erc20.burn(get_caller_address(), value);' - ] + args: [getSelfArg(), { name: 'value', type: 'u256' }], + code: ['self.erc20.burn(get_caller_address(), value);'], }, mint: { - args: [ - getSelfArg(), - { name: 'recipient', type: 'ContractAddress' }, - { name: 'amount', type: 'u256' } - ], - code: [ - 'self.erc20.mint(recipient, amount);' - ] + args: [getSelfArg(), { name: 'recipient', type: 'ContractAddress' }, { name: 'amount', type: 'u256' }], + 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 6608368fa..b5f4583e9 100644 --- a/packages/core/cairo/src/erc721.test.ts +++ b/packages/core/cairo/src/erc721.test.ts @@ -1,10 +1,12 @@ import test from 'ava'; -import { buildERC721, ERC721Options } from './erc721'; +import type { ERC721Options } from './erc721'; +import { buildERC721 } from './erc721'; import { printContract } from './print'; import { royaltyInfoOptions } from './set-royalty-info'; -import { erc721, OptionsError } from '.'; +import type { OptionsError } from '.'; +import { erc721 } from '.'; const NAME = 'MyToken'; const CUSTOM_NAME = 'CustomToken'; @@ -23,7 +25,7 @@ const allFeaturesON: Partial = { votes: true, appName: APP_NAME, appVersion: APP_VERSION, - upgradeable: true + upgradeable: true, } as const; function testERC721(title: string, opts: Partial) { @@ -40,13 +42,18 @@ function testERC721(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: ERC721Options) { +function testAPIEquivalence(title: string, opts?: ERC721Options) { test(title, t => { - t.is(erc721.print(opts), printContract(buildERC721({ - name: NAME, - symbol: SYMBOL, - ...opts, - }))); + t.is( + erc721.print(opts), + printContract( + buildERC721({ + name: NAME, + symbol: SYMBOL, + ...opts, + }), + ), + ); }); } @@ -87,27 +94,27 @@ testERC721('mintable + roles', { }); testERC721('royalty info disabled', { - royaltyInfo: royaltyInfoOptions.disabled + royaltyInfo: royaltyInfoOptions.disabled, }); testERC721('royalty info enabled default + ownable', { royaltyInfo: royaltyInfoOptions.enabledDefault, - access: 'ownable' + access: 'ownable', }); testERC721('royalty info enabled default + roles', { royaltyInfo: royaltyInfoOptions.enabledDefault, - access: 'roles' + access: 'roles', }); testERC721('royalty info enabled custom + ownable', { royaltyInfo: royaltyInfoOptions.enabledCustom, - access: 'ownable' + access: 'ownable', }); testERC721('royalty info enabled custom + roles', { royaltyInfo: royaltyInfoOptions.enabledCustom, - access: 'roles' + access: 'roles', }); testERC721('full non-upgradeable', { @@ -127,33 +134,39 @@ testERC721('erc721 votes, version', { }); test('erc721 votes, no name', async t => { - let error = t.throws(() => buildERC721({ - name: NAME, - symbol: SYMBOL, - votes: true, - })); + const error = t.throws(() => + buildERC721({ + name: NAME, + symbol: SYMBOL, + votes: true, + }), + ); t.is((error as OptionsError).messages.appName, 'Application Name is required when Votes are enabled'); }); test('erc721 votes, no version', async t => { - let error = t.throws(() => buildERC721({ - name: NAME, - symbol: SYMBOL, - votes: true, - appName: APP_NAME, - appVersion: '' - })); + const error = t.throws(() => + buildERC721({ + name: NAME, + symbol: SYMBOL, + votes: true, + appName: APP_NAME, + appVersion: '', + }), + ); t.is((error as OptionsError).messages.appVersion, 'Application Version is required when Votes are enabled'); }); test('erc721 votes, empty version', async t => { - let error = t.throws(() => buildERC721({ - name: NAME, - symbol: SYMBOL, - votes: true, - appName: APP_NAME, - appVersion: '', // avoids default value of v1 - })); + const error = t.throws(() => + buildERC721({ + name: NAME, + symbol: SYMBOL, + votes: true, + appName: APP_NAME, + appVersion: '', // avoids default value of v1 + }), + ); t.is((error as OptionsError).messages.appVersion, 'Application Version is required when Votes are enabled'); }); @@ -172,7 +185,7 @@ testAPIEquivalence('API basic', { name: CUSTOM_NAME, symbol: CUSTOM_SYMBOL }); testAPIEquivalence('API full upgradeable', { ...allFeaturesON, name: CUSTOM_NAME, - symbol: CUSTOM_SYMBOL + symbol: CUSTOM_SYMBOL, }); test('API assert defaults', async t => { @@ -183,9 +196,24 @@ 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 }), true); - t.is(erc721.isAccessControlRequired({ royaltyInfo: royaltyInfoOptions.enabledDefault }), true); - t.is(erc721.isAccessControlRequired({ royaltyInfo: royaltyInfoOptions.enabledCustom }), true); - t.is(erc721.isAccessControlRequired({ royaltyInfo: royaltyInfoOptions.disabled }), false); + t.is( + erc721.isAccessControlRequired({ + royaltyInfo: royaltyInfoOptions.enabledDefault, + }), + true, + ); + t.is( + erc721.isAccessControlRequired({ + royaltyInfo: royaltyInfoOptions.enabledCustom, + }), + true, + ); + t.is( + erc721.isAccessControlRequired({ + royaltyInfo: royaltyInfoOptions.disabled, + }), + false, + ); t.is(erc721.isAccessControlRequired({ burnable: true }), false); t.is(erc721.isAccessControlRequired({ enumerable: true }), false); -}); \ No newline at end of file +}); diff --git a/packages/core/cairo/src/erc721.ts b/packages/core/cairo/src/erc721.ts index 6b23e1c28..6ddaf2efd 100644 --- a/packages/core/cairo/src/erc721.ts +++ b/packages/core/cairo/src/erc721.ts @@ -1,8 +1,11 @@ -import { BaseImplementedTrait, Contract, ContractBuilder } from './contract'; -import { Access, requireAccessControl, setAccessControl } from './set-access-control'; +import type { BaseImplementedTrait, Contract } from './contract'; +import { ContractBuilder } from './contract'; +import type { Access } from './set-access-control'; +import { requireAccessControl, setAccessControl } from './set-access-control'; import { addPausable } from './add-pausable'; import { defineFunctions } from './utils/define-functions'; -import { CommonContractOptions, withCommonContractDefaults, getSelfArg } from './common-options'; +import type { CommonContractOptions } from './common-options'; +import { withCommonContractDefaults, getSelfArg } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { defineComponents } from './utils/define-components'; @@ -12,7 +15,8 @@ import { addSRC5Component, addVotesComponent } from './common-components'; import { externalTrait } from './external-trait'; import { toByteArray, toFelt252 } from './utils/convert-strings'; import { OptionsError } from './error'; -import { RoyaltyInfoOptions, setRoyaltyInfo, defaults as royaltyInfoDefaults } from './set-royalty-info'; +import type { RoyaltyInfoOptions } from './set-royalty-info'; +import { setRoyaltyInfo, defaults as royaltyInfoDefaults } from './set-royalty-info'; export const defaults: Required = { name: 'MyToken', @@ -28,7 +32,7 @@ export const defaults: Required = { appVersion: 'v1', access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info + info: commonDefaults.info, } as const; export function printERC721(opts: ERC721Options = defaults): string { @@ -61,12 +65,14 @@ function withDefaults(opts: ERC721Options): Required { royaltyInfo: opts.royaltyInfo ?? defaults.royaltyInfo, votes: opts.votes ?? defaults.votes, appName: opts.appName ?? defaults.appName, - appVersion: opts.appVersion ?? defaults.appVersion + appVersion: opts.appVersion ?? defaults.appVersion, }; } export function isAccessControlRequired(opts: Partial): boolean { - return opts.mintable === true || opts.pausable === true || opts.upgradeable === true || opts.royaltyInfo?.enabled === true; + return ( + opts.mintable === true || opts.pausable === true || opts.upgradeable === true || opts.royaltyInfo?.enabled === true + ); } export function buildERC721(opts: ERC721Options): Contract { @@ -97,7 +103,7 @@ export function buildERC721(opts: ERC721Options): Contract { setUpgradeable(c, allOpts.upgradeable, allOpts.access); setInfo(c, allOpts.info); setRoyaltyInfo(c, allOpts.royaltyInfo, allOpts.access); - + addHooks(c, allOpts); return c; @@ -127,17 +133,17 @@ function addHooks(c: ContractBuilder, opts: Required) { beforeUpdateCode.push('contract_state.erc721_enumerable.before_update(to, token_id)'); } if (opts.votes) { - if (!opts.appName) { - throw new OptionsError({ - appName: 'Application Name is required when Votes are enabled', - }); - } + if (!opts.appName) { + throw new OptionsError({ + appName: 'Application Name is required when Votes are enabled', + }); + } - if (!opts.appVersion) { - throw new OptionsError({ - appVersion: 'Application Version is required when Votes are enabled', - }); - } + if (!opts.appVersion) { + throw new OptionsError({ + appVersion: 'Application Version is required when Votes are enabled', + }); + } addVotesComponent( c, @@ -151,7 +157,10 @@ function addHooks(c: ContractBuilder, opts: Required) { c.addFunction(ERC721HooksTrait, { name: 'before_update', args: [ - { name: 'ref self', type: `ERC721Component::ComponentState` }, + { + name: 'ref self', + type: `ERC721Component::ComponentState`, + }, { name: 'to', type: 'ContractAddress' }, { name: 'token_id', type: 'u256' }, { name: 'auth', type: 'ContractAddress' }, @@ -173,13 +182,7 @@ function addERC721Mixin(c: ContractBuilder) { } function addBase(c: ContractBuilder, name: string, symbol: string, baseUri: string) { - c.addComponent( - components.ERC721Component, - [ - name, symbol, baseUri, - ], - true, - ); + c.addComponent(components.ERC721Component, [name, symbol, baseUri], true); } function addEnumerable(c: ContractBuilder) { @@ -201,7 +204,7 @@ function addMintable(c: ContractBuilder, access: Access) { c.addFunction(externalTrait, functions.safeMint); } -const components = defineComponents( { +const components = defineComponents({ ERC721Component: { path: 'openzeppelin::token::erc721', substorage: { @@ -212,11 +215,13 @@ const components = defineComponents( { name: 'ERC721Event', type: 'ERC721Component::Event', }, - impls: [{ - name: 'ERC721InternalImpl', - embed: false, - value: 'ERC721Component::InternalImpl', - }], + impls: [ + { + name: 'ERC721InternalImpl', + embed: false, + value: 'ERC721Component::InternalImpl', + }, + ], }, ERC721EnumerableComponent: { path: 'openzeppelin::token::erc721::extensions', @@ -228,26 +233,24 @@ const components = defineComponents( { name: 'ERC721EnumerableEvent', type: 'ERC721EnumerableComponent::Event', }, - impls: [{ - name: 'ERC721EnumerableImpl', - value: 'ERC721EnumerableComponent::ERC721EnumerableImpl', - }, { - name: 'ERC721EnumerableInternalImpl', - embed: false, - value: 'ERC721EnumerableComponent::InternalImpl', - }], + impls: [ + { + name: 'ERC721EnumerableImpl', + value: 'ERC721EnumerableComponent::ERC721EnumerableImpl', + }, + { + name: 'ERC721EnumerableInternalImpl', + embed: false, + value: 'ERC721EnumerableComponent::InternalImpl', + }, + ], }, }); const functions = defineFunctions({ burn: { - args: [ - getSelfArg(), - { name: 'token_id', type: 'u256' } - ], - code: [ - 'self.erc721.update(Zero::zero(), token_id, get_caller_address());', - ] + args: [getSelfArg(), { name: 'token_id', type: 'u256' }], + code: ['self.erc721.update(Zero::zero(), token_id, get_caller_address());'], }, safe_mint: { args: [ @@ -256,9 +259,7 @@ const functions = defineFunctions({ { name: 'token_id', type: 'u256' }, { name: 'data', type: 'Span' }, ], - code: [ - 'self.erc721.safe_mint(recipient, token_id, data);', - ] + code: ['self.erc721.safe_mint(recipient, token_id, data);'], }, safeMint: { args: [ @@ -267,8 +268,6 @@ const functions = defineFunctions({ { name: 'tokenId', type: 'u256' }, { name: 'data', type: 'Span' }, ], - code: [ - 'self.safe_mint(recipient, tokenId, data);', - ] + code: ['self.safe_mint(recipient, tokenId, data);'], }, }); diff --git a/packages/core/cairo/src/error.ts b/packages/core/cairo/src/error.ts index 8b3d2b8e3..a26433319 100644 --- a/packages/core/cairo/src/error.ts +++ b/packages/core/cairo/src/error.ts @@ -2,6 +2,6 @@ export type OptionsErrorMessages = { [prop in string]?: string }; export class OptionsError extends Error { constructor(readonly messages: OptionsErrorMessages) { - super("Invalid options"); + super('Invalid options'); } } diff --git a/packages/core/cairo/src/external-trait.ts b/packages/core/cairo/src/external-trait.ts index ed7e99e45..152ab3ed2 100644 --- a/packages/core/cairo/src/external-trait.ts +++ b/packages/core/cairo/src/external-trait.ts @@ -1,11 +1,8 @@ -import type { BaseImplementedTrait } from "./contract"; +import type { BaseImplementedTrait } from './contract'; export const externalTrait: BaseImplementedTrait = { name: 'ExternalImpl', of: 'ExternalTrait', - tags: [ - 'generate_trait', - 'abi(per_item)', - ], + tags: ['generate_trait', 'abi(per_item)'], perItemTag: 'external(v0)', -} +}; diff --git a/packages/core/cairo/src/generate/alternatives.ts b/packages/core/cairo/src/generate/alternatives.ts index afd89ab67..b66e733cf 100644 --- a/packages/core/cairo/src/generate/alternatives.ts +++ b/packages/core/cairo/src/generate/alternatives.ts @@ -4,9 +4,7 @@ type Alternatives = { [k in keyof B]: B[k][number]; }; -export function* generateAlternatives( - blueprint: B, -): Generator> { +export function* generateAlternatives(blueprint: B): Generator> { const entries = Object.entries(blueprint).map(([key, values]) => ({ key, values, @@ -15,9 +13,7 @@ export function* generateAlternatives( })); for (; !done(); advance()) { - yield Object.fromEntries( - entries.map(e => [e.key, e.values[e.current % e.limit]]), - ) as Alternatives; + yield Object.fromEntries(entries.map(e => [e.key, e.values[e.current % e.limit]])) as Alternatives; } function done() { diff --git a/packages/core/cairo/src/generate/erc20.ts b/packages/core/cairo/src/generate/erc20.ts index 941505c7e..51659af86 100644 --- a/packages/core/cairo/src/generate/erc20.ts +++ b/packages/core/cairo/src/generate/erc20.ts @@ -18,7 +18,7 @@ const blueprint = { appVersion: ['v1'], access: accessOptions, upgradeable: upgradeableOptions, - info: infoOptions + info: infoOptions, }; export function* generateERC20Options(): Generator> { diff --git a/packages/core/cairo/src/generate/governor.ts b/packages/core/cairo/src/generate/governor.ts index 8ffee9aef..9cb8d6f26 100644 --- a/packages/core/cairo/src/generate/governor.ts +++ b/packages/core/cairo/src/generate/governor.ts @@ -1,4 +1,5 @@ -import { clockModeOptions, GovernorOptions, quorumModeOptions, timelockOptions, votesOptions } from '../governor'; +import type { GovernorOptions } from '../governor'; +import { clockModeOptions, quorumModeOptions, timelockOptions, votesOptions } from '../governor'; import { infoOptions } from '../set-info'; import { upgradeableOptions } from '../set-upgradeable'; import { generateAlternatives } from './alternatives'; @@ -27,4 +28,3 @@ const blueprint = { export function* generateGovernorOptions(): Generator> { yield* generateAlternatives(blueprint); } - diff --git a/packages/core/cairo/src/generate/sources.ts b/packages/core/cairo/src/generate/sources.ts index 5be28487c..44d777f26 100644 --- a/packages/core/cairo/src/generate/sources.ts +++ b/packages/core/cairo/src/generate/sources.ts @@ -9,7 +9,8 @@ import { generateAccountOptions } from './account'; import { generateCustomOptions } from './custom'; import { generateGovernorOptions } from './governor'; import { generateVestingOptions } from './vesting'; -import { buildGeneric, GenericOptions, KindedOptions } from '../build-generic'; +import type { GenericOptions, KindedOptions } from '../build-generic'; +import { buildGeneric } from '../build-generic'; import { printContract } from '../print'; import { OptionsError } from '../error'; import { findCover } from '../utils/find-cover'; @@ -77,11 +78,7 @@ function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[ const contracts = []; for (const options of generateOptions(kind)) { - const id = crypto - .createHash('sha1') - .update(JSON.stringify(options)) - .digest() - .toString('hex'); + const id = crypto.createHash('sha1').update(JSON.stringify(options)).digest().toString('hex'); try { const contract = buildGeneric(options); @@ -111,11 +108,12 @@ function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[ case 'Governor': case 'Custom': return c.options.upgradeable === isUpgradeable; - default: + default: { const _: never = c.options; throw new Error('Unknown kind'); + } } - } + }; } return [ ...findCover(contracts.filter(filterByUpgradeableSetTo(true)), getParents), @@ -135,9 +133,14 @@ export function* generateSources(subset: Subset, uniqueName?: boolean, kind?: Ki } } -export async function writeGeneratedSources(dir: string, subset: Subset, uniqueName?: boolean, kind?: Kind): Promise { +export async function writeGeneratedSources( + dir: string, + subset: Subset, + uniqueName?: boolean, + kind?: Kind, +): Promise { await fs.mkdir(dir, { recursive: true }); - let contractNames = []; + const contractNames = []; for (const { id, contract, source } of generateSources(subset, uniqueName, kind)) { const name = uniqueName ? contract.name : id; diff --git a/packages/core/cairo/src/generate/vesting.ts b/packages/core/cairo/src/generate/vesting.ts index 45de06143..9be2e455d 100644 --- a/packages/core/cairo/src/generate/vesting.ts +++ b/packages/core/cairo/src/generate/vesting.ts @@ -8,7 +8,7 @@ const blueprint = { duration: ['90 days', '1 year'], cliffDuration: ['0 seconds', '30 day'], schedule: ['linear', 'custom'] as const, - info: infoOptions + info: infoOptions, }; export function* generateVestingOptions(): Generator> { diff --git a/packages/core/cairo/src/governor.test.ts b/packages/core/cairo/src/governor.test.ts index e3b3f0c22..0f102c18f 100644 --- a/packages/core/cairo/src/governor.test.ts +++ b/packages/core/cairo/src/governor.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { governor } from '.'; -import { buildGovernor, GovernorOptions } from './governor'; +import type { GovernorOptions } from './governor'; +import { buildGovernor } from './governor'; import { printContract } from './print'; const NAME = 'MyGovernor'; @@ -23,21 +24,26 @@ function testGovernor(title: string, opts: Partial) { */ function testAPIEquivalence(title: string, opts?: GovernorOptions) { test(title, t => { - t.is(governor.print(opts), printContract(buildGovernor({ - name: NAME, - delay: '1 day', - period: '1 week', - ...opts, - }))); + t.is( + governor.print(opts), + printContract( + buildGovernor({ + name: NAME, + delay: '1 day', + period: '1 week', + ...opts, + }), + ), + ); }); } testGovernor('basic + upgradeable', { - upgradeable: true + upgradeable: true, }); testGovernor('basic non-upgradeable', { - upgradeable: false + upgradeable: false, }); testGovernor('erc20 votes + timelock', { @@ -98,14 +104,14 @@ testAPIEquivalence('API basic + upgradeable', { name: NAME, delay: '1 day', period: '1 week', - upgradeable: true + upgradeable: true, }); testAPIEquivalence('API basic non-upgradeable', { name: NAME, delay: '1 day', period: '1 week', - upgradeable: false + upgradeable: false, }); testAPIEquivalence('API erc20 votes + timelock', { @@ -146,7 +152,7 @@ testAPIEquivalence('API quorum mode absolute', { quorumAbsolute: '200', }); -testAPIEquivalence('API quorum mode percent', { +testAPIEquivalence('API quorum mode percent', { name: NAME, delay: '1 day', period: '1 week', diff --git a/packages/core/cairo/src/governor.ts b/packages/core/cairo/src/governor.ts index fac953e62..f0c05f2e7 100644 --- a/packages/core/cairo/src/governor.ts +++ b/packages/core/cairo/src/governor.ts @@ -1,17 +1,18 @@ import { contractDefaults as commonDefaults, withCommonDefaults } from './common-options'; import type { CommonOptions } from './common-options'; -import { ContractBuilder, Contract } from "./contract"; -import { OptionsError } from "./error"; -import { printContract } from "./print"; -import { setInfo } from "./set-info"; -import { setUpgradeableGovernor } from "./set-upgradeable"; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; +import { OptionsError } from './error'; +import { printContract } from './print'; +import { setInfo } from './set-info'; +import { setUpgradeableGovernor } from './set-upgradeable'; import { defineComponents } from './utils/define-components'; import { durationToTimestamp } from './utils/duration'; import { addSNIP12Metadata, addSRC5Component } from './common-components'; import { toUint } from './utils/convert-strings'; export const clockModeOptions = ['timestamp'] as const; export const clockModeDefault = 'timestamp' as const; -export type ClockMode = typeof clockModeOptions[number]; +export type ClockMode = (typeof clockModeOptions)[number]; const extensionPath = 'openzeppelin::governance::governor::extensions'; const extensionExternalSection = 'Extensions (external)'; @@ -33,17 +34,17 @@ export const defaults: Required = { upgradeable: commonDefaults.upgradeable, appName: 'OpenZeppelin Governor', appVersion: 'v1', - info: commonDefaults.info + info: commonDefaults.info, } as const; export const quorumModeOptions = ['percent', 'absolute'] as const; -export type QuorumMode = typeof quorumModeOptions[number]; +export type QuorumMode = (typeof quorumModeOptions)[number]; export const votesOptions = ['erc20votes', 'erc721votes'] as const; -export type VotesOptions = typeof votesOptions[number]; +export type VotesOptions = (typeof votesOptions)[number]; export const timelockOptions = [false, 'openzeppelin'] as const; -export type TimelockOptions = typeof timelockOptions[number]; +export type TimelockOptions = (typeof timelockOptions)[number]; export function printGovernor(opts: GovernorOptions = defaults): string { return printContract(buildGovernor(opts)); @@ -105,7 +106,7 @@ export function buildGovernor(opts: GovernorOptions): Contract { return c; } -const components = defineComponents( { +const components = defineComponents({ GovernorComponent: { path: 'openzeppelin::governance::governor', substorage: { @@ -116,11 +117,13 @@ const components = defineComponents( { name: 'GovernorEvent', type: 'GovernorComponent::Event', }, - impls: [{ - name: 'GovernorImpl', - value: 'GovernorComponent::GovernorImpl', - section: 'Governor Core', - }], + impls: [ + { + name: 'GovernorImpl', + value: 'GovernorComponent::GovernorImpl', + section: 'Governor Core', + }, + ], }, GovernorSettingsComponent: { path: extensionPath, @@ -132,16 +135,19 @@ const components = defineComponents( { name: 'GovernorSettingsEvent', type: 'GovernorSettingsComponent::Event', }, - impls: [{ - name: 'GovernorSettingsAdminImpl', - value: 'GovernorSettingsComponent::GovernorSettingsAdminImpl', - section: extensionExternalSection, - }, { - name: 'GovernorSettingsImpl', - value: 'GovernorSettingsComponent::GovernorSettings', - embed: false, - section: extensionInternalSection, - }], + impls: [ + { + name: 'GovernorSettingsAdminImpl', + value: 'GovernorSettingsComponent::GovernorSettingsAdminImpl', + section: extensionExternalSection, + }, + { + name: 'GovernorSettingsImpl', + value: 'GovernorSettingsComponent::GovernorSettings', + embed: false, + section: extensionInternalSection, + }, + ], }, GovernorVotesComponent: { path: extensionPath, @@ -153,16 +159,19 @@ const components = defineComponents( { name: 'GovernorVotesEvent', type: 'GovernorVotesComponent::Event', }, - impls: [{ - name: 'VotesTokenImpl', - value: 'GovernorVotesComponent::VotesTokenImpl', - section: extensionExternalSection, - }, { - name: 'GovernorVotesImpl', - value: 'GovernorVotesComponent::GovernorVotes', - embed: false, - section: extensionInternalSection, - }], + impls: [ + { + name: 'VotesTokenImpl', + value: 'GovernorVotesComponent::VotesTokenImpl', + section: extensionExternalSection, + }, + { + name: 'GovernorVotesImpl', + value: 'GovernorVotesComponent::GovernorVotes', + embed: false, + section: extensionInternalSection, + }, + ], }, GovernorVotesQuorumFractionComponent: { path: extensionPath, @@ -174,21 +183,25 @@ const components = defineComponents( { name: 'GovernorVotesEvent', type: 'GovernorVotesQuorumFractionComponent::Event', }, - impls: [{ - name: 'GovernorQuorumImpl', - value: 'GovernorVotesQuorumFractionComponent::GovernorQuorum', - embed: false, - section: extensionInternalSection, - }, { - name: 'GovernorVotesImpl', - value: 'GovernorVotesQuorumFractionComponent::GovernorVotes', - embed: false, - section: extensionInternalSection, - }, { - name: 'QuorumFractionImpl', - value: 'GovernorVotesQuorumFractionComponent::QuorumFractionImpl', - section: extensionExternalSection, - }], + impls: [ + { + name: 'GovernorQuorumImpl', + value: 'GovernorVotesQuorumFractionComponent::GovernorQuorum', + embed: false, + section: extensionInternalSection, + }, + { + name: 'GovernorVotesImpl', + value: 'GovernorVotesQuorumFractionComponent::GovernorVotes', + embed: false, + section: extensionInternalSection, + }, + { + name: 'QuorumFractionImpl', + value: 'GovernorVotesQuorumFractionComponent::QuorumFractionImpl', + section: extensionExternalSection, + }, + ], }, GovernorCountingSimpleComponent: { path: extensionPath, @@ -200,12 +213,14 @@ const components = defineComponents( { name: 'GovernorCountingSimpleEvent', type: 'GovernorCountingSimpleComponent::Event', }, - impls: [{ - name: 'GovernorCountingSimpleImpl', - value: 'GovernorCountingSimpleComponent::GovernorCounting', - embed: false, - section: extensionInternalSection, - }], + impls: [ + { + name: 'GovernorCountingSimpleImpl', + value: 'GovernorCountingSimpleComponent::GovernorCounting', + embed: false, + section: extensionInternalSection, + }, + ], }, GovernorCoreExecutionComponent: { path: extensionPath, @@ -217,12 +232,14 @@ const components = defineComponents( { name: 'GovernorCoreExecutionEvent', type: 'GovernorCoreExecutionComponent::Event', }, - impls: [{ - name: 'GovernorCoreExecutionImpl', - value: 'GovernorCoreExecutionComponent::GovernorExecution', - embed: false, - section: extensionInternalSection, - }], + impls: [ + { + name: 'GovernorCoreExecutionImpl', + value: 'GovernorCoreExecutionComponent::GovernorExecution', + embed: false, + section: extensionInternalSection, + }, + ], }, GovernorTimelockExecutionComponent: { path: extensionPath, @@ -234,16 +251,19 @@ const components = defineComponents( { name: 'GovernorTimelockExecutionEvent', type: 'GovernorTimelockExecutionComponent::Event', }, - impls: [{ - name: 'TimelockedImpl', - value: 'GovernorTimelockExecutionComponent::TimelockedImpl', - section: extensionExternalSection, - }, { - name: 'GovernorTimelockExecutionImpl', - value: 'GovernorTimelockExecutionComponent::GovernorExecution', - embed: false, - section: extensionInternalSection, - }], + impls: [ + { + name: 'TimelockedImpl', + value: 'GovernorTimelockExecutionComponent::TimelockedImpl', + section: extensionExternalSection, + }, + { + name: 'GovernorTimelockExecutionImpl', + value: 'GovernorTimelockExecutionComponent::GovernorExecution', + embed: false, + section: extensionInternalSection, + }, + ], }, }); @@ -251,7 +271,9 @@ function addBase(c: ContractBuilder, _: GovernorOptions) { c.addUseClause('starknet', 'ContractAddress'); c.addUseClause('openzeppelin::governance::governor', 'DefaultConfig'); c.addConstructorArgument({ name: 'votes_token', type: 'ContractAddress' }); - c.addUseClause('openzeppelin::governance::governor::GovernorComponent', 'InternalTrait', { alias: 'GovernorInternalTrait' }); + c.addUseClause('openzeppelin::governance::governor::GovernorComponent', 'InternalTrait', { + alias: 'GovernorInternalTrait', + }); c.addComponent(components.GovernorComponent, [], true); } @@ -278,12 +300,14 @@ function addSettings(c: ContractBuilder, allOpts: Required) { }); if (allOpts.settings) { - c.addUseClause(`${extensionPath}::GovernorSettingsComponent`, 'InternalTrait', { alias: 'GovernorSettingsInternalTrait' }); - c.addComponent(components.GovernorSettingsComponent, [ - { lit: 'VOTING_DELAY' }, - { lit: 'VOTING_PERIOD' }, - { lit: 'PROPOSAL_THRESHOLD' }, - ], true); + c.addUseClause(`${extensionPath}::GovernorSettingsComponent`, 'InternalTrait', { + alias: 'GovernorSettingsInternalTrait', + }); + c.addComponent( + components.GovernorSettingsComponent, + [{ lit: 'VOTING_DELAY' }, { lit: 'VOTING_PERIOD' }, { lit: 'PROPOSAL_THRESHOLD' }], + true, + ); } else { addSettingsLocalImpl(c, allOpts); } @@ -292,7 +316,7 @@ function addSettings(c: ContractBuilder, allOpts: Required) { function getVotingDelay(opts: Required): number { try { if (opts.clockMode === 'timestamp') { - return durationToTimestamp(opts.delay); + return durationToTimestamp(opts.delay); } else { throw new Error('Invalid clock mode'); } @@ -310,7 +334,7 @@ function getVotingDelay(opts: Required): number { function getVotingPeriod(opts: Required): number { try { if (opts.clockMode === 'timestamp') { - return durationToTimestamp(opts.period); + return durationToTimestamp(opts.period); } else { throw new Error('Invalid clock mode'); } @@ -333,7 +357,10 @@ function validateDecimals(decimals: number) { } } -function getProposalThreshold({ proposalThreshold, decimals, votes }: Required): {value: string, comment?: string} { +function getProposalThreshold({ proposalThreshold, decimals, votes }: Required): { + value: string; + comment?: string; +} { if (!/^\d+$/.test(proposalThreshold)) { throw new OptionsError({ proposalThreshold: 'Not a valid number', @@ -343,9 +370,12 @@ function getProposalThreshold({ proposalThreshold, decimals, votes }: Required) c.addFunction(settingsTrait, { name: 'voting_delay', - args: [{ - name: 'self', - type: '@GovernorComponent::ComponentState' - }], + args: [ + { + name: 'self', + type: '@GovernorComponent::ComponentState', + }, + ], returns: 'u64', code: ['VOTING_DELAY'], }); c.addFunction(settingsTrait, { name: 'voting_period', - args: [{ - name: 'self', - type: '@GovernorComponent::ComponentState' - }], + args: [ + { + name: 'self', + type: '@GovernorComponent::ComponentState', + }, + ], returns: 'u64', code: ['VOTING_PERIOD'], }); c.addFunction(settingsTrait, { name: 'proposal_threshold', - args: [{ - name: 'self', - type: '@GovernorComponent::ComponentState' - }], + args: [ + { + name: 'self', + type: '@GovernorComponent::ComponentState', + }, + ], returns: 'u256', code: ['PROPOSAL_THRESHOLD'], }); @@ -399,8 +435,7 @@ function addQuorumAndVotes(c: ContractBuilder, allOpts: Required) { - c.addUseClause(`${extensionPath}::GovernorVotesComponent`, 'InternalTrait', { alias: 'GovernorVotesInternalTrait' }); - c.addComponent(components.GovernorVotesComponent, [ - { lit: 'votes_token' }, - ], true); + c.addUseClause(`${extensionPath}::GovernorVotesComponent`, 'InternalTrait', { + alias: 'GovernorVotesInternalTrait', + }); + c.addComponent(components.GovernorVotesComponent, [{ lit: 'votes_token' }], true); } function addQuorumLocalImpl(c: ContractBuilder, quorum: string, comment: string) { @@ -463,13 +501,16 @@ function addQuorumLocalImpl(c: ContractBuilder, quorum: string, comment: string) c.addFunction(quorumTrait, { name: 'quorum', - args: [{ - name: 'self', - type: '@GovernorComponent::ComponentState' - }, { - name: 'timepoint', - type: 'u64', - }], + args: [ + { + name: 'self', + type: '@GovernorComponent::ComponentState', + }, + { + name: 'timepoint', + type: 'u64', + }, + ], returns: 'u256', code: ['QUORUM'], }); @@ -483,11 +524,14 @@ function addExecution(c: ContractBuilder, { timelock }: Required(value: Kind | T): value is Kind { } } } - diff --git a/packages/core/cairo/src/print.ts b/packages/core/cairo/src/print.ts index d946c1a26..30eecae76 100644 --- a/packages/core/cairo/src/print.ts +++ b/packages/core/cairo/src/print.ts @@ -1,16 +1,26 @@ -import type { Contract, Component, Argument, Value, Impl, ContractFunction, ImplementedTrait, UseClause, } from './contract'; - -import { formatLines, spaceBetween, Lines } from './utils/format-lines'; +import type { + Contract, + Component, + Argument, + Value, + Impl, + ContractFunction, + ImplementedTrait, + UseClause, +} from './contract'; + +import { formatLines, spaceBetween } from './utils/format-lines'; +import type { Lines } from './utils/format-lines'; import { getSelfArg } from './common-options'; import { compatibleContractsSemver } from './utils/version'; const DEFAULT_SECTION = '1. with no section'; const STANDALONE_IMPORTS_GROUP = 'Standalone Imports'; const MAX_USE_CLAUSE_LINE_LENGTH = 90; -const TAB = "\t"; +const TAB = '\t'; export function printContract(contract: Contract): string { - const contractAttribute = contract.account ? '#[starknet::contract(account)]' : '#[starknet::contract]' + const contractAttribute = contract.account ? '#[starknet::contract(account)]' : '#[starknet::contract]'; return formatLines( ...spaceBetween( [ @@ -38,7 +48,7 @@ export function printContract(contract: Contract): string { } function withSemicolons(lines: string[]): string[] { - return lines.map(line => line.endsWith(';') ? line : line + ';'); + return lines.map(line => (line.endsWith(';') ? line : line + ';')); } function printSuperVariables(contract: Contract): string[] { @@ -49,15 +59,14 @@ function printUseClauses(contract: Contract): Lines[] { const useClauses = sortUseClauses(contract); // group by containerPath - const grouped = useClauses.reduce( - (result: { [containerPath: string]: UseClause[] }, useClause: UseClause) => { - if (useClause.groupable) { - (result[useClause.containerPath] = result[useClause.containerPath] || []).push(useClause); - } else { - (result[STANDALONE_IMPORTS_GROUP] = result[STANDALONE_IMPORTS_GROUP] || []).push(useClause); - } - return result; - }, {}); + const grouped = useClauses.reduce((result: { [containerPath: string]: UseClause[] }, useClause: UseClause) => { + if (useClause.groupable) { + (result[useClause.containerPath] = result[useClause.containerPath] || []).push(useClause); + } else { + (result[STANDALONE_IMPORTS_GROUP] = result[STANDALONE_IMPORTS_GROUP] || []).push(useClause); + } + return result; + }, {}); const lines = Object.entries(grouped).flatMap(([groupName, group]) => getLinesFromUseClausesGroup(group, groupName)); return lines.flatMap(line => splitLongUseClauseLine(line.toString())); @@ -73,7 +82,7 @@ function getLinesFromUseClausesGroup(group: UseClause[], groupName: string): Lin if (group.length == 1) { lines.push(`use ${groupName}::${nameWithAlias(group[0]!)};`); } else if (group.length > 1) { - let names = group.map((useClause) => nameWithAlias(useClause)).join(', '); + const names = group.map(useClause => nameWithAlias(useClause)).join(', '); lines.push(`use ${groupName}::{${names}};`); } } @@ -93,7 +102,7 @@ function splitLongUseClauseLine(line: string): Lines[] { // split at the first brace lines.push(line.slice(0, line.indexOf('{') + 1)); lines.push(...splitLongLineInner(line.slice(line.indexOf('{') + 1, -2))); - lines.push("};"); + lines.push('};'); } else { lines.push(line); } @@ -147,7 +156,9 @@ function printConstants(contract: Contract): Lines[] { function printComponentDeclarations(contract: Contract): Lines[] { const lines = []; for (const component of contract.components) { - lines.push(`component!(path: ${component.name}, storage: ${component.substorage.name}, event: ${component.event.name});`); + lines.push( + `component!(path: ${component.name}, storage: ${component.substorage.name}, event: ${component.event.name});`, + ); } return lines; } @@ -156,19 +167,18 @@ function printImpls(contract: Contract): Lines[] { const impls = contract.components.flatMap(c => c.impls); // group by section - const grouped = impls.reduce( - (result: { [section: string]: Impl[] }, current:Impl) => { - // default section depends on embed - // embed defaults to true - const embed = current.embed ?? true; - const section = current.section ?? (embed ? 'External' : 'Internal'); - (result[section] = result[section] || []).push(current); - return result; - }, {}); - - const sections = Object.entries(grouped).sort((a, b) => a[0].localeCompare(b[0])).map( - ([section, impls]) => printSection(section, impls as Impl[]), - ); + const grouped = impls.reduce((result: { [section: string]: Impl[] }, current: Impl) => { + // default section depends on embed + // embed defaults to true + const embed = current.embed ?? true; + const section = current.section ?? (embed ? 'External' : 'Internal'); + (result[section] = result[section] || []).push(current); + return result; + }, {}); + + const sections = Object.entries(grouped) + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([section, impls]) => printSection(section, impls as Impl[])); return spaceBetween(...sections); } @@ -209,7 +219,7 @@ function printEvents(contract: Contract): (string | string[])[] { if (contract.components.length > 0) { lines.push('#[event]'); lines.push('#[derive(Drop, starknet::Event)]'); - lines.push('enum Event {') + lines.push('enum Event {'); const eventLines = []; for (const component of contract.components) { eventLines.push('#[flat]'); @@ -235,17 +245,19 @@ function printImplementedTraits(contract: Contract): Lines[] { // group by section const grouped = sortedTraits.reduce( - (result: { [section: string]: ImplementedTrait[] }, current:ImplementedTrait) => { + (result: { [section: string]: ImplementedTrait[] }, current: ImplementedTrait) => { // default to no section const section = current.section ?? DEFAULT_SECTION; (result[section] = result[section] || []).push(current); return result; - }, {}); - - const sections = Object.entries(grouped).sort((a, b) => a[0].localeCompare(b[0])).map( - ([section, impls]) => printImplementedTraitsSection(section, impls as ImplementedTrait[]), + }, + {}, ); + const sections = Object.entries(grouped) + .sort((a, b) => a[0].localeCompare(b[0])) + .map(([section, impls]) => printImplementedTraitsSection(section, impls as ImplementedTrait[])); + return spaceBetween(...sections); } @@ -271,9 +283,7 @@ function printImplementedTrait(trait: ImplementedTrait): Lines[] { implLines.push(...trait.tags.map(t => `#[${t}]`)); implLines.push(`impl ${trait.name} of ${trait.of} {`); - const superVars = withSemicolons( - trait.superVariables.map(v => `const ${v.name}: ${v.type} = ${v.value}`) - ); + const superVars = withSemicolons(trait.superVariables.map(v => `const ${v.name}: ${v.type} = ${v.value}`)); implLines.push(superVars); const fns = trait.functions.map(fn => printFunction(fn)); @@ -306,17 +316,12 @@ function printConstructor(contract: Contract): Lines[] { const hasInitializers = contract.components.some(p => p.initializer !== undefined); const hasConstructorCode = contract.constructorCode.length > 0; if (hasInitializers || hasConstructorCode) { - const parents = contract.components - .filter(hasInitializer) - .flatMap(p => printParentConstructor(p)); + const parents = contract.components.filter(hasInitializer).flatMap(p => printParentConstructor(p)); const tag = 'constructor'; const head = 'fn constructor'; - const args = [ getSelfArg(), ...contract.constructorArgs ]; + const args = [getSelfArg(), ...contract.constructorArgs]; - const body = spaceBetween( - withSemicolons(parents), - withSemicolons(contract.constructorCode), - ); + const body = spaceBetween(withSemicolons(parents), withSemicolons(contract.constructorCode)); const constructor = printFunction2( head, @@ -341,9 +346,7 @@ function printParentConstructor({ substorage, initializer }: Component): [] | [s return []; } const fn = `self.${substorage.name}.initializer`; - return [ - fn + '(' + initializer.params.map(printValue).join(', ') + ')', - ]; + return [fn + '(' + initializer.params.map(printValue).join(', ') + ')']; } export function printValue(value: Value): string { @@ -363,7 +366,7 @@ export function printValue(value: Value): string { throw new Error(`Number not representable (${value})`); } } else if (typeof value === 'bigint') { - return `${value}` + return `${value}`; } else { return `"${value}"`; } @@ -377,7 +380,7 @@ function printFunction2( tag: string | undefined, returns: string | undefined, returnLine: string | undefined, - code: Lines[] + code: Lines[], ): Lines[] { const fn = []; diff --git a/packages/core/cairo/src/scripts/update-scarb-project.ts b/packages/core/cairo/src/scripts/update-scarb-project.ts index 022e74759..b6ee6a901 100644 --- a/packages/core/cairo/src/scripts/update-scarb-project.ts +++ b/packages/core/cairo/src/scripts/update-scarb-project.ts @@ -27,8 +27,8 @@ async function writeLibCairo(contractNames: string[]) { async function updateScarbToml() { const scarbTomlPath = path.join('test_project', 'Scarb.toml'); - let currentContent = await fs.readFile(scarbTomlPath, 'utf8'); - let updatedContent = currentContent + const currentContent = await fs.readFile(scarbTomlPath, 'utf8'); + const updatedContent = currentContent .replace(/edition = "\w+"/, `edition = "${edition}"`) .replace(/cairo-version = "\d+\.\d+\.\d+"/, `cairo-version = "${cairoVersion}"`) .replace(/scarb-version = "\d+\.\d+\.\d+"/, `scarb-version = "${scarbVersion}"`) diff --git a/packages/core/cairo/src/set-access-control.ts b/packages/core/cairo/src/set-access-control.ts index 7bd3c2218..d567c15c8 100644 --- a/packages/core/cairo/src/set-access-control.ts +++ b/packages/core/cairo/src/set-access-control.ts @@ -5,18 +5,18 @@ import { addSRC5Component } from './common-components'; export const accessOptions = [false, 'ownable', 'roles'] as const; export const DEFAULT_ACCESS_CONTROL = 'ownable'; -export type Access = typeof accessOptions[number]; +export type Access = (typeof accessOptions)[number]; /** * Sets access control for the contract by adding inheritance. */ - export function setAccessControl(c: ContractBuilder, access: Access): void { +export function setAccessControl(c: ContractBuilder, access: Access): void { switch (access) { case 'ownable': { c.addComponent(components.OwnableComponent, [{ lit: 'owner' }], true); c.addUseClause('starknet', 'ContractAddress'); - c.addConstructorArgument({ name: 'owner', type: 'ContractAddress'}); + c.addConstructorArgument({ name: 'owner', type: 'ContractAddress' }); break; } @@ -41,7 +41,10 @@ export type Access = typeof accessOptions[number]; addSRC5Component(c); c.addUseClause('starknet', 'ContractAddress'); - c.addConstructorArgument({ name: 'default_admin', type: 'ContractAddress'}); + c.addConstructorArgument({ + name: 'default_admin', + type: 'ContractAddress', + }); c.addUseClause('openzeppelin::access::accesscontrol', 'DEFAULT_ADMIN_ROLE'); c.addConstructorCode('self.accesscontrol._grant_role(DEFAULT_ADMIN_ROLE, default_admin)'); @@ -55,12 +58,12 @@ 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, - trait: BaseImplementedTrait, - fn: BaseFunction, - access: Access, - roleIdPrefix: string, - roleOwner: string | undefined + c: ContractBuilder, + trait: BaseImplementedTrait, + fn: BaseFunction, + access: Access, + roleIdPrefix: string, + roleOwner: string | undefined, ): void { if (access === false) { access = DEFAULT_ACCESS_CONTROL; @@ -74,10 +77,14 @@ export function requireAccessControl( } case 'roles': { const roleId = roleIdPrefix + '_ROLE'; - const addedSuper = c.addSuperVariable({ name: roleId, type: 'felt252', value: `selector!("${roleId}")` }) + const addedSuper = c.addSuperVariable({ + name: roleId, + type: 'felt252', + value: `selector!("${roleId}")`, + }); if (roleOwner !== undefined) { c.addUseClause('starknet', 'ContractAddress'); - c.addConstructorArgument({ name: roleOwner, type: 'ContractAddress'}); + c.addConstructorArgument({ name: roleOwner, type: 'ContractAddress' }); if (addedSuper) { c.addConstructorCode(`self.accesscontrol._grant_role(${roleId}, ${roleOwner})`); } @@ -90,7 +97,7 @@ export function requireAccessControl( } } -const components = defineComponents( { +const components = defineComponents({ OwnableComponent: { path: 'openzeppelin::access::ownable', substorage: { @@ -101,14 +108,17 @@ const components = defineComponents( { name: 'OwnableEvent', type: 'OwnableComponent::Event', }, - impls: [{ - name: 'OwnableMixinImpl', - value: 'OwnableComponent::OwnableMixinImpl', - }, { - name: 'OwnableInternalImpl', - embed: false, - value: 'OwnableComponent::InternalImpl', - }], + impls: [ + { + name: 'OwnableMixinImpl', + value: 'OwnableComponent::OwnableMixinImpl', + }, + { + name: 'OwnableInternalImpl', + embed: false, + value: 'OwnableComponent::InternalImpl', + }, + ], }, AccessControlComponent: { path: 'openzeppelin::access::accesscontrol', @@ -120,10 +130,12 @@ const components = defineComponents( { name: 'AccessControlEvent', type: 'AccessControlComponent::Event', }, - impls: [{ - name: 'AccessControlInternalImpl', - embed: false, - value: 'AccessControlComponent::InternalImpl', - }], + impls: [ + { + name: 'AccessControlInternalImpl', + embed: false, + value: 'AccessControlComponent::InternalImpl', + }, + ], }, }); diff --git a/packages/core/cairo/src/set-info.ts b/packages/core/cairo/src/set-info.ts index 421a15029..232662ae8 100644 --- a/packages/core/cairo/src/set-info.ts +++ b/packages/core/cairo/src/set-info.ts @@ -1,4 +1,4 @@ -import type { ContractBuilder } from "./contract"; +import type { ContractBuilder } from './contract'; export const infoOptions = [{}, { license: 'WTFPL' }] as const; @@ -6,7 +6,7 @@ export const defaults: Info = { license: 'MIT' }; export type Info = { license?: string; -} +}; export function setInfo(c: ContractBuilder, info: Info): void { const { license } = info; diff --git a/packages/core/cairo/src/set-royalty-info.ts b/packages/core/cairo/src/set-royalty-info.ts index 5464be105..cd3920db8 100644 --- a/packages/core/cairo/src/set-royalty-info.ts +++ b/packages/core/cairo/src/set-royalty-info.ts @@ -1,15 +1,16 @@ import type { BaseImplementedTrait, ContractBuilder } from './contract'; import { defineComponents } from './utils/define-components'; -import { OptionsError } from "./error"; +import { OptionsError } from './error'; import { toUint } from './utils/convert-strings'; -import { Access, setAccessControl, DEFAULT_ACCESS_CONTROL } from './set-access-control'; +import type { Access } from './set-access-control'; +import { setAccessControl, DEFAULT_ACCESS_CONTROL } from './set-access-control'; const DEFAULT_FEE_DENOMINATOR = BigInt(10_000); export const defaults: RoyaltyInfoOptions = { enabled: false, defaultRoyaltyFraction: '0', - feeDenominator: DEFAULT_FEE_DENOMINATOR.toString() + feeDenominator: DEFAULT_FEE_DENOMINATOR.toString(), }; export const royaltyInfoOptions = { @@ -23,13 +24,13 @@ export const royaltyInfoOptions = { enabled: true, defaultRoyaltyFraction: '15125', feeDenominator: '100000', - } -} + }, +}; export type RoyaltyInfoOptions = { - enabled: boolean, - defaultRoyaltyFraction: string, - feeDenominator: string, + enabled: boolean; + defaultRoyaltyFraction: string; + feeDenominator: string; }; export function setRoyaltyInfo(c: ContractBuilder, options: RoyaltyInfoOptions, access: Access): void { @@ -42,14 +43,14 @@ export function setRoyaltyInfo(c: ContractBuilder, options: RoyaltyInfoOptions, setAccessControl(c, access); const { defaultRoyaltyFraction, feeDenominator } = getRoyaltyParameters(options); - const initParams = [ - { lit: 'default_royalty_receiver' }, - defaultRoyaltyFraction - ]; + const initParams = [{ lit: 'default_royalty_receiver' }, defaultRoyaltyFraction]; c.addComponent(components.ERC2981Component, initParams, true); c.addUseClause('starknet', 'ContractAddress'); - c.addConstructorArgument({ name: 'default_royalty_receiver', type: 'ContractAddress'}); + c.addConstructorArgument({ + name: 'default_royalty_receiver', + type: 'ContractAddress', + }); switch (access) { case 'ownable': @@ -63,7 +64,10 @@ export function setRoyaltyInfo(c: ContractBuilder, options: RoyaltyInfoOptions, name: 'ERC2981AdminAccessControlImpl', value: `ERC2981Component::ERC2981AdminAccessControlImpl`, }); - c.addConstructorArgument({ name: 'royalty_admin', type: 'ContractAddress'}); + c.addConstructorArgument({ + name: 'royalty_admin', + type: 'ContractAddress', + }); c.addConstructorCode('self.accesscontrol._grant_role(ERC2981Component::ROYALTY_ADMIN_ROLE, royalty_admin)'); break; } @@ -80,22 +84,25 @@ export function setRoyaltyInfo(c: ContractBuilder, options: RoyaltyInfoOptions, c.addSuperVariableToTrait(trait, { name: 'FEE_DENOMINATOR', type: 'u128', - value: feeDenominator.toString() + value: feeDenominator.toString(), }); } } -function getRoyaltyParameters(opts: Required): { defaultRoyaltyFraction: bigint, feeDenominator: bigint } { +function getRoyaltyParameters(opts: Required): { + defaultRoyaltyFraction: bigint; + feeDenominator: bigint; +} { const feeDenominator = toUint(opts.feeDenominator, 'feeDenominator', 'u128'); if (feeDenominator === BigInt(0)) { throw new OptionsError({ - feeDenominator: 'Must be greater than 0' + feeDenominator: 'Must be greater than 0', }); } const defaultRoyaltyFraction = toUint(opts.defaultRoyaltyFraction, 'defaultRoyaltyFraction', 'u128'); if (defaultRoyaltyFraction > feeDenominator) { throw new OptionsError({ - defaultRoyaltyFraction: 'Cannot be greater than fee denominator' + defaultRoyaltyFraction: 'Cannot be greater than fee denominator', }); } return { defaultRoyaltyFraction, feeDenominator }; @@ -124,8 +131,8 @@ const components = defineComponents({ { name: 'ERC2981InternalImpl', value: 'ERC2981Component::InternalImpl', - embed: false - } + embed: false, + }, ], }, }); diff --git a/packages/core/cairo/src/set-upgradeable.ts b/packages/core/cairo/src/set-upgradeable.ts index 65a944128..8948c419a 100644 --- a/packages/core/cairo/src/set-upgradeable.ts +++ b/packages/core/cairo/src/set-upgradeable.ts @@ -1,13 +1,14 @@ import { getSelfArg } from './common-options'; import type { BaseImplementedTrait, ContractBuilder } from './contract'; -import { Access, requireAccessControl } from './set-access-control'; +import type { Access } from './set-access-control'; +import { requireAccessControl } from './set-access-control'; import { defineComponents } from './utils/define-components'; import { defineFunctions } from './utils/define-functions'; import type { Account } from './account'; export const upgradeableOptions = [false, true] as const; -export type Upgradeable = typeof upgradeableOptions[number]; +export type Upgradeable = (typeof upgradeableOptions)[number]; function setUpgradeableBase(c: ContractBuilder, upgradeable: Upgradeable): BaseImplementedTrait | undefined { if (upgradeable === false) { @@ -25,9 +26,7 @@ function setUpgradeableBase(c: ContractBuilder, upgradeable: Upgradeable): BaseI name: 'UpgradeableImpl', of: 'IUpgradeable', section: 'Upgradeable', - tags: [ - 'abi(embed_v0)' - ], + tags: ['abi(embed_v0)'], }; c.addImplementedTrait(t); @@ -63,7 +62,7 @@ export function setAccountUpgradeable(c: ContractBuilder, upgradeable: Upgradeab } } -const components = defineComponents( { +const components = defineComponents({ UpgradeableComponent: { path: 'openzeppelin::upgrades', substorage: { @@ -74,22 +73,19 @@ const components = defineComponents( { name: 'UpgradeableEvent', type: 'UpgradeableComponent::Event', }, - impls: [{ - name: 'UpgradeableInternalImpl', - embed: false, - value: 'UpgradeableComponent::InternalImpl', - }], + impls: [ + { + name: 'UpgradeableInternalImpl', + embed: false, + value: 'UpgradeableComponent::InternalImpl', + }, + ], }, }); const functions = defineFunctions({ upgrade: { - args: [ - getSelfArg(), - { name: 'new_class_hash', type: 'ClassHash' }, - ], - code: [ - 'self.upgradeable.upgrade(new_class_hash)' - ] + args: [getSelfArg(), { name: 'new_class_hash', type: 'ClassHash' }], + code: ['self.upgradeable.upgrade(new_class_hash)'], }, }); diff --git a/packages/core/cairo/src/test.ts b/packages/core/cairo/src/test.ts index 967e17ece..28c6dbdc1 100644 --- a/packages/core/cairo/src/test.ts +++ b/packages/core/cairo/src/test.ts @@ -1,6 +1,7 @@ import { promises as fs } from 'fs'; import os from 'os'; -import _test, { TestFn, ExecutionContext } from 'ava'; +import type { TestFn, ExecutionContext } from 'ava'; +import _test from 'ava'; import path from 'path'; import { generateSources, writeGeneratedSources } from './generate/sources'; @@ -8,7 +9,7 @@ import type { GenericOptions, KindedOptions } from './build-generic'; import { custom, erc20, erc721, erc1155 } from './api'; interface Context { - generatedSourcesPath: string + generatedSourcesPath: string; } const test = _test as TestFn; @@ -42,7 +43,7 @@ async function testGenerate(t: ExecutionContext, kind: keyof KindedOpti } function isAccessControlRequired(opts: GenericOptions) { - switch(opts.kind) { + switch (opts.kind) { case 'ERC20': return erc20.isAccessControlRequired(opts); case 'ERC721': @@ -50,11 +51,11 @@ function isAccessControlRequired(opts: GenericOptions) { case 'ERC1155': return erc1155.isAccessControlRequired(opts); case 'Account': - throw new Error("Not applicable for accounts"); + throw new Error('Not applicable for accounts'); case 'Custom': return custom.isAccessControlRequired(opts); default: - throw new Error("No such kind"); + throw new Error('No such kind'); } } @@ -80,9 +81,10 @@ test('is access control required', async t => { } } break; - default: + default: { const _: never = contract.options; throw new Error('Unknown kind'); + } } } }); diff --git a/packages/core/cairo/src/utils/convert-strings.test.ts b/packages/core/cairo/src/utils/convert-strings.test.ts index 8a1421343..51bb4a7a9 100644 --- a/packages/core/cairo/src/utils/convert-strings.test.ts +++ b/packages/core/cairo/src/utils/convert-strings.test.ts @@ -33,12 +33,14 @@ test('identifier - remove starting numbers', t => { }); test('identifier - empty string', t => { - let error = t.throws(() => toIdentifier(''), { instanceOf: OptionsError }); + const error = t.throws(() => toIdentifier(''), { instanceOf: OptionsError }); t.is(error.messages.name, 'Identifier is empty or does not have valid characters'); }); test('identifier - no valid chars', t => { - let error = t.throws(() => toIdentifier('123'), { instanceOf: OptionsError }); + const error = t.throws(() => toIdentifier('123'), { + instanceOf: OptionsError, + }); t.is(error.messages.name, 'Identifier is empty or does not have valid characters'); }); @@ -55,7 +57,7 @@ test('toByteArray - remove non-ascii-printable characters', t => { }); test('toByteArray - escape double quote', t => { - t.is(toByteArray("abc\"def"), "abc\\\"def"); + t.is(toByteArray('abc"def'), 'abc\\"def'); }); test('toByteArray - does not escape single quote', t => { @@ -94,6 +96,6 @@ test('toFelt252 - escape backslash', t => { test('toFelt252 - max 31 characters', t => { t.is(toFelt252('A234567890123456789012345678901', 'foo'), 'A234567890123456789012345678901'); - let error = t.throws(() => toFelt252('A2345678901234567890123456789012', 'foo'), { instanceOf: OptionsError }); + const error = t.throws(() => toFelt252('A2345678901234567890123456789012', 'foo'), { instanceOf: OptionsError }); 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 d1681ec09..4f00d33d9 100644 --- a/packages/core/cairo/src/utils/convert-strings.ts +++ b/packages/core/cairo/src/utils/convert-strings.ts @@ -1,13 +1,14 @@ -import { OptionsError } from "../error"; +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 { const result = str - .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') // remove accents .replace(/^[^a-zA-Z_]+/, '') - .replace(/^(.)/, c => capitalize ? c.toUpperCase() : c) + .replace(/^(.)/, c => (capitalize ? c.toUpperCase() : c)) .replace(/[^\w]+(.?)/g, (_, c) => c.toUpperCase()); if (result.length === 0) { @@ -24,7 +25,8 @@ export function toIdentifier(str: string, capitalize = false): string { */ export function toByteArray(str: string): string { return str - .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') // remove accents .replace(/[^\x20-\x7E]+/g, '') // remove non-ascii-printable characters .replace(/(\\|")/g, (_, c) => '\\' + c); // escape backslash or double quotes } @@ -34,7 +36,8 @@ export function toByteArray(str: string): string { */ export function toFelt252(str: string, field: string): string { const result = str - .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents + .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 @@ -49,22 +52,22 @@ export function toFelt252(str: string, field: string): string { function maxValueOfUint(bits: number): bigint { if (bits <= 0) { - throw new Error(`Number of bits must be positive (actual '${bits}').`) + throw new Error(`Number of bits must be positive (actual '${bits}').`); } if (bits % 8 !== 0) { - throw new Error(`The number of bits must be a multiple of 8 (actual '${bits}').`) + throw new Error(`The number of bits must be a multiple of 8 (actual '${bits}').`); } const bytes = bits / 8; - return BigInt('0x' + 'ff'.repeat(bytes)) + return BigInt('0x' + 'ff'.repeat(bytes)); } const UINT_MAX_VALUES = { - 'u8': maxValueOfUint(8), - 'u16': maxValueOfUint(16), - 'u32': maxValueOfUint(32), - 'u64': maxValueOfUint(64), - 'u128': maxValueOfUint(128), - 'u256': maxValueOfUint(256) + u8: maxValueOfUint(8), + u16: maxValueOfUint(16), + u32: maxValueOfUint(32), + u64: maxValueOfUint(64), + u128: maxValueOfUint(128), + u256: maxValueOfUint(256), } as const; export type UintType = keyof typeof UINT_MAX_VALUES; @@ -73,17 +76,17 @@ export type UintType = keyof typeof UINT_MAX_VALUES; * Checks that a string/number value is a valid `uint` value and converts it to bigint */ export function toUint(value: number | string, field: string, type: UintType): bigint { - const valueAsStr = value.toString(); + const valueAsStr = value.toString(); const isValidNumber = /^\d+$/.test(valueAsStr); if (!isValidNumber) { throw new OptionsError({ - [field]: 'Not a valid number' + [field]: 'Not a valid number', }); } const numValue = BigInt(valueAsStr); if (numValue > UINT_MAX_VALUES[type]) { throw new OptionsError({ - [field]: `Value is greater than ${type} max value` + [field]: `Value is greater than ${type} max value`, }); } return numValue; diff --git a/packages/core/cairo/src/utils/define-components.ts b/packages/core/cairo/src/utils/define-components.ts index 62ba3ca6e..4fb13f4b2 100644 --- a/packages/core/cairo/src/utils/define-components.ts +++ b/packages/core/cairo/src/utils/define-components.ts @@ -2,17 +2,8 @@ import type { Component } from '../contract'; type ImplicitNameComponent = Omit; -export function defineComponents( - fns: Record, -): Record; +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), - ]), - ); +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-functions.ts b/packages/core/cairo/src/utils/define-functions.ts index c1f664e7e..3c89e6c76 100644 --- a/packages/core/cairo/src/utils/define-functions.ts +++ b/packages/core/cairo/src/utils/define-functions.ts @@ -2,17 +2,8 @@ import type { BaseFunction } from '../contract'; type ImplicitNameFunction = Omit; -export function defineFunctions( - fns: Record, -): Record; +export function defineFunctions(fns: Record): Record; -export function defineFunctions( - fns: Record, -): Record { - return Object.fromEntries( - Object.entries(fns).map(([name, fn]) => [ - name, - Object.assign({ name }, fn), - ]), - ); +export function defineFunctions(fns: Record): Record { + return Object.fromEntries(Object.entries(fns).map(([name, fn]) => [name, Object.assign({ name }, fn)])); } diff --git a/packages/core/cairo/src/utils/duration.ts b/packages/core/cairo/src/utils/duration.ts index ffc2fe5b5..cfbaf279e 100644 --- a/packages/core/cairo/src/utils/duration.ts +++ b/packages/core/cairo/src/utils/duration.ts @@ -1,5 +1,5 @@ const durationUnits = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year'] as const; -type DurationUnit = typeof durationUnits[number]; +type DurationUnit = (typeof durationUnits)[number]; export const durationPattern = new RegExp(`^(\\d+(?:\\.\\d+)?) +(${durationUnits.join('|')})s?$`); const second = 1; diff --git a/packages/core/cairo/src/utils/format-lines.ts b/packages/core/cairo/src/utils/format-lines.ts index 5e18a0c4a..52af7ab52 100644 --- a/packages/core/cairo/src/utils/format-lines.ts +++ b/packages/core/cairo/src/utils/format-lines.ts @@ -6,10 +6,7 @@ export function formatLines(...lines: Lines[]): string { return [...indentEach(0, lines)].join('\n') + '\n'; } -function* indentEach( - indent: number, - lines: Lines[], -): Generator { +function* indentEach(indent: number, lines: Lines[]): Generator { for (const line of lines) { if (line === whitespace) { yield ''; diff --git a/packages/core/cairo/src/utils/version.test.ts b/packages/core/cairo/src/utils/version.test.ts index 5b580626c..735d62527 100644 --- a/packages/core/cairo/src/utils/version.test.ts +++ b/packages/core/cairo/src/utils/version.test.ts @@ -5,7 +5,9 @@ import semver from 'semver'; import { contractsVersion, compatibleContractsSemver } from './version'; test('latest target contracts satisfies compatible range', t => { - t.true(semver.satisfies(contractsVersion, compatibleContractsSemver), + t.true( + semver.satisfies(contractsVersion, compatibleContractsSemver), `Latest target contracts version ${contractsVersion} does not satisfy compatible range ${compatibleContractsSemver}. -Check whether the compatible range is up to date.`); +Check whether the compatible range is up to date.`, + ); }); diff --git a/packages/core/cairo/src/vesting.test.ts b/packages/core/cairo/src/vesting.test.ts index 3f9ead374..76139b28b 100644 --- a/packages/core/cairo/src/vesting.test.ts +++ b/packages/core/cairo/src/vesting.test.ts @@ -1,6 +1,8 @@ import test from 'ava'; -import { OptionsError, vesting } from '.'; -import { buildVesting, VestingOptions } from './vesting'; +import type { OptionsError } from '.'; +import { vesting } from '.'; +import type { VestingOptions } from './vesting'; +import { buildVesting } from './vesting'; import { printContract } from './print'; const defaults: VestingOptions = { @@ -8,7 +10,7 @@ const defaults: VestingOptions = { startDate: '', duration: '0 day', cliffDuration: '0 day', - schedule: 'linear' + schedule: 'linear', }; const CUSTOM_NAME = 'CustomVesting'; @@ -24,7 +26,7 @@ function testVesting(title: string, opts: Partial) { test(title, t => { const c = buildVesting({ ...defaults, - ...opts + ...opts, }); t.snapshot(printContract(c)); }); @@ -32,10 +34,15 @@ function testVesting(title: string, opts: Partial) { function testAPIEquivalence(title: string, opts?: VestingOptions) { test(title, t => { - t.is(vesting.print(opts), printContract(buildVesting({ - ...defaults, - ...opts - }))); + t.is( + vesting.print(opts), + printContract( + buildVesting({ + ...defaults, + ...opts, + }), + ), + ); }); } @@ -48,27 +55,27 @@ testVesting('custom name', { }); testVesting('custom start date', { - startDate: CUSTOM_DATE + startDate: CUSTOM_DATE, }); testVesting('custom duration', { - duration: CUSTOM_DURATION + duration: CUSTOM_DURATION, }); testVesting('custom cliff', { duration: CUSTOM_DURATION, - cliffDuration: CUSTOM_CLIFF + cliffDuration: CUSTOM_CLIFF, }); testVesting('custom schedule', { - schedule: 'custom' + schedule: 'custom', }); testVesting('all custom settings', { startDate: CUSTOM_DATE, duration: CUSTOM_DURATION, cliffDuration: CUSTOM_CLIFF, - schedule: 'custom' + schedule: 'custom', }); // @@ -77,28 +84,28 @@ testVesting('all custom settings', { testAPIEquivalence('API custom name', { ...defaults, - name: CUSTOM_NAME + name: CUSTOM_NAME, }); testAPIEquivalence('API custom start date', { ...defaults, - startDate: CUSTOM_DATE + startDate: CUSTOM_DATE, }); testAPIEquivalence('API custom duration', { ...defaults, - duration: CUSTOM_DURATION + duration: CUSTOM_DURATION, }); testAPIEquivalence('API custom cliff', { ...defaults, duration: CUSTOM_DURATION, - cliffDuration: CUSTOM_CLIFF + cliffDuration: CUSTOM_CLIFF, }); testAPIEquivalence('API custom schedule', { ...defaults, - schedule: 'custom' + schedule: 'custom', }); testAPIEquivalence('API all custom settings', { @@ -106,14 +113,19 @@ testAPIEquivalence('API all custom settings', { startDate: CUSTOM_DATE, duration: CUSTOM_DURATION, cliffDuration: CUSTOM_CLIFF, - schedule: 'custom' + schedule: 'custom', }); test('cliff too high', async t => { - const error = t.throws(() => buildVesting({ - ...defaults, - duration: '20 days', - cliffDuration: '21 days' - })); - t.is((error as OptionsError).messages.cliffDuration, 'Cliff duration must be less than or equal to the total duration'); + const error = t.throws(() => + buildVesting({ + ...defaults, + duration: '20 days', + cliffDuration: '21 days', + }), + ); + t.is( + (error as OptionsError).messages.cliffDuration, + 'Cliff duration must be less than or equal to the total duration', + ); }); diff --git a/packages/core/cairo/src/vesting.ts b/packages/core/cairo/src/vesting.ts index 51c6512f2..451c42a80 100644 --- a/packages/core/cairo/src/vesting.ts +++ b/packages/core/cairo/src/vesting.ts @@ -1,8 +1,10 @@ -import { BaseImplementedTrait, Contract, ContractBuilder } from './contract'; +import type { BaseImplementedTrait, Contract } from './contract'; +import { ContractBuilder } from './contract'; import { contractDefaults as commonDefaults } from './common-options'; import { setAccessControl } from './set-access-control'; import { setUpgradeable } from './set-upgradeable'; -import { Info, setInfo } from './set-info'; +import type { Info } from './set-info'; +import { setInfo } from './set-info'; import { defineComponents } from './utils/define-components'; import { printContract } from './print'; import { OptionsError } from './error'; @@ -17,7 +19,7 @@ export const defaults: Required = { duration: '0 day', cliffDuration: '0 day', schedule: 'custom', - info: commonDefaults.info + info: commonDefaults.info, } as const; export function printVesting(opts: VestingOptions = defaults): string { @@ -40,7 +42,7 @@ function withDefaults(opts: VestingOptions): Required { duration: opts.duration ?? defaults.duration, cliffDuration: opts.cliffDuration ?? defaults.cliffDuration, schedule: opts.schedule ?? defaults.schedule, - info: opts.info ?? defaults.info + info: opts.info ?? defaults.info, }; } @@ -74,13 +76,13 @@ function addBase(c: ContractBuilder, opts: VestingOptions) { type: 'u64', value: startDate.timestampInSec.toString(), comment: startDate.formattedDate, - inlineComment: true + inlineComment: true, }); } else { c.addConstant({ name: 'START', type: 'u64', - value: '0' + value: '0', }); } c.addConstant({ @@ -88,14 +90,14 @@ function addBase(c: ContractBuilder, opts: VestingOptions) { type: 'u64', value: totalDuration.toString(), comment: opts.duration, - inlineComment: true + inlineComment: true, }); c.addConstant({ name: 'CLIFF_DURATION', type: 'u64', value: cliffDuration.toString(), comment: opts.cliffDuration, - inlineComment: true + inlineComment: true, }); const initParams = [{ lit: 'START' }, { lit: 'DURATION' }, { lit: 'CLIFF_DURATION' }]; c.addComponent(components.VestingComponent, initParams, true); @@ -106,7 +108,7 @@ function addSchedule(c: ContractBuilder, opts: VestingOptions) { case 'linear': c.addUseClause('openzeppelin::finance::vesting', 'LinearVestingSchedule'); return; - case 'custom': + case 'custom': { const scheduleTrait: BaseImplementedTrait = { name: `VestingSchedule`, of: 'VestingComponent::VestingScheduleTrait', @@ -118,34 +120,31 @@ function addSchedule(c: ContractBuilder, opts: VestingOptions) { name: 'calculate_vested_amount', returns: 'u256', args: [ - { name: 'self', type: `@VestingComponent::ComponentState` }, + { + name: 'self', + type: `@VestingComponent::ComponentState`, + }, { name: 'token', type: 'ContractAddress' }, { name: 'total_allocation', type: 'u256' }, { name: 'timestamp', type: 'u64' }, { name: 'start', type: 'u64' }, { name: 'duration', type: 'u64' }, - { name: 'cliff', type: 'u64' } - ], - code: [ - '// TODO: Must be implemented according to the desired vesting schedule', - '0', + { name: 'cliff', type: 'u64' }, ], + code: ['// TODO: Must be implemented according to the desired vesting schedule', '0'], }); return; + } } } -function getVestingStart(opts: VestingOptions): { timestampInSec: bigint, formattedDate: string } | undefined { +function getVestingStart(opts: VestingOptions): { timestampInSec: bigint; formattedDate: string } | undefined { if (opts.startDate === '' || opts.startDate === 'NaN') { return undefined; } const startDate = new Date(`${opts.startDate}Z`); const timestampInMillis = startDate.getTime(); - const timestampInSec = toUint( - Math.floor(timestampInMillis / 1000), - 'startDate', - 'u64' - ); + const timestampInSec = toUint(Math.floor(timestampInMillis / 1000), 'startDate', 'u64'); const formattedDate = startDate.toLocaleString('en-GB', { day: '2-digit', month: 'short', @@ -153,7 +152,7 @@ function getVestingStart(opts: VestingOptions): { timestampInSec: bigint, format hour: '2-digit', minute: '2-digit', hour12: false, - timeZone: 'UTC' + timeZone: 'UTC', }); return { timestampInSec, formattedDate: `${formattedDate} (UTC)` }; } @@ -164,7 +163,7 @@ function getVestingDuration(opts: VestingOptions): number { } catch (e) { if (e instanceof Error) { throw new OptionsError({ - duration: e.message + duration: e.message, }); } else { throw e; @@ -178,7 +177,7 @@ function getCliffDuration(opts: VestingOptions): number { } catch (e) { if (e instanceof Error) { throw new OptionsError({ - cliffDuration: e.message + cliffDuration: e.message, }); } else { throw e; @@ -191,7 +190,7 @@ function validateDurations(duration: number, cliffDuration: number): void { validateUint(cliffDuration, 'cliffDuration', 'u64'); if (cliffDuration > duration) { throw new OptionsError({ - cliffDuration: `Cliff duration must be less than or equal to the total duration` + cliffDuration: `Cliff duration must be less than or equal to the total duration`, }); } } @@ -207,13 +206,16 @@ const components = defineComponents({ name: 'VestingEvent', type: 'VestingComponent::Event', }, - impls: [{ - name: 'VestingImpl', - value: 'VestingComponent::VestingImpl' - }, { - name: 'VestingInternalImpl', - embed: false, - value: 'VestingComponent::InternalImpl', - }], - } + impls: [ + { + name: 'VestingImpl', + value: 'VestingComponent::VestingImpl', + }, + { + name: 'VestingInternalImpl', + embed: false, + value: 'VestingComponent::InternalImpl', + }, + ], + }, }); diff --git a/packages/core/solidity/ava.config.js b/packages/core/solidity/ava.config.js index 77a9117a9..e39146f7a 100644 --- a/packages/core/solidity/ava.config.js +++ b/packages/core/solidity/ava.config.js @@ -2,11 +2,7 @@ module.exports = { extensions: ['ts'], require: ['ts-node/register'], watchmode: { - ignoreChanges: [ - 'contracts', - 'artifacts', - 'cache', - ], + ignoreChanges: ['contracts', 'artifacts', 'cache'], }, timeout: '10m', workerThreads: false, diff --git a/packages/core/solidity/get-imports.js b/packages/core/solidity/get-imports.js index c93672cc4..bc85ea526 100644 --- a/packages/core/solidity/get-imports.js +++ b/packages/core/solidity/get-imports.js @@ -1 +1 @@ -module.exports = require('./dist/get-imports'); \ No newline at end of file +module.exports = require('./dist/get-imports'); diff --git a/packages/core/solidity/hardhat.config.js b/packages/core/solidity/hardhat.config.js index 680ecea41..fe8394ddd 100644 --- a/packages/core/solidity/hardhat.config.js +++ b/packages/core/solidity/hardhat.config.js @@ -15,7 +15,7 @@ const IGNORED_WARNINGS = [WARN_UNUSED_PARAMETER, WARN_CODE_SIZE]; // Overriding this task so that warnings are considered errors. task(TASK_COMPILE_SOLIDITY_CHECK_ERRORS, async ({ output, quiet }, { run }) => { - const errors = output.errors && output.errors.filter(e => !IGNORED_WARNINGS.includes(e.errorCode)) || []; + const errors = (output.errors && output.errors.filter(e => !IGNORED_WARNINGS.includes(e.errorCode))) || []; await run(TASK_COMPILE_SOLIDITY_LOG_COMPILATION_ERRORS, { output: { ...output, errors }, @@ -37,7 +37,6 @@ task(TASK_COMPILE_SOLIDITY_MERGE_COMPILATION_JOBS, async ({ compilationJobs }, _ return mergedChunks.flat(); }); - /** * @type import('hardhat/config').HardhatUserConfig */ diff --git a/packages/core/solidity/src/add-pausable.ts b/packages/core/solidity/src/add-pausable.ts index 7877905c7..12fe36288 100644 --- a/packages/core/solidity/src/add-pausable.ts +++ b/packages/core/solidity/src/add-pausable.ts @@ -1,5 +1,6 @@ import type { ContractBuilder, BaseFunction } from './contract'; -import { Access, requireAccessControl } from './set-access-control'; +import type { Access } from './set-access-control'; +import { requireAccessControl } from './set-access-control'; import { defineFunctions } from './utils/define-functions'; export function addPausable(c: ContractBuilder, access: Access, pausableFns: BaseFunction[]) { diff --git a/packages/core/solidity/src/api.ts b/packages/core/solidity/src/api.ts index 5a9a86190..43ce36e6d 100644 --- a/packages/core/solidity/src/api.ts +++ b/packages/core/solidity/src/api.ts @@ -1,27 +1,57 @@ import type { CommonOptions } from './common-options'; -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 { printStablecoin, defaults as stablecoinDefaults, isAccessControlRequired as stablecoinIsAccessControlRequired, StablecoinOptions } from './stablecoin'; -import { printGovernor, defaults as governorDefaults, isAccessControlRequired as governorIsAccessControlRequired, GovernorOptions } from './governor'; -import { printCustom, defaults as customDefaults, isAccessControlRequired as customIsAccessControlRequired, CustomOptions } from './custom'; +import type { ERC20Options } from './erc20'; +import { + printERC20, + defaults as erc20defaults, + isAccessControlRequired as erc20IsAccessControlRequired, +} from './erc20'; +import type { ERC721Options } from './erc721'; +import { + printERC721, + defaults as erc721defaults, + isAccessControlRequired as erc721IsAccessControlRequired, +} from './erc721'; +import type { ERC1155Options } from './erc1155'; +import { + printERC1155, + defaults as erc1155defaults, + isAccessControlRequired as erc1155IsAccessControlRequired, +} from './erc1155'; +import type { StablecoinOptions } from './stablecoin'; +import { + printStablecoin, + defaults as stablecoinDefaults, + isAccessControlRequired as stablecoinIsAccessControlRequired, +} from './stablecoin'; +import type { GovernorOptions } from './governor'; +import { + printGovernor, + defaults as governorDefaults, + isAccessControlRequired as governorIsAccessControlRequired, +} from './governor'; +import type { CustomOptions } from './custom'; +import { + printCustom, + defaults as customDefaults, + isAccessControlRequired as customIsAccessControlRequired, +} from './custom'; export interface WizardContractAPI { /** * Returns a string representation of a contract generated using the provided options. If opts is not provided, uses `defaults`. */ - print: (opts?: Options) => string, - + print: (opts?: Options) => string; + /** * The default options that are used for `print`. */ defaults: Required; /** - * Whether any of the provided options require access control to be enabled. If this returns `true`, then calling `print` with the - * same options would cause the `access` option to default to `'ownable'` if it was `undefined` or `false`. + * Whether any of the provided options require access control to be enabled. If this returns `true`, then calling `print` with the + * same options would cause the `access` option to default to `'ownable'` if it was `undefined` or `false`. */ - isAccessControlRequired: (opts: Partial) => boolean, + isAccessControlRequired: (opts: Partial) => boolean; } export type ERC20 = WizardContractAPI; @@ -35,35 +65,35 @@ export type Custom = WizardContractAPI; export const erc20: ERC20 = { print: printERC20, defaults: erc20defaults, - isAccessControlRequired: erc20IsAccessControlRequired -} + isAccessControlRequired: erc20IsAccessControlRequired, +}; export const erc721: ERC721 = { print: printERC721, defaults: erc721defaults, - isAccessControlRequired: erc721IsAccessControlRequired -} + isAccessControlRequired: erc721IsAccessControlRequired, +}; export const erc1155: ERC1155 = { print: printERC1155, defaults: erc1155defaults, - isAccessControlRequired: erc1155IsAccessControlRequired -} + isAccessControlRequired: erc1155IsAccessControlRequired, +}; export const stablecoin: Stablecoin = { print: printStablecoin, defaults: stablecoinDefaults, - isAccessControlRequired: stablecoinIsAccessControlRequired -} + isAccessControlRequired: stablecoinIsAccessControlRequired, +}; export const realWorldAsset: RealWorldAsset = { print: printStablecoin, defaults: stablecoinDefaults, - isAccessControlRequired: stablecoinIsAccessControlRequired -} + isAccessControlRequired: stablecoinIsAccessControlRequired, +}; export const governor: Governor = { print: printGovernor, defaults: governorDefaults, - isAccessControlRequired: governorIsAccessControlRequired -} + isAccessControlRequired: governorIsAccessControlRequired, +}; export const custom: Custom = { print: printCustom, defaults: customDefaults, - isAccessControlRequired: customIsAccessControlRequired -} \ No newline at end of file + isAccessControlRequired: customIsAccessControlRequired, +}; diff --git a/packages/core/solidity/src/build-generic.ts b/packages/core/solidity/src/build-generic.ts index e0b9084da..fe64543fa 100644 --- a/packages/core/solidity/src/build-generic.ts +++ b/packages/core/solidity/src/build-generic.ts @@ -1,19 +1,25 @@ -import { CustomOptions, buildCustom } from './custom'; -import { ERC20Options, buildERC20 } from './erc20'; -import { ERC721Options, buildERC721 } from './erc721'; -import { ERC1155Options, buildERC1155 } from './erc1155'; -import { StablecoinOptions, buildStablecoin } from './stablecoin'; -import { GovernorOptions, buildGovernor } from './governor'; -import { Contract } from './contract'; +import type { CustomOptions } from './custom'; +import { buildCustom } from './custom'; +import type { ERC20Options } from './erc20'; +import { buildERC20 } from './erc20'; +import type { ERC721Options } from './erc721'; +import { buildERC721 } from './erc721'; +import type { ERC1155Options } from './erc1155'; +import { buildERC1155 } from './erc1155'; +import type { StablecoinOptions } from './stablecoin'; +import { buildStablecoin } from './stablecoin'; +import type { GovernorOptions } from './governor'; +import { buildGovernor } from './governor'; +import type { Contract } from './contract'; export interface KindedOptions { - ERC20: { kind: 'ERC20' } & ERC20Options; - ERC721: { kind: 'ERC721' } & ERC721Options; - ERC1155: { kind: 'ERC1155' } & ERC1155Options; - Stablecoin: { kind: 'Stablecoin' } & StablecoinOptions; - RealWorldAsset: { kind: 'RealWorldAsset' } & StablecoinOptions; + ERC20: { kind: 'ERC20' } & ERC20Options; + ERC721: { kind: 'ERC721' } & ERC721Options; + ERC1155: { kind: 'ERC1155' } & ERC1155Options; + Stablecoin: { kind: 'Stablecoin' } & StablecoinOptions; + RealWorldAsset: { kind: 'RealWorldAsset' } & StablecoinOptions; Governor: { kind: 'Governor' } & GovernorOptions; - Custom: { kind: 'Custom' } & CustomOptions; + Custom: { kind: 'Custom' } & CustomOptions; } export type GenericOptions = KindedOptions[keyof KindedOptions]; @@ -41,8 +47,9 @@ export function buildGeneric(opts: GenericOptions): Contract { case 'Custom': return buildCustom(opts); - default: + default: { const _: never = opts; throw new Error('Unknown ERC'); + } } } diff --git a/packages/core/solidity/src/common-functions.ts b/packages/core/solidity/src/common-functions.ts index 7d76c5f02..cf311c898 100644 --- a/packages/core/solidity/src/common-functions.ts +++ b/packages/core/solidity/src/common-functions.ts @@ -3,9 +3,7 @@ import type { BaseFunction } from './contract'; export const supportsInterface: BaseFunction = { name: 'supportsInterface', kind: 'public', - args: [ - { name: 'interfaceId', type: 'bytes4' }, - ], + args: [{ name: 'interfaceId', type: 'bytes4' }], returns: ['bool'], mutability: 'view', }; diff --git a/packages/core/solidity/src/common-options.ts b/packages/core/solidity/src/common-options.ts index eb0cec1ba..b001ae5f6 100644 --- a/packages/core/solidity/src/common-options.ts +++ b/packages/core/solidity/src/common-options.ts @@ -1,7 +1,7 @@ -import type { Access } from "./set-access-control"; -import type { Info } from "./set-info"; -import { defaults as infoDefaults } from "./set-info"; -import type { Upgradeable } from "./set-upgradeable"; +import type { Access } from './set-access-control'; +import type { Info } from './set-info'; +import { defaults as infoDefaults } from './set-info'; +import type { Upgradeable } from './set-upgradeable'; export const defaults: Required = { access: false, diff --git a/packages/core/solidity/src/contract.test.ts b/packages/core/solidity/src/contract.test.ts index b391a2445..0a1824cee 100644 --- a/packages/core/solidity/src/contract.test.ts +++ b/packages/core/solidity/src/contract.test.ts @@ -7,15 +7,15 @@ import { TAG_SECURITY_CONTACT } from './set-info'; const toContractReference = (name: string) => { return { name: name, - } -} + }; +}; const toParentContract = (name: string, path: string) => { return { name: name, path: path, - } -} + }; +}; test('contract basics', t => { const Foo = new ContractBuilder('Foo'); @@ -41,7 +41,7 @@ test('contract with two parents', t => { test('contract with a parent with parameters', t => { const Foo = new ContractBuilder('Foo'); const Bar = toParentContract('Bar', './Bar.sol'); - Foo.addParent(Bar, ["param1", "param2"]); + Foo.addParent(Bar, ['param1', 'param2']); t.snapshot(printContract(Foo)); }); @@ -49,7 +49,7 @@ test('contract with two parents only one with parameters', t => { const Foo = new ContractBuilder('Foo'); const Bar = toParentContract('Bar', './Bar.sol'); const Quux = toParentContract('Quux', './Quux.sol'); - Foo.addParent(Bar, ["param1", "param2"]); + Foo.addParent(Bar, ['param1', 'param2']); Foo.addParent(Quux); t.snapshot(printContract(Foo)); }); @@ -110,7 +110,7 @@ test('contract with constructor code', t => { test('contract with constructor code and a parent', t => { const Foo = new ContractBuilder('Foo'); const Bar = toParentContract('Bar', './Bar.sol'); - Foo.addParent(Bar, ["param1", "param2"]); + Foo.addParent(Bar, ['param1', 'param2']); Foo.addConstructorCode('_mint(msg.sender, 10 ether);'); t.snapshot(printContract(Foo)); }); @@ -152,7 +152,6 @@ test('contract with info', t => { t.snapshot(printContract(Foo)); }); - const _beforeTokenTransfer = { name: '_beforeTokenTransfer', kind: 'internal' as const, diff --git a/packages/core/solidity/src/contract.ts b/packages/core/solidity/src/contract.ts index e7142d54f..6ed276124 100644 --- a/packages/core/solidity/src/contract.ts +++ b/packages/core/solidity/src/contract.ts @@ -13,7 +13,7 @@ export interface Contract { upgradeable: boolean; } -export type Value = string | number | { lit: string } | { note: string, value: Value }; +export type Value = string | number | { lit: string } | { note: string; value: Value }; export interface Parent { contract: ImportContract; @@ -53,15 +53,13 @@ export interface ContractFunction extends BaseFunction { } export type FunctionKind = 'internal' | 'public'; -export type FunctionMutability = typeof mutabilityRank[number]; +export type FunctionMutability = (typeof mutabilityRank)[number]; // Order is important const mutabilityRank = ['pure', 'view', 'nonpayable', 'payable'] as const; function maxMutability(a: FunctionMutability, b: FunctionMutability): FunctionMutability { - return mutabilityRank[ - Math.max(mutabilityRank.indexOf(a), mutabilityRank.indexOf(b)) - ]!; + return mutabilityRank[Math.max(mutabilityRank.indexOf(a), mutabilityRank.indexOf(b))]!; } export interface FunctionArgument { @@ -94,22 +92,21 @@ export class ContractBuilder implements Contract { } get parents(): Parent[] { - return [...this.parentMap.values()].filter(p => !p.importOnly).sort((a, b) => { - if (a.contract.name === 'Initializable') { - return -1; - } else if (b.contract.name === 'Initializable') { - return 1; - } else { - return 0; - } - }); + return [...this.parentMap.values()] + .filter(p => !p.importOnly) + .sort((a, b) => { + if (a.contract.name === 'Initializable') { + return -1; + } else if (b.contract.name === 'Initializable') { + return 1; + } else { + return 0; + } + }); } get imports(): ImportContract[] { - return [ - ...[...this.parentMap.values()].map(p => p.contract), - ...this.using.map(u => u.library), - ]; + return [...[...this.parentMap.values()].map(p => p.contract), ...this.using.map(u => u.library)]; } get functions(): ContractFunction[] { @@ -128,7 +125,11 @@ export class ContractBuilder implements Contract { addImportOnly(contract: ImportContract): boolean { const present = this.parentMap.has(contract.name); - this.parentMap.set(contract.name, { contract, params: [], importOnly: true }); + this.parentMap.set(contract.name, { + contract, + params: [], + importOnly: true, + }); return !present; } @@ -146,6 +147,7 @@ export class ContractBuilder implements Contract { } addNatspecTag(key: string, value: string) { + // eslint-disable-next-line no-useless-escape if (!/^(@custom:)?[a-z][a-z\-]*$/.exec(key)) throw new Error(`Invalid natspec key: ${key}`); this.natspecTags.push({ key, value }); } diff --git a/packages/core/solidity/src/custom.test.ts b/packages/core/solidity/src/custom.test.ts index 2cfb60ce4..751b40277 100644 --- a/packages/core/solidity/src/custom.test.ts +++ b/packages/core/solidity/src/custom.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { custom } from '.'; -import { buildCustom, CustomOptions } from './custom'; +import type { CustomOptions } from './custom'; +import { buildCustom } from './custom'; import { printContract } from './print'; function testCustom(title: string, opts: Partial) { @@ -17,12 +18,17 @@ function testCustom(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: CustomOptions) { +function testAPIEquivalence(title: string, opts?: CustomOptions) { test(title, t => { - t.is(custom.print(opts), printContract(buildCustom({ - name: 'MyContract', - ...opts, - }))); + t.is( + custom.print(opts), + printContract( + buildCustom({ + name: 'MyContract', + ...opts, + }), + ), + ); }); } @@ -88,4 +94,4 @@ test('API isAccessControlRequired', async t => { t.is(custom.isAccessControlRequired({ pausable: true }), true); t.is(custom.isAccessControlRequired({ upgradeable: 'uups' }), true); t.is(custom.isAccessControlRequired({ upgradeable: 'transparent' }), false); -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/custom.ts b/packages/core/solidity/src/custom.ts index b82ca2c67..5baaf31b5 100644 --- a/packages/core/solidity/src/custom.ts +++ b/packages/core/solidity/src/custom.ts @@ -1,5 +1,7 @@ -import { Contract, ContractBuilder } from './contract'; -import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from './common-options'; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; +import type { CommonOptions } from './common-options'; +import { withCommonDefaults, defaults as commonDefaults } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { setAccessControl } from './set-access-control'; @@ -52,4 +54,3 @@ export function buildCustom(opts: CustomOptions): Contract { return c; } - diff --git a/packages/core/solidity/src/erc1155.test.ts b/packages/core/solidity/src/erc1155.test.ts index d34232159..bea4ae13e 100644 --- a/packages/core/solidity/src/erc1155.test.ts +++ b/packages/core/solidity/src/erc1155.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { erc1155 } from '.'; -import { buildERC1155, ERC1155Options } from './erc1155'; +import type { ERC1155Options } from './erc1155'; +import { buildERC1155 } from './erc1155'; import { printContract } from './print'; function testERC1155(title: string, opts: Partial) { @@ -18,13 +19,18 @@ function testERC1155(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: ERC1155Options) { +function testAPIEquivalence(title: string, opts?: ERC1155Options) { test(title, t => { - t.is(erc1155.print(opts), printContract(buildERC1155({ - name: 'MyToken', - uri: '', - ...opts, - }))); + t.is( + erc1155.print(opts), + printContract( + buildERC1155({ + name: 'MyToken', + uri: '', + ...opts, + }), + ), + ); }); } @@ -94,7 +100,10 @@ testERC1155('full upgradeable transparent with managed', { testAPIEquivalence('API default'); -testAPIEquivalence('API basic', { name: 'CustomToken', uri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/' }); +testAPIEquivalence('API basic', { + name: 'CustomToken', + uri: 'https://gateway.pinata.cloud/ipfs/QmcP9hxrnC1T5ATPmq2saFeAM1ypFX9BnAswCdHB9JCjLA/', +}); testAPIEquivalence('API full upgradeable', { name: 'CustomToken', @@ -113,8 +122,14 @@ test('API assert defaults', async t => { 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: 'uups' }), true); + t.is( + erc1155.isAccessControlRequired({ + updatableUri: false, + upgradeable: 'uups', + }), + true, + ); t.is(erc1155.isAccessControlRequired({ updatableUri: true }), true); - t.is(erc1155.isAccessControlRequired({ updatableUri: false}), false); + 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/solidity/src/erc1155.ts b/packages/core/solidity/src/erc1155.ts index 8631e4220..9bb93ded1 100644 --- a/packages/core/solidity/src/erc1155.ts +++ b/packages/core/solidity/src/erc1155.ts @@ -1,9 +1,12 @@ -import { Contract, ContractBuilder } from './contract'; -import { Access, setAccessControl, requireAccessControl } from './set-access-control'; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; +import type { Access } from './set-access-control'; +import { setAccessControl, requireAccessControl } from './set-access-control'; import { addPauseFunctions } from './add-pausable'; import { supportsInterface } from './common-functions'; import { defineFunctions } from './utils/define-functions'; -import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from './common-options'; +import type { CommonOptions } from './common-options'; +import { withCommonDefaults, defaults as commonDefaults } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { printContract } from './print'; @@ -28,7 +31,7 @@ export const defaults: Required = { updatableUri: true, access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info + info: commonDefaults.info, } as const; function withDefaults(opts: ERC1155Options): Required { @@ -150,9 +153,7 @@ const functions = defineFunctions({ setURI: { kind: 'public' as const, - args: [ - { name: 'newuri', type: 'string memory' }, - ], + args: [{ name: 'newuri', type: 'string memory' }], }, mint: { diff --git a/packages/core/solidity/src/erc20.test.ts b/packages/core/solidity/src/erc20.test.ts index 7cd107d26..84409b78d 100644 --- a/packages/core/solidity/src/erc20.test.ts +++ b/packages/core/solidity/src/erc20.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { erc20 } from '.'; -import { buildERC20, ERC20Options } from './erc20'; +import type { ERC20Options } from './erc20'; +import { buildERC20 } from './erc20'; import { printContract } from './print'; function testERC20(title: string, opts: Partial) { @@ -18,13 +19,18 @@ function testERC20(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: ERC20Options) { +function testAPIEquivalence(title: string, opts?: ERC20Options) { test(title, t => { - t.is(erc20.print(opts), printContract(buildERC20({ - name: 'MyToken', - symbol: 'MTK', - ...opts, - }))); + t.is( + erc20.print(opts), + printContract( + buildERC20({ + name: 'MyToken', + symbol: 'MTK', + ...opts, + }), + ), + ); }); } @@ -155,4 +161,4 @@ test('erc20 API isAccessControlRequired', async t => { t.is(erc20.isAccessControlRequired({ pausable: true }), true); t.is(erc20.isAccessControlRequired({ upgradeable: 'uups' }), true); t.is(erc20.isAccessControlRequired({ upgradeable: 'transparent' }), false); -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/erc20.ts b/packages/core/solidity/src/erc20.ts index 09847179b..3b0f3419b 100644 --- a/packages/core/solidity/src/erc20.ts +++ b/packages/core/solidity/src/erc20.ts @@ -1,12 +1,15 @@ -import { Contract, ContractBuilder } from './contract'; -import { Access, setAccessControl, requireAccessControl } from './set-access-control'; +import { ContractBuilder } from './contract'; +import type { Access } from './set-access-control'; +import { setAccessControl, requireAccessControl } from './set-access-control'; import { addPauseFunctions } from './add-pausable'; import { defineFunctions } from './utils/define-functions'; -import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from './common-options'; +import type { CommonOptions } from './common-options'; +import { withCommonDefaults, defaults as commonDefaults } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { printContract } from './print'; -import { ClockMode, clockModeDefault, setClockMode } from './set-clock-mode'; +import type { ClockMode } from './set-clock-mode'; +import { clockModeDefault, setClockMode } from './set-clock-mode'; export interface ERC20Options extends CommonOptions { name: string; @@ -112,10 +115,7 @@ function addBase(c: ContractBuilder, name: string, symbol: string) { name: 'ERC20', path: '@openzeppelin/contracts/token/ERC20/ERC20.sol', }; - c.addParent( - ERC20, - [name, symbol], - ); + c.addParent(ERC20, [name, symbol]); c.addOverride(ERC20, functions._update); c.addOverride(ERC20, functions._approve); // allows override from stablecoin @@ -153,7 +153,7 @@ function addPremint(c: ContractBuilder, amount: string) { const zeroes = new Array(Math.max(0, -decimalPlace)).fill('0').join(''); const units = integer + decimals + zeroes; const exp = decimalPlace <= 0 ? 'decimals()' : `(decimals() - ${decimalPlace})`; - c.addConstructorArgument({type: 'address', name: 'recipient'}); + c.addConstructorArgument({ type: 'address', name: 'recipient' }); c.addConstructorCode(`_mint(recipient, ${units} * 10 ** ${exp});`); } } @@ -171,7 +171,6 @@ function addPermit(c: ContractBuilder, name: string) { }; c.addParent(ERC20Permit, [name]); c.addOverride(ERC20Permit, functions.nonces); - } function addVotes(c: ContractBuilder, clockMode: ClockMode) { @@ -190,9 +189,12 @@ function addVotes(c: ContractBuilder, clockMode: ClockMode) { name: 'Nonces', path: '@openzeppelin/contracts/utils/Nonces.sol', }); - c.addOverride({ - name: 'Nonces', - }, functions.nonces); + c.addOverride( + { + name: 'Nonces', + }, + functions.nonces, + ); setClockMode(c, ERC20Votes, clockMode); } @@ -249,10 +251,8 @@ export const functions = defineFunctions({ nonces: { kind: 'public' as const, - args: [ - { name: 'owner', type: 'address' }, - ], + args: [{ name: 'owner', type: 'address' }], returns: ['uint256'], mutability: 'view' as const, - } + }, }); diff --git a/packages/core/solidity/src/erc721.test.ts b/packages/core/solidity/src/erc721.test.ts index 4b39a2472..1b26718e0 100644 --- a/packages/core/solidity/src/erc721.test.ts +++ b/packages/core/solidity/src/erc721.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { erc721 } from '.'; -import { buildERC721, ERC721Options } from './erc721'; +import type { ERC721Options } from './erc721'; +import { buildERC721 } from './erc721'; import { printContract } from './print'; function testERC721(title: string, opts: Partial) { @@ -18,13 +19,18 @@ function testERC721(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: ERC721Options) { +function testAPIEquivalence(title: string, opts?: ERC721Options) { test(title, t => { - t.is(erc721.print(opts), printContract(buildERC721({ - name: 'MyToken', - symbol: 'MTK', - ...opts, - }))); + t.is( + erc721.print(opts), + printContract( + buildERC721({ + name: 'MyToken', + symbol: 'MTK', + ...opts, + }), + ), + ); }); } @@ -149,4 +155,4 @@ test('API isAccessControlRequired', async t => { t.is(erc721.isAccessControlRequired({ pausable: true }), true); t.is(erc721.isAccessControlRequired({ upgradeable: 'uups' }), true); t.is(erc721.isAccessControlRequired({ upgradeable: 'transparent' }), false); -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/erc721.ts b/packages/core/solidity/src/erc721.ts index ab75267e0..2b945123f 100644 --- a/packages/core/solidity/src/erc721.ts +++ b/packages/core/solidity/src/erc721.ts @@ -1,13 +1,17 @@ -import { BaseFunction, Contract, ContractBuilder } from './contract'; -import { Access, setAccessControl, requireAccessControl } from './set-access-control'; +import type { BaseFunction, Contract } from './contract'; +import { ContractBuilder } from './contract'; +import type { Access } from './set-access-control'; +import { setAccessControl, requireAccessControl } from './set-access-control'; import { addPauseFunctions } from './add-pausable'; import { supportsInterface } from './common-functions'; import { defineFunctions } from './utils/define-functions'; -import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from './common-options'; +import type { CommonOptions } from './common-options'; +import { withCommonDefaults, defaults as commonDefaults } from './common-options'; import { setUpgradeable } from './set-upgradeable'; import { setInfo } from './set-info'; import { printContract } from './print'; -import { ClockMode, clockModeDefault, setClockMode } from './set-clock-mode'; +import type { ClockMode } from './set-clock-mode'; +import { clockModeDefault, setClockMode } from './set-clock-mode'; export interface ERC721Options extends CommonOptions { name: string; diff --git a/packages/core/solidity/src/error.ts b/packages/core/solidity/src/error.ts index 2235dfd68..96eb23489 100644 --- a/packages/core/solidity/src/error.ts +++ b/packages/core/solidity/src/error.ts @@ -2,6 +2,6 @@ export type OptionsErrorMessages = { [prop in string]?: string }; export class OptionsError extends Error { constructor(readonly messages: OptionsErrorMessages) { - super("Invalid options for Governor"); + super('Invalid options for Governor'); } } diff --git a/packages/core/solidity/src/generate/alternatives.ts b/packages/core/solidity/src/generate/alternatives.ts index e26603539..b66e733cf 100644 --- a/packages/core/solidity/src/generate/alternatives.ts +++ b/packages/core/solidity/src/generate/alternatives.ts @@ -1,14 +1,10 @@ -import { mapValues } from "../utils/map-values"; - type Blueprint = Record; type Alternatives = { [k in keyof B]: B[k][number]; }; -export function* generateAlternatives( - blueprint: B, -): Generator> { +export function* generateAlternatives(blueprint: B): Generator> { const entries = Object.entries(blueprint).map(([key, values]) => ({ key, values, @@ -17,9 +13,7 @@ export function* generateAlternatives( })); for (; !done(); advance()) { - yield Object.fromEntries( - entries.map(e => [e.key, e.values[e.current % e.limit]]), - ) as Alternatives; + yield Object.fromEntries(entries.map(e => [e.key, e.values[e.current % e.limit]])) as Alternatives; } function done() { diff --git a/packages/core/solidity/src/generate/erc20.ts b/packages/core/solidity/src/generate/erc20.ts index 929da1af5..3db65e95f 100644 --- a/packages/core/solidity/src/generate/erc20.ts +++ b/packages/core/solidity/src/generate/erc20.ts @@ -14,7 +14,7 @@ const blueprint = { pausable: booleans, mintable: booleans, permit: booleans, - votes: [ ...booleans, ...clockModeOptions ] as const, + votes: [...booleans, ...clockModeOptions] as const, flashmint: booleans, premint: ['1'], access: accessOptions, diff --git a/packages/core/solidity/src/generate/erc721.ts b/packages/core/solidity/src/generate/erc721.ts index 4bf97e744..1f91b7c30 100644 --- a/packages/core/solidity/src/generate/erc721.ts +++ b/packages/core/solidity/src/generate/erc721.ts @@ -20,7 +20,7 @@ const blueprint = { access: accessOptions, upgradeable: upgradeableOptions, info: infoOptions, - votes: [ ...booleans, ...clockModeOptions ] as const, + votes: [...booleans, ...clockModeOptions] as const, }; export function* generateERC721Options(): Generator> { diff --git a/packages/core/solidity/src/generate/governor.ts b/packages/core/solidity/src/generate/governor.ts index a5a93f26a..765f4e69f 100644 --- a/packages/core/solidity/src/generate/governor.ts +++ b/packages/core/solidity/src/generate/governor.ts @@ -1,4 +1,5 @@ -import { defaults, GovernorOptions, timelockOptions, votesOptions } from '../governor'; +import type { GovernorOptions } from '../governor'; +import { defaults, timelockOptions, votesOptions } from '../governor'; import { accessOptions } from '../set-access-control'; import { clockModeOptions } from '../set-clock-mode'; import { infoOptions } from '../set-info'; diff --git a/packages/core/solidity/src/generate/sources.ts b/packages/core/solidity/src/generate/sources.ts index a6745f6eb..b25f6c444 100644 --- a/packages/core/solidity/src/generate/sources.ts +++ b/packages/core/solidity/src/generate/sources.ts @@ -8,7 +8,8 @@ import { generateERC1155Options } from './erc1155'; import { generateStablecoinOptions } from './stablecoin'; import { generateGovernorOptions } from './governor'; import { generateCustomOptions } from './custom'; -import { buildGeneric, GenericOptions, KindedOptions } from '../build-generic'; +import type { GenericOptions, KindedOptions } from '../build-generic'; +import { buildGeneric } from '../build-generic'; import { printContract } from '../print'; import { OptionsError } from '../error'; import { findCover } from '../utils/find-cover'; @@ -76,11 +77,7 @@ function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[ const contracts = []; for (const options of generateOptions(kind)) { - const id = crypto - .createHash('sha1') - .update(JSON.stringify(options)) - .digest() - .toString('hex'); + const id = crypto.createHash('sha1').update(JSON.stringify(options)).digest().toString('hex'); try { const contract = buildGeneric(options); @@ -99,8 +96,14 @@ function generateContractSubset(subset: Subset, kind?: Kind): GeneratedContract[ } else { const getParents = (c: GeneratedContract) => c.contract.parents.map(p => p.contract.path); return [ - ...findCover(contracts.filter(c => c.options.upgradeable), getParents), - ...findCover(contracts.filter(c => !c.options.upgradeable), getParents), + ...findCover( + contracts.filter(c => c.options.upgradeable), + getParents, + ), + ...findCover( + contracts.filter(c => !c.options.upgradeable), + getParents, + ), ]; } } diff --git a/packages/core/solidity/src/generate/stablecoin.ts b/packages/core/solidity/src/generate/stablecoin.ts index 358052aa9..8cbcd1adc 100644 --- a/packages/core/solidity/src/generate/stablecoin.ts +++ b/packages/core/solidity/src/generate/stablecoin.ts @@ -15,7 +15,7 @@ const blueprint = { mintable: booleans, permit: booleans, limitations: [false, 'allowlist', 'blocklist'] as const, - votes: [ ...booleans, ...clockModeOptions ] as const, + votes: [...booleans, ...clockModeOptions] as const, flashmint: booleans, premint: ['1'], custodian: booleans, diff --git a/packages/core/solidity/src/get-imports.test.ts b/packages/core/solidity/src/get-imports.test.ts index 5678fdc57..d6f1509bb 100644 --- a/packages/core/solidity/src/get-imports.test.ts +++ b/packages/core/solidity/src/get-imports.test.ts @@ -21,7 +21,12 @@ test('erc20 basic', t => { }); test('erc721 auto increment', t => { - const c = buildERC721({ name: 'MyToken', symbol: 'MTK', mintable: true, incremental: true }); + const c = buildERC721({ + name: 'MyToken', + symbol: 'MTK', + mintable: true, + incremental: true, + }); const sources = getImports(c); const files = Object.keys(sources).sort(); @@ -45,7 +50,13 @@ test('erc721 auto increment', t => { }); test('erc721 auto increment uups', t => { - const c = buildERC721({ name: 'MyToken', symbol: 'MTK', mintable: true, incremental: true, upgradeable: 'uups' }); + const c = buildERC721({ + name: 'MyToken', + symbol: 'MTK', + mintable: true, + incremental: true, + upgradeable: 'uups', + }); const sources = getImports(c); const files = Object.keys(sources).sort(); @@ -83,4 +94,4 @@ test('can get imports for all combinations', t => { getImports(c); } t.pass(); -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/get-imports.ts b/packages/core/solidity/src/get-imports.ts index 9c51ab86b..c7e390907 100644 --- a/packages/core/solidity/src/get-imports.ts +++ b/packages/core/solidity/src/get-imports.ts @@ -11,10 +11,10 @@ export interface SolcInputSources { } /** -* Gets the source code for all imports of a contract, including all transitive dependencies, -* in a format compatible with the Solidity compiler input's `sources` field. -* -* Does not include the contract itself (use `printContract` for that if needed). + * Gets the source code for all imports of a contract, including all transitive dependencies, + * in a format compatible with the Solidity compiler input's `sources` field. + * + * Does not include the contract itself (use `printContract` for that if needed). * * @param c The contract to get imports for. * @returns A record of import paths to `content` that contains the source code for each contract. @@ -42,4 +42,4 @@ export function getImports(c: Contract): SolcInputSources { } return result; -} \ No newline at end of file +} diff --git a/packages/core/solidity/src/governor.test.ts b/packages/core/solidity/src/governor.test.ts index ee34b0a4b..8b84b468c 100644 --- a/packages/core/solidity/src/governor.test.ts +++ b/packages/core/solidity/src/governor.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { governor } from '.'; -import { buildGovernor, GovernorOptions } from './governor'; +import type { GovernorOptions } from './governor'; +import { buildGovernor } from './governor'; import { printContract } from './print'; function testGovernor(title: string, opts: Partial) { @@ -20,14 +21,19 @@ function testGovernor(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: GovernorOptions) { +function testAPIEquivalence(title: string, opts?: GovernorOptions) { test(title, t => { - t.is(governor.print(opts), printContract(buildGovernor({ - name: 'MyGovernor', - delay: '1 day', - period: '1 week', - ...opts, - }))); + t.is( + governor.print(opts), + printContract( + buildGovernor({ + name: 'MyGovernor', + delay: '1 day', + period: '1 week', + ...opts, + }), + ), + ); }); } @@ -138,9 +144,18 @@ testGovernor('governor with erc20votes, upgradable', { testAPIEquivalence('API default'); -testAPIEquivalence('API basic', { name: 'CustomGovernor', delay: '2 weeks', period: '2 week' }); +testAPIEquivalence('API basic', { + name: 'CustomGovernor', + delay: '2 weeks', + period: '2 week', +}); -testAPIEquivalence('API basic upgradeable', { name: 'CustomGovernor', delay: '2 weeks', period: '2 week', upgradeable: 'uups' }); +testAPIEquivalence('API basic upgradeable', { + name: 'CustomGovernor', + delay: '2 weeks', + period: '2 week', + upgradeable: 'uups', +}); test('API assert defaults', async t => { t.is(governor.print(governor.defaults), governor.print()); @@ -149,4 +164,4 @@ test('API assert defaults', async t => { test('API isAccessControlRequired', async t => { t.is(governor.isAccessControlRequired({ upgradeable: 'uups' }), true); t.is(governor.isAccessControlRequired({}), false); -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/governor.ts b/packages/core/solidity/src/governor.ts index 4591cdfdb..2ffaa90e1 100644 --- a/packages/core/solidity/src/governor.ts +++ b/packages/core/solidity/src/governor.ts @@ -1,14 +1,16 @@ -import { supportsInterface } from "./common-functions"; -import { CommonOptions, withCommonDefaults, defaults as commonDefaults } from "./common-options"; -import { ContractBuilder, Contract, Value } from "./contract"; -import { OptionsError } from "./error"; -import { setAccessControl } from "./set-access-control"; -import { printContract } from "./print"; -import { setInfo } from "./set-info"; -import { setUpgradeable } from "./set-upgradeable"; +import { supportsInterface } from './common-functions'; +import type { CommonOptions } from './common-options'; +import { withCommonDefaults, defaults as commonDefaults } from './common-options'; +import type { Contract } from './contract'; +import { ContractBuilder } from './contract'; +import { OptionsError } from './error'; +import { setAccessControl } from './set-access-control'; +import { printContract } from './print'; +import { setInfo } from './set-info'; +import { setUpgradeable } from './set-upgradeable'; import { defineFunctions } from './utils/define-functions'; -import { durationToBlocks, durationToTimestamp } from "./utils/duration"; -import { clockModeDefault, type ClockMode } from "./set-clock-mode"; +import { durationToBlocks, durationToTimestamp } from './utils/duration'; +import { clockModeDefault, type ClockMode } from './set-clock-mode'; export const defaults: Required = { name: 'MyGovernor', @@ -26,17 +28,17 @@ export const defaults: Required = { quorumAbsolute: '', storage: false, settings: true, - + access: commonDefaults.access, upgradeable: commonDefaults.upgradeable, - info: commonDefaults.info + info: commonDefaults.info, } as const; export const votesOptions = ['erc20votes', 'erc721votes'] as const; -export type VotesOptions = typeof votesOptions[number]; +export type VotesOptions = (typeof votesOptions)[number]; export const timelockOptions = [false, 'openzeppelin', 'compound'] as const; -export type TimelockOptions = typeof timelockOptions[number]; +export type TimelockOptions = (typeof timelockOptions)[number]; export function printGovernor(opts: GovernorOptions = defaults): string { return printContract(buildGovernor(opts)); @@ -77,7 +79,7 @@ function withDefaults(opts: GovernorOptions): Required { quorumMode: opts.quorumMode ?? defaults.quorumMode, votes: opts.votes ?? defaults.votes, clockMode: opts.clockMode ?? defaults.clockMode, - timelock: opts.timelock ?? defaults.timelock + timelock: opts.timelock ?? defaults.timelock, }; } @@ -130,14 +132,11 @@ function addSettings(c: ContractBuilder, allOpts: Required) { name: 'GovernorSettings', path: '@openzeppelin/contracts/governance/extensions/GovernorSettings.sol', }; - c.addParent( - GovernorSettings, - [ - getVotingDelay(allOpts), - getVotingPeriod(allOpts), - { lit: getProposalThreshold(allOpts) }, - ], - ); + c.addParent(GovernorSettings, [ + getVotingDelay(allOpts), + getVotingPeriod(allOpts), + { lit: getProposalThreshold(allOpts) }, + ]); c.addOverride(GovernorSettings, functions.votingDelay, 'view'); c.addOverride(GovernorSettings, functions.votingPeriod, 'view'); c.addOverride(GovernorSettings, functions.proposalThreshold, 'view'); @@ -147,7 +146,7 @@ function addSettings(c: ContractBuilder, allOpts: Required) { } } -function getVotingDelay(opts: Required): { lit: string } | { note: string, value: number } { +function getVotingDelay(opts: Required): { lit: string } | { note: string; value: number } { try { if (opts.clockMode === 'timestamp') { return { @@ -156,7 +155,7 @@ function getVotingDelay(opts: Required): { lit: string } | { no } else { return { value: durationToBlocks(opts.delay, opts.blockTime), - note: opts.delay + note: opts.delay, }; } } catch (e) { @@ -170,7 +169,7 @@ function getVotingDelay(opts: Required): { lit: string } | { no } } -function getVotingPeriod(opts: Required): { lit: string } | { note: string, value: number } { +function getVotingPeriod(opts: Required): { lit: string } | { note: string; value: number } { try { if (opts.clockMode === 'timestamp') { return { @@ -179,7 +178,7 @@ function getVotingPeriod(opts: Required): { lit: string } | { n } else { return { value: durationToBlocks(opts.period, opts.blockTime), - note: opts.period + note: opts.period, }; } } catch (e) { @@ -263,10 +262,13 @@ function addVotes(c: ContractBuilder) { name: tokenArg, }); - c.addParent({ - name: 'GovernorVotes', - path: `@openzeppelin/contracts/governance/extensions/GovernorVotes.sol`, - }, [{ lit: tokenArg }]); + c.addParent( + { + name: 'GovernorVotes', + path: `@openzeppelin/contracts/governance/extensions/GovernorVotes.sol`, + }, + [{ lit: tokenArg }], + ); } export const numberPattern = /^(?!$)(\d*)(?:\.(\d+))?(?:e(\d+))?$/; @@ -279,7 +281,7 @@ function addQuorum(c: ContractBuilder, opts: Required) { }); } - let { quorumFractionNumerator, quorumFractionDenominator } = getQuorumFractionComponents(opts.quorumPercent); + const { quorumFractionNumerator, quorumFractionDenominator } = getQuorumFractionComponents(opts.quorumPercent); const GovernorVotesQuorumFraction = { name: 'GovernorVotesQuorumFraction', @@ -288,29 +290,24 @@ function addQuorum(c: ContractBuilder, opts: Required) { if (quorumFractionDenominator !== undefined) { c.addOverride(GovernorVotesQuorumFraction, functions.quorumDenominator); - c.setFunctionBody([ - `return ${quorumFractionDenominator};` - ], functions.quorumDenominator, 'pure'); + c.setFunctionBody([`return ${quorumFractionDenominator};`], functions.quorumDenominator, 'pure'); } c.addParent(GovernorVotesQuorumFraction, [quorumFractionNumerator]); c.addOverride(GovernorVotesQuorumFraction, functions.quorum); - } - - else if (opts.quorumMode === 'absolute') { + } else if (opts.quorumMode === 'absolute') { if (!numberPattern.test(opts.quorumAbsolute)) { throw new OptionsError({ quorumAbsolute: 'Not a valid number', }); } - let returnStatement = (opts.decimals === 0 || opts.votes === 'erc721votes') ? - `return ${opts.quorumAbsolute};` : - `return ${opts.quorumAbsolute}e${opts.decimals};`; + const returnStatement = + opts.decimals === 0 || opts.votes === 'erc721votes' + ? `return ${opts.quorumAbsolute};` + : `return ${opts.quorumAbsolute}e${opts.decimals};`; - c.setFunctionBody([ - returnStatement, - ], functions.quorum, 'pure'); + c.setFunctionBody([returnStatement], functions.quorum, 'pure'); } } @@ -323,7 +320,7 @@ const timelockModules = { timelockParent: { name: 'GovernorTimelockControl', path: `@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol`, - } + }, }, compound: { timelockType: { @@ -334,20 +331,27 @@ const timelockModules = { timelockParent: { name: 'GovernorTimelockCompound', path: `@openzeppelin/contracts/governance/extensions/GovernorTimelockCompound.sol`, - } + }, }, } as const; -function getQuorumFractionComponents(quorumPercent: number): {quorumFractionNumerator: number, quorumFractionDenominator: string | undefined} { +function getQuorumFractionComponents(quorumPercent: number): { + quorumFractionNumerator: number; + quorumFractionDenominator: string | undefined; +} { let quorumFractionNumerator = quorumPercent; let quorumFractionDenominator = undefined; - const quorumPercentSegments = quorumPercent.toString().split("."); + const quorumPercentSegments = quorumPercent.toString().split('.'); if (quorumPercentSegments.length > 2) { throw new OptionsError({ quorumPercent: 'Invalid percentage', }); - } else if (quorumPercentSegments.length == 2 && quorumPercentSegments[0] !== undefined && quorumPercentSegments[1] !== undefined) { + } else if ( + quorumPercentSegments.length == 2 && + quorumPercentSegments[0] !== undefined && + quorumPercentSegments[1] !== undefined + ) { quorumFractionNumerator = parseInt(quorumPercentSegments[0].concat(quorumPercentSegments[1])); const decimals = quorumPercentSegments[1].length; quorumFractionDenominator = '100'; @@ -412,17 +416,13 @@ const functions = defineFunctions({ mutability: 'pure', }, proposalNeedsQueuing: { - args: [ - { name: 'proposalId', type: 'uint256' }, - ], + args: [{ name: 'proposalId', type: 'uint256' }], returns: ['bool'], kind: 'public', mutability: 'view', }, quorum: { - args: [ - { name: 'blockNumber', type: 'uint256' }, - ], + args: [{ name: 'blockNumber', type: 'uint256' }], returns: ['uint256'], kind: 'public', mutability: 'view', @@ -486,9 +486,7 @@ const functions = defineFunctions({ kind: 'internal', }, state: { - args: [ - { name: 'proposalId', type: 'uint256' }, - ], + args: [{ name: 'proposalId', type: 'uint256' }], returns: ['ProposalState'], kind: 'public', mutability: 'view', diff --git a/packages/core/solidity/src/index.ts b/packages/core/solidity/src/index.ts index b6e0ed24c..4b4bba141 100644 --- a/packages/core/solidity/src/index.ts +++ b/packages/core/solidity/src/index.ts @@ -21,4 +21,4 @@ export { sanitizeKind } from './kind'; export { erc20, erc721, erc1155, stablecoin, realWorldAsset, governor, custom } from './api'; -export { compatibleContractsSemver } from './utils/version'; \ No newline at end of file +export { compatibleContractsSemver } from './utils/version'; diff --git a/packages/core/solidity/src/infer-transpiled.test.ts b/packages/core/solidity/src/infer-transpiled.test.ts index c6ead4149..cccffeeab 100644 --- a/packages/core/solidity/src/infer-transpiled.test.ts +++ b/packages/core/solidity/src/infer-transpiled.test.ts @@ -9,4 +9,4 @@ test('infer transpiled', t => { t.false(inferTranspiled({ name: 'IFoo' })); t.true(inferTranspiled({ name: 'IFoo', transpiled: true })); t.false(inferTranspiled({ name: 'IFoo', transpiled: false })); -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/infer-transpiled.ts b/packages/core/solidity/src/infer-transpiled.ts index 52eeba679..f338ea6a4 100644 --- a/packages/core/solidity/src/infer-transpiled.ts +++ b/packages/core/solidity/src/infer-transpiled.ts @@ -1,5 +1,5 @@ -import type { ReferencedContract } from "./contract"; +import type { ReferencedContract } from './contract'; export function inferTranspiled(c: ReferencedContract): boolean { return c.transpiled ?? !/^I[A-Z]/.test(c.name); -} \ No newline at end of file +} diff --git a/packages/core/solidity/src/kind.ts b/packages/core/solidity/src/kind.ts index de78812fc..26a775c4a 100644 --- a/packages/core/solidity/src/kind.ts +++ b/packages/core/solidity/src/kind.ts @@ -30,4 +30,3 @@ function isKind(value: Kind | T): value is Kind { } } } - diff --git a/packages/core/solidity/src/options.ts b/packages/core/solidity/src/options.ts index b86fe6c4f..6e800715f 100644 --- a/packages/core/solidity/src/options.ts +++ b/packages/core/solidity/src/options.ts @@ -9,7 +9,7 @@ const upgradeableName = (n: string) => { } else { return n.replace(/(Upgradeable)?(?=\.|$)/, 'Upgradeable'); } -} +}; const upgradeableImport = (p: ImportContract): ImportContract => { const { dir, ext, name } = path.parse(p.path); @@ -22,7 +22,7 @@ const upgradeableImport = (p: ImportContract): ImportContract => { dir: dir.replace(/^@openzeppelin\/contracts/, '@openzeppelin/contracts-upgradeable'), name: upgradeableName(name), // Solidity file name }), - } + }; }; export interface Options { @@ -36,7 +36,8 @@ export interface Helpers extends Required { export function withHelpers(contract: Contract, opts: Options = {}): Helpers { const contractUpgradeable = contract.upgradeable; - const transformName = (n: ReferencedContract) => contractUpgradeable && inferTranspiled(n) ? upgradeableName(n.name) : n.name; + const transformName = (n: ReferencedContract) => + contractUpgradeable && inferTranspiled(n) ? upgradeableName(n.name) : n.name; return { upgradeable: contractUpgradeable, transformName, diff --git a/packages/core/solidity/src/print-versioned.ts b/packages/core/solidity/src/print-versioned.ts index 471b42c09..d4bde0aad 100644 --- a/packages/core/solidity/src/print-versioned.ts +++ b/packages/core/solidity/src/print-versioned.ts @@ -1,6 +1,6 @@ import contracts from '../openzeppelin-contracts'; -import type { Contract } from "./contract"; -import { printContract } from "./print"; +import type { Contract } from './contract'; +import { printContract } from './print'; export function printContractVersioned(contract: Contract): string { return printContract(contract, { @@ -8,9 +8,7 @@ export function printContractVersioned(contract: Contract): string { return { ...p, path: p.path.replace(/^@openzeppelin\/contracts(-upgradeable)?/, `$&@${contracts.version}`), - } - } + }; + }, }); } - - diff --git a/packages/core/solidity/src/print.ts b/packages/core/solidity/src/print.ts index 0cdc4d111..11fce8d12 100644 --- a/packages/core/solidity/src/print.ts +++ b/packages/core/solidity/src/print.ts @@ -1,7 +1,17 @@ -import type { Contract, Parent, ContractFunction, FunctionArgument, Value, NatspecTag, ImportContract } from './contract'; -import { Options, Helpers, withHelpers } from './options'; - -import { formatLines, spaceBetween, Lines } from './utils/format-lines'; +import type { + Contract, + Parent, + ContractFunction, + FunctionArgument, + Value, + NatspecTag, + ImportContract, +} from './contract'; +import type { Options, Helpers } from './options'; +import { withHelpers } from './options'; + +import type { Lines } from './utils/format-lines'; +import { formatLines, spaceBetween } from './utils/format-lines'; import { mapValues } from './utils/map-values'; import SOLIDITY_VERSION from './solidity-version.json'; import { inferTranspiled } from './infer-transpiled'; @@ -10,10 +20,7 @@ import { compatibleContractsSemver } from './utils/version'; export function printContract(contract: Contract, opts?: Options): string { const helpers = withHelpers(contract, opts); - const fns = mapValues( - sortedFunctions(contract), - fns => fns.map(fn => printFunction(fn, helpers)), - ); + const fns = mapValues(sortedFunctions(contract), fns => fns.map(fn => printFunction(fn, helpers))); const hasOverrides = fns.override.some(l => l.length > 0); @@ -59,31 +66,21 @@ function printConstructor(contract: Contract, helpers: Helpers): Lines[] { const hasConstructorCode = contract.constructorCode.length > 0; const parentsWithInitializers = contract.parents.filter(hasInitializer); if (hasParentParams || hasConstructorCode || (helpers.upgradeable && parentsWithInitializers.length > 0)) { - const parents = parentsWithInitializers - .flatMap(p => printParentConstructor(p, helpers)); + const parents = parentsWithInitializers.flatMap(p => printParentConstructor(p, helpers)); const modifiers = helpers.upgradeable ? ['public initializer'] : parents; - const args = contract.constructorArgs.map(a => printArgument(a, helpers)); + const args = contract.constructorArgs.map(a => printArgument(a, helpers)); const body = helpers.upgradeable ? spaceBetween( - parents.map(p => p + ';'), - contract.constructorCode, - ) + parents.map(p => p + ';'), + contract.constructorCode, + ) : contract.constructorCode; const head = helpers.upgradeable ? 'function initialize' : 'constructor'; - const constructor = printFunction2( - [], - head, - args, - modifiers, - body, - ); + const constructor = printFunction2([], head, args, modifiers, body); if (!helpers.upgradeable) { return constructor; } else { - return spaceBetween( - DISABLE_INITIALIZERS, - constructor, - ); + return spaceBetween(DISABLE_INITIALIZERS, constructor); } } else if (!helpers.upgradeable) { return []; @@ -92,14 +89,11 @@ function printConstructor(contract: Contract, helpers: Helpers): Lines[] { } } -const DISABLE_INITIALIZERS = -[ +const DISABLE_INITIALIZERS = [ '/// @custom:oz-upgrades-unsafe-allow constructor', 'constructor() {', - [ - '_disableInitializers();' - ], - '}' + ['_disableInitializers();'], + '}', ]; function hasInitializer(parent: Parent) { @@ -132,9 +126,7 @@ function printParentConstructor({ contract, params }: Parent, helpers: Helpers): const useTranspiled = helpers.upgradeable && inferTranspiled(contract); const fn = useTranspiled ? `__${contract.name}_init` : contract.name; if (useTranspiled || params.length > 0) { - return [ - fn + '(' + params.map(printValue).join(', ') + ')', - ]; + return [fn + '(' + params.map(printValue).join(', ') + ')']; } else { return []; } @@ -164,14 +156,14 @@ function printFunction(fn: ContractFunction, helpers: Helpers): Lines[] { const { transformName } = helpers; if (fn.override.size <= 1 && fn.modifiers.length === 0 && fn.code.length === 0 && !fn.final) { - return [] + return []; } - const modifiers: string[] = [fn.kind] + const modifiers: string[] = [fn.kind]; if (fn.mutability !== 'nonpayable') { modifiers.push(fn.mutability); } - + if (fn.override.size === 1) { modifiers.push(`override`); } else if (fn.override.size > 1) { @@ -206,12 +198,16 @@ function printFunction(fn: ContractFunction, helpers: Helpers): Lines[] { // generic for functions and constructors // kindedName = 'function foo' or 'constructor' -function printFunction2(comments: string[], kindedName: string, args: string[], modifiers: string[], code: Lines[]): Lines[] { - const fn: Lines[] = [ ...comments ]; +function printFunction2( + comments: string[], + kindedName: string, + args: string[], + modifiers: string[], + code: Lines[], +): Lines[] { + const fn: Lines[] = [...comments]; - const headingLength = [kindedName, ...args, ...modifiers] - .map(s => s.length) - .reduce((a, b) => a + b); + const headingLength = [kindedName, ...args, ...modifiers].map(s => s.length).reduce((a, b) => a + b); const braces = code.length > 0 ? '{' : '{}'; @@ -232,6 +228,7 @@ function printArgument(arg: FunctionArgument, { transformName }: Helpers): strin let type: string; if (typeof arg.type === 'string') { if (/^[A-Z]/.test(arg.type)) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions `Type ${arg.type} is not a primitive type. Define it as a ContractReference`; } type = arg.type; @@ -261,4 +258,4 @@ function printImports(imports: ImportContract[], helpers: Helpers): string[] { }); return lines; -} \ No newline at end of file +} diff --git a/packages/core/solidity/src/scripts/prepare.ts b/packages/core/solidity/src/scripts/prepare.ts index a499b2005..e65e08d9b 100644 --- a/packages/core/solidity/src/scripts/prepare.ts +++ b/packages/core/solidity/src/scripts/prepare.ts @@ -4,7 +4,7 @@ import hre from 'hardhat'; import type { BuildInfo } from 'hardhat/types'; import { findAll } from 'solidity-ast/utils'; import { rimraf } from 'rimraf'; -import { version } from "@openzeppelin/contracts/package.json"; +import { version } from '@openzeppelin/contracts/package.json'; import type { OpenZeppelinContracts } from '../../openzeppelin-contracts'; import { writeGeneratedSources } from '../generate/sources'; @@ -21,12 +21,13 @@ async function main() { const sources: Record = {}; for (const buildInfoPath of await hre.artifacts.getBuildInfoPaths()) { - const buildInfo: BuildInfo = JSON.parse( - await fs.readFile(buildInfoPath, 'utf8'), - ); + const buildInfo: BuildInfo = JSON.parse(await fs.readFile(buildInfoPath, 'utf8')); for (const [sourceFile, { ast }] of Object.entries(buildInfo.output.sources)) { - if (sourceFile.startsWith('@openzeppelin/contracts') || sourceFile.startsWith('@openzeppelin/community-contracts')) { + if ( + sourceFile.startsWith('@openzeppelin/contracts') || + sourceFile.startsWith('@openzeppelin/community-contracts') + ) { const sourceDependencies = (dependencies[sourceFile] ??= new Set()); for (const imp of findAll('ImportDirective', ast)) { sourceDependencies.add(imp.absolutePath); @@ -35,7 +36,10 @@ async function main() { } for (const [sourceFile, { content }] of Object.entries(buildInfo.input.sources)) { - if (sourceFile.startsWith('@openzeppelin/contracts') || sourceFile.startsWith('@openzeppelin/community-contracts')) { + if ( + sourceFile.startsWith('@openzeppelin/contracts') || + sourceFile.startsWith('@openzeppelin/community-contracts') + ) { sources[sourceFile] = content; } } diff --git a/packages/core/solidity/src/set-access-control.ts b/packages/core/solidity/src/set-access-control.ts index 7394c31c1..a4779231d 100644 --- a/packages/core/solidity/src/set-access-control.ts +++ b/packages/core/solidity/src/set-access-control.ts @@ -3,7 +3,7 @@ import { supportsInterface } from './common-functions'; export const accessOptions = [false, 'ownable', 'roles', 'managed'] as const; -export type Access = typeof accessOptions[number]; +export type Access = (typeof accessOptions)[number]; /** * Sets access control for the contract by adding inheritance. @@ -11,10 +11,10 @@ export type Access = typeof accessOptions[number]; export function setAccessControl(c: ContractBuilder, access: Access) { switch (access) { case 'ownable': { - if (c.addParent(parents.Ownable, [ {lit: 'initialOwner'} ])) { + if (c.addParent(parents.Ownable, [{ lit: 'initialOwner' }])) { c.addConstructorArgument({ type: 'address', - name: 'initialOwner' + name: 'initialOwner', }); } break; @@ -23,7 +23,7 @@ export function setAccessControl(c: ContractBuilder, access: Access) { if (c.addParent(parents.AccessControl)) { c.addConstructorArgument({ type: 'address', - name: 'defaultAdmin' + name: 'defaultAdmin', }); c.addConstructorCode('_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin);'); } @@ -31,10 +31,10 @@ export function setAccessControl(c: ContractBuilder, access: Access) { break; } case 'managed': { - if (c.addParent(parents.AccessManaged, [ {lit: 'initialAuthority'} ])) { + if (c.addParent(parents.AccessManaged, [{ lit: 'initialAuthority' }])) { c.addConstructorArgument({ type: 'address', - name: 'initialAuthority' + name: 'initialAuthority', }); } break; @@ -45,11 +45,17 @@ export function setAccessControl(c: ContractBuilder, access: Access) { /** * Enables access control for the contract and restricts the given function with access control. */ -export function requireAccessControl(c: ContractBuilder, fn: BaseFunction, access: Access, roleIdPrefix: string, roleOwner: string | undefined) { +export function requireAccessControl( + c: ContractBuilder, + fn: BaseFunction, + access: Access, + roleIdPrefix: string, + roleOwner: string | undefined, +) { if (access === false) { access = 'ownable'; } - + setAccessControl(c, access); switch (access) { @@ -61,7 +67,7 @@ export function requireAccessControl(c: ContractBuilder, fn: BaseFunction, acces const roleId = roleIdPrefix + '_ROLE'; const addedConstant = c.addVariable(`bytes32 public constant ${roleId} = keccak256("${roleId}");`); if (roleOwner && addedConstant) { - c.addConstructorArgument({type: 'address', name: roleOwner}); + c.addConstructorArgument({ type: 'address', name: roleOwner }); c.addConstructorCode(`_grantRole(${roleId}, ${roleOwner});`); } c.addModifier(`onlyRole(${roleId})`, fn); diff --git a/packages/core/solidity/src/set-clock-mode.ts b/packages/core/solidity/src/set-clock-mode.ts index 65387cdd6..189a952cc 100644 --- a/packages/core/solidity/src/set-clock-mode.ts +++ b/packages/core/solidity/src/set-clock-mode.ts @@ -1,9 +1,9 @@ -import type { ContractBuilder, ReferencedContract } from "./contract"; -import { defineFunctions } from "./utils/define-functions"; +import type { ContractBuilder, ReferencedContract } from './contract'; +import { defineFunctions } from './utils/define-functions'; export const clockModeOptions = ['blocknumber', 'timestamp'] as const; export const clockModeDefault = 'blocknumber' as const; -export type ClockMode = typeof clockModeOptions[number]; +export type ClockMode = (typeof clockModeOptions)[number]; const functions = defineFunctions({ clock: { @@ -18,7 +18,7 @@ const functions = defineFunctions({ args: [], returns: ['string memory'], mutability: 'pure' as const, - } + }, }); export function setClockMode(c: ContractBuilder, parent: ReferencedContract, votes: ClockMode) { @@ -30,4 +30,4 @@ export function setClockMode(c: ContractBuilder, parent: ReferencedContract, vot c.addOverride(parent, functions.CLOCK_MODE); c.setFunctionBody(['return "mode=timestamp";'], functions.CLOCK_MODE); } -} \ No newline at end of file +} diff --git a/packages/core/solidity/src/set-info.ts b/packages/core/solidity/src/set-info.ts index bf5b2300d..61e3713f4 100644 --- a/packages/core/solidity/src/set-info.ts +++ b/packages/core/solidity/src/set-info.ts @@ -1,4 +1,4 @@ -import type { ContractBuilder } from "./contract"; +import type { ContractBuilder } from './contract'; export const TAG_SECURITY_CONTACT = `@custom:security-contact`; @@ -9,11 +9,11 @@ export const defaults: Info = { license: 'MIT' }; export type Info = { securityContact?: string; license?: string; -} +}; export function setInfo(c: ContractBuilder, info: Info) { const { securityContact, license } = info; - + if (securityContact) { c.addNatspecTag(TAG_SECURITY_CONTACT, securityContact); } diff --git a/packages/core/solidity/src/set-upgradeable.ts b/packages/core/solidity/src/set-upgradeable.ts index 04fcccc03..ff6502805 100644 --- a/packages/core/solidity/src/set-upgradeable.ts +++ b/packages/core/solidity/src/set-upgradeable.ts @@ -1,10 +1,11 @@ import type { ContractBuilder } from './contract'; -import { Access, requireAccessControl } from './set-access-control'; +import type { Access } from './set-access-control'; +import { requireAccessControl } from './set-access-control'; import { defineFunctions } from './utils/define-functions'; export const upgradeableOptions = [false, 'transparent', 'uups'] as const; -export type Upgradeable = typeof upgradeableOptions[number]; +export type Upgradeable = (typeof upgradeableOptions)[number]; export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, access: Access) { if (upgradeable === false) { @@ -19,7 +20,8 @@ export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, acc }); switch (upgradeable) { - case 'transparent': break; + case 'transparent': + break; case 'uups': { requireAccessControl(c, functions._authorizeUpgrade, access, 'UPGRADER', 'upgrader'); @@ -42,9 +44,7 @@ export function setUpgradeable(c: ContractBuilder, upgradeable: Upgradeable, acc const functions = defineFunctions({ _authorizeUpgrade: { - args: [ - { name: 'newImplementation', type: 'address' }, - ], + args: [{ name: 'newImplementation', type: 'address' }], kind: 'internal', }, }); diff --git a/packages/core/solidity/src/stablecoin.test.ts b/packages/core/solidity/src/stablecoin.test.ts index a3980f869..b5a837863 100644 --- a/packages/core/solidity/src/stablecoin.test.ts +++ b/packages/core/solidity/src/stablecoin.test.ts @@ -1,7 +1,8 @@ import test from 'ava'; import { stablecoin } from '.'; -import { buildStablecoin, StablecoinOptions } from './stablecoin'; +import type { StablecoinOptions } from './stablecoin'; +import { buildStablecoin } from './stablecoin'; import { printContract } from './print'; function testStablecoin(title: string, opts: Partial) { @@ -18,13 +19,18 @@ function testStablecoin(title: string, opts: Partial) { /** * Tests external API for equivalence with internal API */ - function testAPIEquivalence(title: string, opts?: StablecoinOptions) { +function testAPIEquivalence(title: string, opts?: StablecoinOptions) { test(title, t => { - t.is(stablecoin.print(opts), printContract(buildStablecoin({ - name: 'MyStablecoin', - symbol: 'MST', - ...opts, - }))); + t.is( + stablecoin.print(opts), + printContract( + buildStablecoin({ + name: 'MyStablecoin', + symbol: 'MST', + ...opts, + }), + ), + ); }); } @@ -106,7 +112,10 @@ testStablecoin('stablecoin flashmint', { testAPIEquivalence('stablecoin API default'); -testAPIEquivalence('stablecoin API basic', { name: 'CustomStablecoin', symbol: 'CST' }); +testAPIEquivalence('stablecoin API basic', { + name: 'CustomStablecoin', + symbol: 'CST', +}); testAPIEquivalence('stablecoin API full', { name: 'CustomStablecoin', @@ -120,7 +129,7 @@ testAPIEquivalence('stablecoin API full', { votes: true, flashmint: true, limitations: 'allowlist', - custodian: true + custodian: true, }); test('stablecoin API assert defaults', async t => { @@ -132,4 +141,4 @@ test('stablecoin API isAccessControlRequired', async t => { t.is(stablecoin.isAccessControlRequired({ pausable: true }), true); t.is(stablecoin.isAccessControlRequired({ limitations: 'allowlist' }), true); t.is(stablecoin.isAccessControlRequired({ limitations: 'blocklist' }), true); -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/stablecoin.ts b/packages/core/solidity/src/stablecoin.ts index 66ba36c0d..7510d6755 100644 --- a/packages/core/solidity/src/stablecoin.ts +++ b/packages/core/solidity/src/stablecoin.ts @@ -1,11 +1,18 @@ -import { Contract, ContractBuilder } from './contract'; -import { Access, setAccessControl, requireAccessControl } from './set-access-control'; +import type { Contract, ContractBuilder } from './contract'; +import type { Access } from './set-access-control'; +import { setAccessControl, requireAccessControl } from './set-access-control'; import { defineFunctions } from './utils/define-functions'; import { printContract } from './print'; -import { buildERC20, ERC20Options, defaults as erc20defaults, withDefaults as withERC20Defaults, functions as erc20functions } from './erc20'; +import type { ERC20Options } from './erc20'; +import { + buildERC20, + defaults as erc20defaults, + withDefaults as withERC20Defaults, + functions as erc20functions, +} from './erc20'; export interface StablecoinOptions extends ERC20Options { - limitations?: false | "allowlist" | "blocklist"; + limitations?: false | 'allowlist' | 'blocklist'; custodian?: boolean; } @@ -65,7 +72,7 @@ function addLimitations(c: ContractBuilder, access: Access, mode: boolean | 'all c.addOverride(ERC20Limitation, functions._update); c.addOverride(ERC20Limitation, functions._approve); - const [addFn, removeFn] = type + const [addFn, removeFn] = type ? [functions.allowUser, functions.disallowUser] : [functions.blockUser, functions.unblockUser]; @@ -89,7 +96,7 @@ function addCustodian(c: ContractBuilder, access: Access) { if (access === false) { access = 'ownable'; } - + setAccessControl(c, access); switch (access) { @@ -102,7 +109,7 @@ function addCustodian(c: ContractBuilder, access: Access) { const roleId = 'CUSTODIAN_ROLE'; const addedConstant = c.addVariable(`bytes32 public constant ${roleId} = keccak256("${roleId}");`); if (roleOwner && addedConstant) { - c.addConstructorArgument({type: 'address', name: roleOwner}); + c.addConstructorArgument({ type: 'address', name: roleOwner }); c.addConstructorCode(`_grantRole(${roleId}, ${roleOwner});`); } c.setFunctionBody([`return hasRole(CUSTODIAN_ROLE, user);`], functions._isCustodian); @@ -115,8 +122,8 @@ function addCustodian(c: ContractBuilder, access: Access) { }); const logic = [ `(bool immediate,) = AuthorityUtils.canCallWithDelay(authority(), user, address(this), bytes4(_msgData()[0:4]));`, - `return immediate;` - ] + `return immediate;`, + ]; c.setFunctionBody(logic, functions._isCustodian); break; } @@ -128,40 +135,29 @@ const functions = { ...defineFunctions({ _isCustodian: { kind: 'internal' as const, - args: [ - { name: 'user', type: 'address' }, - ], + args: [{ name: 'user', type: 'address' }], returns: ['bool'], - mutability: 'view' as const + mutability: 'view' as const, }, allowUser: { kind: 'public' as const, - args: [ - { name: 'user', type: 'address' } - ], + args: [{ name: 'user', type: 'address' }], }, disallowUser: { kind: 'public' as const, - args: [ - { name: 'user', type: 'address' } - ], + args: [{ name: 'user', type: 'address' }], }, blockUser: { kind: 'public' as const, - args: [ - { name: 'user', type: 'address' } - ], + args: [{ name: 'user', type: 'address' }], }, unblockUser: { kind: 'public' as const, - args: [ - { name: 'user', type: 'address' } - ], + args: [{ name: 'user', type: 'address' }], }, - }) + }), }; - diff --git a/packages/core/solidity/src/test.ts b/packages/core/solidity/src/test.ts index 9ff1738b2..1d7105f86 100644 --- a/packages/core/solidity/src/test.ts +++ b/packages/core/solidity/src/test.ts @@ -1,5 +1,6 @@ import { promises as fs } from 'fs'; -import _test, { TestFn, ExecutionContext } from 'ava'; +import type { TestFn, ExecutionContext } from 'ava'; +import _test from 'ava'; import hre from 'hardhat'; import path from 'path'; @@ -8,7 +9,7 @@ import type { GenericOptions, KindedOptions } from './build-generic'; import { custom, erc1155, stablecoin, erc20, erc721, governor } from './api'; interface Context { - generatedSourcesPath: string + generatedSourcesPath: string; } const test = _test as TestFn; @@ -54,7 +55,7 @@ async function testCompile(t: ExecutionContext, kind: keyof KindedOptio } function isAccessControlRequired(opts: GenericOptions) { - switch(opts.kind) { + switch (opts.kind) { case 'ERC20': return erc20.isAccessControlRequired(opts); case 'ERC721': @@ -70,7 +71,7 @@ function isAccessControlRequired(opts: GenericOptions) { case 'Custom': return custom.isAccessControlRequired(opts); default: - throw new Error("No such kind"); + throw new Error('No such kind'); } } @@ -86,4 +87,4 @@ test('is access control required', async t => { } } } -}); \ No newline at end of file +}); diff --git a/packages/core/solidity/src/utils/define-functions.ts b/packages/core/solidity/src/utils/define-functions.ts index c1f664e7e..3c89e6c76 100644 --- a/packages/core/solidity/src/utils/define-functions.ts +++ b/packages/core/solidity/src/utils/define-functions.ts @@ -2,17 +2,8 @@ import type { BaseFunction } from '../contract'; type ImplicitNameFunction = Omit; -export function defineFunctions( - fns: Record, -): Record; +export function defineFunctions(fns: Record): Record; -export function defineFunctions( - fns: Record, -): Record { - return Object.fromEntries( - Object.entries(fns).map(([name, fn]) => [ - name, - Object.assign({ name }, fn), - ]), - ); +export function defineFunctions(fns: Record): Record { + return Object.fromEntries(Object.entries(fns).map(([name, fn]) => [name, Object.assign({ name }, fn)])); } diff --git a/packages/core/solidity/src/utils/duration.ts b/packages/core/solidity/src/utils/duration.ts index a0a4549f6..f74ff1c1d 100644 --- a/packages/core/solidity/src/utils/duration.ts +++ b/packages/core/solidity/src/utils/duration.ts @@ -1,5 +1,5 @@ const durationUnits = ['block', 'second', 'minute', 'hour', 'day', 'week', 'month', 'year'] as const; -type DurationUnit = typeof durationUnits[number]; +type DurationUnit = (typeof durationUnits)[number]; export const durationPattern = new RegExp(`^(\\d+(?:\\.\\d+)?) +(${durationUnits.join('|')})s?$`); const second = 1; @@ -49,4 +49,4 @@ export function durationToTimestamp(duration: string): string { } return `${value} ${unit}s`; -} \ No newline at end of file +} diff --git a/packages/core/solidity/src/utils/format-lines.ts b/packages/core/solidity/src/utils/format-lines.ts index 1860507f8..6ab9aa445 100644 --- a/packages/core/solidity/src/utils/format-lines.ts +++ b/packages/core/solidity/src/utils/format-lines.ts @@ -10,11 +10,7 @@ export function formatLinesWithSpaces(spacesPerIndent: number, ...lines: Lines[] return [...indentEach(0, lines, spacesPerIndent)].join('\n') + '\n'; } -function* indentEach( - indent: number, - lines: Lines[], - spacesPerIndent: number, -): Generator { +function* indentEach(indent: number, lines: Lines[], spacesPerIndent: number): Generator { for (const line of lines) { if (line === whitespace) { yield ''; diff --git a/packages/core/solidity/src/utils/map-values.ts b/packages/core/solidity/src/utils/map-values.ts index 56d598de3..1e42bad36 100644 --- a/packages/core/solidity/src/utils/map-values.ts +++ b/packages/core/solidity/src/utils/map-values.ts @@ -1,7 +1,5 @@ -export function mapValues( - obj: Record, - fn: (val: V) => W, -): Record { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function mapValues(obj: Record, fn: (val: V) => W): Record { const res = {} as Record; for (const key in obj) { res[key] = fn(obj[key]); diff --git a/packages/core/solidity/src/utils/to-identifier.ts b/packages/core/solidity/src/utils/to-identifier.ts index 2e4a2f9f4..70e7c9310 100644 --- a/packages/core/solidity/src/utils/to-identifier.ts +++ b/packages/core/solidity/src/utils/to-identifier.ts @@ -1,7 +1,8 @@ export function toIdentifier(str: string, capitalize = false): string { return str - .normalize('NFD').replace(/[\u0300-\u036f]/g, '') // remove accents + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') // remove accents .replace(/^[^a-zA-Z$_]+/, '') - .replace(/^(.)/, c => capitalize ? c.toUpperCase() : c) + .replace(/^(.)/, c => (capitalize ? c.toUpperCase() : c)) .replace(/[^\w$]+(.?)/g, (_, c) => c.toUpperCase()); } diff --git a/packages/core/solidity/src/utils/version.test.ts b/packages/core/solidity/src/utils/version.test.ts index ceac997fb..5a90bc410 100644 --- a/packages/core/solidity/src/utils/version.test.ts +++ b/packages/core/solidity/src/utils/version.test.ts @@ -6,7 +6,9 @@ import { compatibleContractsSemver } from './version'; import contracts from '../../openzeppelin-contracts'; test('installed contracts satisfies compatible range', t => { - t.true(semver.satisfies(contracts.version, compatibleContractsSemver), + t.true( + semver.satisfies(contracts.version, compatibleContractsSemver), `Installed contracts version ${contracts.version} does not satisfy compatible range ${compatibleContractsSemver}. -Check whether the compatible range is up to date.`); +Check whether the compatible range is up to date.`, + ); }); diff --git a/packages/core/solidity/src/zip-foundry.test.ts b/packages/core/solidity/src/zip-foundry.test.ts index eef1c8791..c1214fa24 100644 --- a/packages/core/solidity/src/zip-foundry.test.ts +++ b/packages/core/solidity/src/zip-foundry.test.ts @@ -1,4 +1,5 @@ -import _test, { TestFn, ExecutionContext } from 'ava'; +import type { TestFn, ExecutionContext } from 'ava'; +import _test from 'ava'; import { zipFoundry } from './zip-foundry'; @@ -10,7 +11,7 @@ import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; import util from 'util'; -import child from "child_process"; +import child from 'child_process'; import type { Contract } from './contract'; import { rimraf } from 'rimraf'; import type { JSZipObject } from 'jszip'; @@ -50,25 +51,47 @@ test.serial('erc20 full', async t => { }); test.serial('erc20 uups, roles', async t => { - const opts: GenericOptions = { kind: 'ERC20', name: 'My Token', symbol: 'MTK', upgradeable: 'uups', access: 'roles' }; + const opts: GenericOptions = { + kind: 'ERC20', + name: 'My Token', + symbol: 'MTK', + upgradeable: 'uups', + access: 'roles', + }; const c = buildERC20(opts); await runTest(c, t, opts); }); test.serial('erc721 uups, ownable', async t => { - const opts: GenericOptions = { kind: 'ERC721', name: 'My Token', symbol: 'MTK', upgradeable: 'uups', access: 'ownable' }; + const opts: GenericOptions = { + kind: 'ERC721', + name: 'My Token', + symbol: 'MTK', + upgradeable: 'uups', + access: 'ownable', + }; const c = buildERC721(opts); await runTest(c, t, opts); }); test.serial('erc1155 basic', async t => { - const opts: GenericOptions = { kind: 'ERC1155', name: 'My Token', uri: 'https://myuri/{id}' }; + const opts: GenericOptions = { + kind: 'ERC1155', + name: 'My Token', + uri: 'https://myuri/{id}', + }; const c = buildERC1155(opts); await runTest(c, t, opts); }); test.serial('erc1155 transparent, ownable', async t => { - const opts: GenericOptions = { kind: 'ERC1155', name: 'My Token', uri: 'https://myuri/{id}', upgradeable: 'transparent', access: 'ownable' }; + const opts: GenericOptions = { + kind: 'ERC1155', + name: 'My Token', + uri: 'https://myuri/{id}', + upgradeable: 'transparent', + access: 'ownable', + }; const c = buildERC1155(opts); await runTest(c, t, opts); }); @@ -80,7 +103,12 @@ test.serial('custom basic', async t => { }); test.serial('custom transparent, managed', async t => { - const opts: GenericOptions = { kind: 'Custom', name: 'My Contract', upgradeable: 'transparent', access: 'managed' }; + const opts: GenericOptions = { + kind: 'Custom', + name: 'My Contract', + upgradeable: 'transparent', + access: 'managed', + }; const c = buildCustom(opts); await runTest(c, t, opts); }); @@ -94,7 +122,9 @@ async function runTest(c: Contract, t: ExecutionContext, opts: GenericO } function assertLayout(zip: JSZip, c: Contract, t: ExecutionContext) { - const sorted = Object.values(zip.files).map(f => f.name).sort(); + const sorted = Object.values(zip.files) + .map(f => f.name) + .sort(); t.deepEqual(sorted, [ 'README.md', 'script/', diff --git a/packages/core/solidity/src/zip-foundry.ts b/packages/core/solidity/src/zip-foundry.ts index 96b88122e..81850a8d0 100644 --- a/packages/core/solidity/src/zip-foundry.ts +++ b/packages/core/solidity/src/zip-foundry.ts @@ -1,32 +1,21 @@ -import JSZip from "jszip"; -import type { GenericOptions } from "./build-generic"; -import type { Contract } from "./contract"; -import { printContract } from "./print"; +import JSZip from 'jszip'; +import type { GenericOptions } from './build-generic'; +import type { Contract } from './contract'; +import { printContract } from './print'; import SOLIDITY_VERSION from './solidity-version.json'; import contracts from '../openzeppelin-contracts'; -import { formatLinesWithSpaces, Lines, spaceBetween } from "./utils/format-lines"; +import type { Lines } from './utils/format-lines'; +import { formatLinesWithSpaces, spaceBetween } from './utils/format-lines'; function getHeader(c: Contract) { - return [ - `// SPDX-License-Identifier: ${c.license}`, - `pragma solidity ^${SOLIDITY_VERSION};` - ]; + return [`// SPDX-License-Identifier: ${c.license}`, `pragma solidity ^${SOLIDITY_VERSION};`]; } const test = (c: Contract, opts?: GenericOptions) => { - return formatLinesWithSpaces( - 2, - ...spaceBetween( - getHeader(c), - getImports(c), - getTestCase(c), - ), - ); + return formatLinesWithSpaces(2, ...spaceBetween(getHeader(c), getImports(c), getTestCase(c))); function getImports(c: Contract) { - const result = [ - 'import {Test} from "forge-std/Test.sol";', - ]; + const result = ['import {Test} from "forge-std/Test.sol";']; if (c.upgradeable) { result.push('import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";'); } @@ -39,15 +28,8 @@ const test = (c: Contract, opts?: GenericOptions) => { return [ `contract ${c.name}Test is Test {`, spaceBetween( - [ - `${c.name} public instance;`, - ], - [ - 'function setUp() public {', - getAddressVariables(c, args), - getDeploymentCode(c, args), - '}', - ], + [`${c.name} public instance;`], + ['function setUp() public {', getAddressVariables(c, args), getDeploymentCode(c, args), '}'], getContractSpecificTestFunction(), ), '}', @@ -59,29 +41,20 @@ const test = (c: Contract, opts?: GenericOptions) => { if (opts?.upgradeable === 'transparent') { return [ `address proxy = Upgrades.deployTransparentProxy(`, - [ - `"${c.name}.sol",`, - `initialOwner,`, - `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))` - ], + [`"${c.name}.sol",`, `initialOwner,`, `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))`], ');', `instance = ${c.name}(proxy);`, ]; } else { return [ `address proxy = Upgrades.deployUUPSProxy(`, - [ - `"${c.name}.sol",`, - `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))` - ], + [`"${c.name}.sol",`, `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))`], ');', `instance = ${c.name}(proxy);`, ]; } } else { - return [ - `instance = new ${c.name}(${args.join(', ')});`, - ]; + return [`instance = new ${c.name}(${args.join(', ')});`]; } } @@ -102,32 +75,14 @@ const test = (c: Contract, opts?: GenericOptions) => { switch (opts.kind) { case 'ERC20': case 'ERC721': - return [ - 'function testName() public view {', - [ - `assertEq(instance.name(), "${opts.name}");` - ], - '}', - ]; + return ['function testName() public view {', [`assertEq(instance.name(), "${opts.name}");`], '}']; case 'ERC1155': - return [ - 'function testUri() public view {', - [ - `assertEq(instance.uri(0), "${opts.uri}");` - ], - '}', - ]; + return ['function testUri() public view {', [`assertEq(instance.uri(0), "${opts.uri}");`], '}']; case 'Governor': case 'Custom': - return [ - 'function testSomething() public {', - [ - '// Add your test here', - ], - '}', - ] + return ['function testSomething() public {', ['// Add your test here'], '}']; default: throw new Error('Unknown ERC'); @@ -148,20 +103,10 @@ function getAddressArgs(c: Contract): string[] { } const script = (c: Contract, opts?: GenericOptions) => { - return formatLinesWithSpaces( - 2, - ...spaceBetween( - getHeader(c), - getImports(c), - getScript(c), - ), - ); + return formatLinesWithSpaces(2, ...spaceBetween(getHeader(c), getImports(c), getScript(c))); function getImports(c: Contract) { - const result = [ - 'import {Script} from "forge-std/Script.sol";', - 'import {console} from "forge-std/console.sol";', - ]; + const result = ['import {Script} from "forge-std/Script.sol";', 'import {console} from "forge-std/console.sol";']; if (c.upgradeable) { result.push('import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";'); } @@ -181,14 +126,8 @@ const script = (c: Contract, opts?: GenericOptions) => { return [ `contract ${c.name}Script is Script {`, spaceBetween( - [ - 'function setUp() public {}', - ], - [ - 'function run() public {', - args.length > 0 ? addTodoAndCommentOut(deploymentLines) : deploymentLines, - '}', - ], + ['function setUp() public {}'], + ['function run() public {', args.length > 0 ? addTodoAndCommentOut(deploymentLines) : deploymentLines, '}'], ), '}', ]; @@ -199,29 +138,20 @@ const script = (c: Contract, opts?: GenericOptions) => { if (opts?.upgradeable === 'transparent') { return [ `address proxy = Upgrades.deployTransparentProxy(`, - [ - `"${c.name}.sol",`, - `initialOwner,`, - `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))` - ], + [`"${c.name}.sol",`, `initialOwner,`, `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))`], ');', `${c.name} instance = ${c.name}(proxy);`, ]; } else { return [ `address proxy = Upgrades.deployUUPSProxy(`, - [ - `"${c.name}.sol",`, - `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))` - ], + [`"${c.name}.sol",`, `abi.encodeCall(${c.name}.initialize, (${args.join(', ')}))`], ');', `${c.name} instance = ${c.name}(proxy);`, ]; } } else { - return [ - `${c.name} instance = new ${c.name}(${args.join(', ')});`, - ]; + return [`${c.name} instance = new ${c.name}(${args.join(', ')});`]; } } @@ -274,14 +204,18 @@ then # Initialize sample Foundry project forge init --force --no-commit --quiet -${c.upgradeable ? `\ +${ + c.upgradeable + ? `\ # Install OpenZeppelin Contracts and Upgrades forge install OpenZeppelin/openzeppelin-contracts-upgradeable@v${contracts.version} --no-commit --quiet forge install OpenZeppelin/openzeppelin-foundry-upgrades --no-commit --quiet\ -` : `\ +` + : `\ # Install OpenZeppelin Contracts forge install OpenZeppelin/openzeppelin-contracts@v${contracts.version} --no-commit --quiet\ -`} +` +} # Remove unneeded Foundry template files rm src/Counter.sol @@ -297,7 +231,9 @@ ${c.upgradeable ? `\ then echo "" >> remappings.txt fi -${c.upgradeable ? `\ +${ + c.upgradeable + ? `\ echo "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/" >> remappings.txt echo "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/" >> remappings.txt @@ -307,9 +243,11 @@ ${c.upgradeable ? `\ echo "ast = true" >> foundry.toml echo "build_info = true" >> foundry.toml echo "extra_output = [\\"storageLayout\\"]" >> foundry.toml\ -` : `\ +` + : `\ echo "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/" >> remappings.txt\ -`} +` +} # Perform initial git commit git add . @@ -363,4 +301,4 @@ export async function zipFoundry(c: Contract, opts?: GenericOptions) { zip.file('README.md', readme(c)); return zip; -} \ No newline at end of file +} diff --git a/packages/core/solidity/src/zip-hardhat.test.ts b/packages/core/solidity/src/zip-hardhat.test.ts index 7ad696284..5e08d7010 100644 --- a/packages/core/solidity/src/zip-hardhat.test.ts +++ b/packages/core/solidity/src/zip-hardhat.test.ts @@ -1,4 +1,5 @@ -import _test, { TestFn, ExecutionContext } from 'ava'; +import type { TestFn, ExecutionContext } from 'ava'; +import _test from 'ava'; import { zipHardhat } from './zip-hardhat'; @@ -10,7 +11,7 @@ import { promises as fs } from 'fs'; import path from 'path'; import os from 'os'; import util from 'util'; -import child from "child_process"; +import child from 'child_process'; import type { Contract } from './contract'; import { rimraf } from 'rimraf'; import type { JSZipObject } from 'jszip'; @@ -50,13 +51,22 @@ test.serial('erc20 full', async t => { }); test.serial('erc721 upgradeable', async t => { - const opts: GenericOptions = { kind: 'ERC721', name: 'My Token', symbol: 'MTK', upgradeable: 'uups' }; + const opts: GenericOptions = { + kind: 'ERC721', + name: 'My Token', + symbol: 'MTK', + upgradeable: 'uups', + }; const c = buildERC721(opts); await runTest(c, t, opts); }); test.serial('erc1155 basic', async t => { - const opts: GenericOptions = { kind: 'ERC1155', name: 'My Token', uri: 'https://myuri/{id}' }; + const opts: GenericOptions = { + kind: 'ERC1155', + name: 'My Token', + uri: 'https://myuri/{id}', + }; const c = buildERC1155(opts); await runTest(c, t, opts); }); @@ -68,7 +78,11 @@ test.serial('custom basic', async t => { }); test.serial('custom upgradeable', async t => { - const opts: GenericOptions = { kind: 'Custom', name: 'My Contract', upgradeable: 'transparent' }; + const opts: GenericOptions = { + kind: 'Custom', + name: 'My Contract', + upgradeable: 'transparent', + }; const c = buildCustom(opts); await runTest(c, t, opts); }); @@ -82,7 +96,9 @@ async function runTest(c: Contract, t: ExecutionContext, opts: GenericO } function assertLayout(zip: JSZip, c: Contract, t: ExecutionContext) { - const sorted = Object.values(zip.files).map(f => f.name).sort(); + const sorted = Object.values(zip.files) + .map(f => f.name) + .sort(); t.deepEqual(sorted, [ '.gitignore', 'README.md', diff --git a/packages/core/solidity/src/zip-hardhat.ts b/packages/core/solidity/src/zip-hardhat.ts index 195322586..893f9cf79 100644 --- a/packages/core/solidity/src/zip-hardhat.ts +++ b/packages/core/solidity/src/zip-hardhat.ts @@ -1,9 +1,10 @@ -import JSZip from "jszip"; -import type { GenericOptions } from "./build-generic"; -import type { Contract } from "./contract"; -import { printContract } from "./print"; +import JSZip from 'jszip'; +import type { GenericOptions } from './build-generic'; +import type { Contract } from './contract'; +import { printContract } from './print'; import SOLIDITY_VERSION from './solidity-version.json'; -import { formatLinesWithSpaces, Lines, spaceBetween } from "./utils/format-lines"; +import type { Lines } from './utils/format-lines'; +import { formatLinesWithSpaces, spaceBetween } from './utils/format-lines'; const hardhatConfig = (upgradeable: boolean) => `\ import { HardhatUserConfig } from "hardhat/config"; @@ -52,13 +53,7 @@ artifacts `; const test = (c: Contract, opts?: GenericOptions) => { - return formatLinesWithSpaces( - 2, - ...spaceBetween( - getImports(c), - getTestCase(c), - ), - ); + return formatLinesWithSpaces(2, ...spaceBetween(getImports(c), getTestCase(c))); function getTestCase(c: Contract) { const args = getAddressArgs(c); @@ -67,27 +62,19 @@ const test = (c: Contract, opts?: GenericOptions) => { [ 'it("Test contract", async function () {', spaceBetween( - [ - `const ContractFactory = await ethers.getContractFactory("${c.name}");`, - ], + [`const ContractFactory = await ethers.getContractFactory("${c.name}");`], getAddressVariables(args), - [ - `const instance = await ${getDeploymentCall(c, args)};`, - 'await instance.waitForDeployment();' - ], + [`const instance = await ${getDeploymentCall(c, args)};`, 'await instance.waitForDeployment();'], getExpects(), ), - '});' + '});', ], '});', ]; } function getImports(c: Contract) { - return [ - 'import { expect } from "chai";', - `import { ${getHardhatPlugins(c).join(', ')} } from "hardhat";`, - ]; + return ['import { expect } from "chai";', `import { ${getHardhatPlugins(c).join(', ')} } from "hardhat";`]; } function getExpects(): Lines[] { @@ -131,7 +118,9 @@ function getAddressArgs(c: Contract): string[] { } function getDeploymentCall(c: Contract, args: string[]): string { - return c.upgradeable ? `upgrades.deployProxy(ContractFactory, [${args.join(', ')}])` : `ContractFactory.deploy(${args.join(', ')})`; + return c.upgradeable + ? `upgrades.deployProxy(ContractFactory, [${args.join(', ')}])` + : `ContractFactory.deploy(${args.join(', ')})`; } const script = (c: Contract) => { @@ -155,7 +144,8 @@ main().catch((error) => { console.error(error); process.exitCode = 1; }); -`}; +`; +}; const readme = `\ # Sample Hardhat Project @@ -184,7 +174,7 @@ npx hardhat run --network scripts/deploy.ts `; function getHardhatPlugins(c: Contract) { - let plugins = ['ethers']; + const plugins = ['ethers']; if (c.upgradeable) { plugins.push('upgrades'); } @@ -194,10 +184,14 @@ function getHardhatPlugins(c: Contract) { export async function zipHardhat(c: Contract, opts?: GenericOptions) { const zip = new JSZip(); - const { default: packageJson } = c.upgradeable ? await import("./environments/hardhat/upgradeable/package.json") : await import("./environments/hardhat/package.json"); + const { default: packageJson } = c.upgradeable + ? await import('./environments/hardhat/upgradeable/package.json') + : await import('./environments/hardhat/package.json'); packageJson.license = c.license; - const { default: packageLock } = c.upgradeable ? await import("./environments/hardhat/upgradeable/package-lock.json") : await import("./environments/hardhat/package-lock.json"); + const { default: packageLock } = c.upgradeable + ? await import('./environments/hardhat/upgradeable/package-lock.json') + : await import('./environments/hardhat/package-lock.json'); packageLock.packages[''].license = c.license; zip.file(`contracts/${c.name}.sol`, printContract(c)); @@ -211,4 +205,4 @@ export async function zipHardhat(c: Contract, opts?: GenericOptions) { zip.file('tsconfig.json', tsConfig); return zip; -} \ No newline at end of file +} diff --git a/packages/core/solidity/zip-env-foundry.ts b/packages/core/solidity/zip-env-foundry.ts index 17e647662..b28db5f46 100644 --- a/packages/core/solidity/zip-env-foundry.ts +++ b/packages/core/solidity/zip-env-foundry.ts @@ -1 +1 @@ -export * from './src/zip-foundry'; \ No newline at end of file +export * from './src/zip-foundry'; diff --git a/packages/core/solidity/zip-env-hardhat.ts b/packages/core/solidity/zip-env-hardhat.ts index 353801961..8786bfeae 100644 --- a/packages/core/solidity/zip-env-hardhat.ts +++ b/packages/core/solidity/zip-env-hardhat.ts @@ -1 +1 @@ -export * from './src/zip-hardhat'; \ No newline at end of file +export * from './src/zip-hardhat'; diff --git a/packages/ui/api/ai.ts b/packages/ui/api/ai.ts index 90fff1255..2332bea44 100644 --- a/packages/ui/api/ai.ts +++ b/packages/ui/api/ai.ts @@ -1,54 +1,73 @@ -import OpenAI from 'https://esm.sh/openai@4.11.0' -import { OpenAIStream, StreamingTextResponse } from 'https://esm.sh/ai@2.2.16' -import { erc20Function, erc721Function, erc1155Function, stablecoinFunction, realWorldAssetFunction, governorFunction, customFunction } from '../src/solidity/wiz-functions.ts' -import { Redis } from 'https://esm.sh/@upstash/redis@1.25.1' +import OpenAI from 'https://esm.sh/openai@4.11.0'; +import { OpenAIStream, StreamingTextResponse } from 'https://esm.sh/ai@2.2.16'; +import { + erc20Function, + erc721Function, + erc1155Function, + stablecoinFunction, + realWorldAssetFunction, + governorFunction, + customFunction, +} from '../src/solidity/wiz-functions.ts'; +import { Redis } from 'https://esm.sh/@upstash/redis@1.25.1'; export default async (req: Request) => { try { - const data = await req.json() - const apiKey = Deno.env.get('OPENAI_API_KEY') + const data = await req.json(); + const apiKey = Deno.env.get('OPENAI_API_KEY'); - const redisUrl = Deno.env.get('REDIS_URL') - const redisToken = Deno.env.get('REDIS_TOKEN') + const redisUrl = Deno.env.get('REDIS_URL'); + const redisToken = Deno.env.get('REDIS_TOKEN'); - if (!redisUrl || !redisToken) { throw new Error('missing redis credentials') } + if (!redisUrl || !redisToken) { + throw new Error('missing redis credentials'); + } const redis = new Redis({ - url: redisUrl, + url: redisUrl, token: redisToken, - }) + }); const openai = new OpenAI({ - apiKey: apiKey - }) + apiKey: apiKey, + }); - const validatedMessages = data.messages.filter((message: { role: string, content: string }) => { - return message.content.length < 500 - }) + const validatedMessages = data.messages.filter((message: { role: string; content: string }) => { + return message.content.length < 500; + }); - const messages = [{ - role: 'system', - content: ` + const messages = [ + { + role: 'system', + content: ` You are a smart contract assistant built by OpenZeppelin to help users using OpenZeppelin Contracts Wizard. The current options are ${JSON.stringify(data.currentOpts)}. Please be kind and concise. Keep responses to <100 words. - `.trim() - }, ...validatedMessages] + `.trim(), + }, + ...validatedMessages, + ]; const response = await openai.chat.completions.create({ model: 'gpt-4-1106-preview', messages, functions: [ - erc20Function, erc721Function, erc1155Function, stablecoinFunction, realWorldAssetFunction, governorFunction, customFunction + erc20Function, + erc721Function, + erc1155Function, + stablecoinFunction, + realWorldAssetFunction, + governorFunction, + customFunction, ], temperature: 0.7, - stream: true - }) + stream: true, + }); const stream = OpenAIStream(response, { async onCompletion(completion) { - const id = data.chatId - const updatedAt = Date.now() + const id = data.chatId; + const updatedAt = Date.now(); const payload = { id, updatedAt, @@ -56,24 +75,23 @@ export default async (req: Request) => { ...messages, { content: completion, - role: 'assistant' - } - ] - } - const exists = await redis.exists(`chat:${id}`) + role: 'assistant', + }, + ], + }; + const exists = await redis.exists(`chat:${id}`); if (!exists) { - // @ts-ignore redis types seem to require [key: string] - payload.createdAt = updatedAt + // @ts-expect-error redis types seem to require [key: string] + payload.createdAt = updatedAt; } - await redis.hset(`chat:${id}`, payload) - } + await redis.hset(`chat:${id}`, payload); + }, }); return new StreamingTextResponse(stream); - } catch (e) { - console.error("Could not retrieve results:", e); + console.error('Could not retrieve results:', e); return Response.json({ - error: 'Could not retrieve results.' + error: 'Could not retrieve results.', }); } -} +}; diff --git a/packages/ui/postcss.config.js b/packages/ui/postcss.config.js index 3dd96fd1e..01dfd298e 100644 --- a/packages/ui/postcss.config.js +++ b/packages/ui/postcss.config.js @@ -3,9 +3,5 @@ const tailwindcss = require('tailwindcss'); const autoprefixer = require('autoprefixer'); module.exports = { - plugins: [ - nesting, - tailwindcss, - autoprefixer, - ], + plugins: [nesting, tailwindcss, autoprefixer], }; diff --git a/packages/ui/rollup.config.mjs b/packages/ui/rollup.config.mjs index 28b9628c9..e920328fd 100644 --- a/packages/ui/rollup.config.mjs +++ b/packages/ui/rollup.config.mjs @@ -30,7 +30,10 @@ function onStartRun(cmd, ...args) { return { async buildStart() { if (ran) return; - const child = proc.spawn(cmd, args, { stdio: 'inherit', shell: process.platform == 'win32' }); + const child = proc.spawn(cmd, args, { + stdio: 'inherit', + shell: process.platform == 'win32', + }); const [code, signal] = await events.once(child, 'exit'); if (code || signal) { throw new Error(`Command \`${cmd}\` failed`); diff --git a/packages/ui/rollup.server.mjs b/packages/ui/rollup.server.mjs index 33e18e92c..ff2266018 100644 --- a/packages/ui/rollup.server.mjs +++ b/packages/ui/rollup.server.mjs @@ -12,14 +12,10 @@ export default function serve() { return { writeBundle() { if (state.server) return; - state.server = proc.spawn( - 'npm', - ['run', 'start', '--', '--dev'], - { - stdio: ['ignore', 'inherit', 'inherit'], - shell: true, - }, - ); + state.server = proc.spawn('npm', ['run', 'start', '--', '--dev'], { + stdio: ['ignore', 'inherit', 'inherit'], + shell: true, + }); process.on('SIGTERM', toExit); process.on('exit', toExit); diff --git a/packages/ui/src/cairo/highlightjs.ts b/packages/ui/src/cairo/highlightjs.ts index c94c01084..eb4e7c319 100644 --- a/packages/ui/src/cairo/highlightjs.ts +++ b/packages/ui/src/cairo/highlightjs.ts @@ -1,6 +1,6 @@ import hljs from 'highlight.js/lib/core'; -// @ts-ignore +// @ts-expect-error missing type declaration import hljsDefineCairo from 'highlightjs-cairo'; hljsDefineCairo(hljs); diff --git a/packages/ui/src/cairo/inject-hyperlinks.ts b/packages/ui/src/cairo/inject-hyperlinks.ts index d48acfdd3..a83929d2e 100644 --- a/packages/ui/src/cairo/inject-hyperlinks.ts +++ b/packages/ui/src/cairo/inject-hyperlinks.ts @@ -1,7 +1,8 @@ -import { contractsVersionTag } from "@openzeppelin/wizard-cairo/src"; +/* eslint-disable no-useless-escape */ +import { contractsVersionTag } from '@openzeppelin/wizard-cairo/src'; export function injectHyperlinks(code: string) { - const importRegex = /use<\/span> (openzeppelin)::([^A-Z]*)(::[a-zA-Z0-9]+|::{)/g + const importRegex = /use<\/span> (openzeppelin)::([^A-Z]*)(::[a-zA-Z0-9]+|::{)/g; let result = code; let match = importRegex.exec(code); while (match != null) { @@ -9,21 +10,25 @@ export function injectHyperlinks(code: string) { if (line !== undefined && libraryPrefix !== undefined && libraryPath !== undefined && suffix !== undefined) { const githubPrefix = `https://github.com/OpenZeppelin/cairo-contracts/blob/${contractsVersionTag}/packages/`; - let libraryPathSegments = libraryPath.split('::'); + const libraryPathSegments = libraryPath.split('::'); libraryPathSegments.splice(1, 0, 'src'); if (libraryPathSegments !== undefined && libraryPathSegments.length > 0) { let replacement; if (suffix === '::{') { // Multiple components are imported, so remove components and link to the parent .cairo file - replacement = `use<\/span> ${libraryPrefix}::${libraryPath}${suffix}`; // Exclude suffix from link + replacement = `use<\/span> ${libraryPrefix}::${libraryPath}${suffix}`; // Exclude suffix from link } else { // Single component is imported // If a mapping exists, link to the mapped file, otherwise remove the component and link to the parent .cairo file const componentName = suffix.substring(2, suffix.length); const mapping = componentMappings[componentName]; const urlSuffix = mapping ? `/${mapping}.cairo` : '.cairo'; - replacement = `use<\/span> ${libraryPrefix}::${libraryPath}${suffix}`; // Include suffix (component) in link + replacement = `use<\/span> ${libraryPrefix}::${libraryPath}${suffix}`; // Include suffix (component) in link } result = result.replace(line, replacement); @@ -35,6 +40,6 @@ export function injectHyperlinks(code: string) { } const componentMappings: { [key: string]: string } = { - 'AccountComponent': 'account', - 'UpgradeableComponent': 'upgradeable', + AccountComponent: 'account', + UpgradeableComponent: 'upgradeable', } as const; diff --git a/packages/ui/src/common/error-tooltip.ts b/packages/ui/src/common/error-tooltip.ts index 79b546a88..804eb5be0 100644 --- a/packages/ui/src/common/error-tooltip.ts +++ b/packages/ui/src/common/error-tooltip.ts @@ -1,4 +1,4 @@ -import tippy, { Props } from 'tippy.js'; +import tippy from 'tippy.js'; const klass = 'has-error'; @@ -9,7 +9,9 @@ export function error(node: HTMLElement, content?: string) { placement: 'right', theme: 'light-red border', showOnCreate: false, - onShow: () => { shown = true; }, + onShow: () => { + shown = true; + }, }); t.disable(); diff --git a/packages/ui/src/common/initial-options.ts b/packages/ui/src/common/initial-options.ts index 9a4ec972d..fb217fa7d 100644 --- a/packages/ui/src/common/initial-options.ts +++ b/packages/ui/src/common/initial-options.ts @@ -1 +1,5 @@ -export interface InitialOptions { name?: string, symbol?: string, premint?: string }; \ No newline at end of file +export interface InitialOptions { + name?: string; + symbol?: string; + premint?: string; +} diff --git a/packages/ui/src/common/post-config.ts b/packages/ui/src/common/post-config.ts index cfc3f4955..b917f6d40 100644 --- a/packages/ui/src/common/post-config.ts +++ b/packages/ui/src/common/post-config.ts @@ -11,8 +11,13 @@ export type Action = 'copy' | 'remix' | 'download-file' | 'download-hardhat' | ' export type Language = 'solidity' | 'cairo' | 'stylus' | 'stellar'; export async function postConfig( - opts: Required | Required, - action: Action, - language: Language) { - window.gtag?.('event', 'wizard_action', { ...opts, action, wizard_lang: language }); -} \ No newline at end of file + opts: Required | Required, + action: Action, + language: Language, +) { + window.gtag?.('event', 'wizard_action', { + ...opts, + action, + wizard_lang: language, + }); +} diff --git a/packages/ui/src/common/post-message.ts b/packages/ui/src/common/post-message.ts index d621a7053..c5ddb81d9 100644 --- a/packages/ui/src/common/post-message.ts +++ b/packages/ui/src/common/post-message.ts @@ -28,7 +28,7 @@ export function postMessage(msg: Message) { } export function postMessageToIframe(id: 'defender-deploy', msg: Message) { - var iframe: HTMLIFrameElement | null = document.getElementById(id) as HTMLIFrameElement; + const iframe: HTMLIFrameElement | null = document.getElementById(id) as HTMLIFrameElement; if (iframe) { iframe.contentWindow?.postMessage(msg, '*'); // in case the iframe is still loading, waits @@ -37,6 +37,6 @@ export function postMessageToIframe(id: 'defender-deploy', msg: Message) { setTimeout(() => { iframe?.contentWindow?.postMessage(msg, '*'); }, 1000); - } + }; } } diff --git a/packages/ui/src/common/resize-to-fit.ts b/packages/ui/src/common/resize-to-fit.ts index f24613e88..6326f1d18 100644 --- a/packages/ui/src/common/resize-to-fit.ts +++ b/packages/ui/src/common/resize-to-fit.ts @@ -5,10 +5,11 @@ export function resizeToFit(node: HTMLInputElement) { } const style = window.getComputedStyle(node); - const font = ['font-size', 'font-family'].map(p => style.getPropertyValue(p)).join(' '); const textWidth = measureTextWidth(node.value, style); const minWidth = measureTextWidth(node.placeholder, style); - const padding = ['padding-left', 'padding-right', 'border-left-width', 'border-right-width'].map(p => style.getPropertyValue(p)); + const padding = ['padding-left', 'padding-right', 'border-left-width', 'border-right-width'].map(p => + style.getPropertyValue(p), + ); const result = `calc(5px + max(${minWidth}, ${textWidth}) + ${padding.join(' + ')})`; node.style.setProperty('width', result); }; diff --git a/packages/ui/src/main.ts b/packages/ui/src/main.ts index a85ab8a81..346c3d8ea 100644 --- a/packages/ui/src/main.ts +++ b/packages/ui/src/main.ts @@ -30,22 +30,31 @@ const initialOpts: InitialOptions = { name: params.get('name') ?? undefined, symbol: params.get('symbol') ?? undefined, premint: params.get('premint') ?? undefined, -} +}; -let compatibleVersionSemver = lang === 'cairo' ? compatibleCairoContractsSemver : compatibleSolidityContractsSemver; +const compatibleVersionSemver = lang === 'cairo' ? compatibleCairoContractsSemver : compatibleSolidityContractsSemver; let app; if (requestedVersion && !semver.satisfies(requestedVersion, compatibleVersionSemver)) { postMessage({ kind: 'oz-wizard-unsupported-version' }); - app = new UnsupportedVersion({ target: document.body, props: { requestedVersion, compatibleVersionSemver }}); + app = new UnsupportedVersion({ + target: document.body, + props: { requestedVersion, compatibleVersionSemver }, + }); } else { switch (lang) { case 'cairo': - app = new CairoApp({ target: document.body, props: { initialTab, initialOpts } }); + app = new CairoApp({ + target: document.body, + props: { initialTab, initialOpts }, + }); break; case 'solidity': default: - app = new SolidityApp({ target: document.body, props: { initialTab, initialOpts } }); + app = new SolidityApp({ + target: document.body, + props: { initialTab, initialOpts }, + }); break; } } @@ -55,4 +64,3 @@ app.$on('tab-change', (e: CustomEvent) => { }); export default app; - diff --git a/packages/ui/src/solidity/highlightjs.ts b/packages/ui/src/solidity/highlightjs.ts index bbe81e6f6..5772decd1 100644 --- a/packages/ui/src/solidity/highlightjs.ts +++ b/packages/ui/src/solidity/highlightjs.ts @@ -1,6 +1,6 @@ import hljs from 'highlight.js/lib/core'; -// @ts-ignore +// @ts-expect-error missing type declaration file import hljsDefineSolidity from 'highlightjs-solidity'; hljsDefineSolidity(hljs); diff --git a/packages/ui/src/solidity/inject-hyperlinks.ts b/packages/ui/src/solidity/inject-hyperlinks.ts index 77efa3002..d8ae1ef13 100644 --- a/packages/ui/src/solidity/inject-hyperlinks.ts +++ b/packages/ui/src/solidity/inject-hyperlinks.ts @@ -1,11 +1,19 @@ -import { version as contractsVersion } from "@openzeppelin/contracts/package.json"; +import { version as contractsVersion } from '@openzeppelin/contracts/package.json'; export function injectHyperlinks(code: string) { // We are modifying HTML, so use HTML escaped chars. The pattern excludes paths that include /../ in the URL. - const contractsRegex = /"(@openzeppelin\/)(contracts-upgradeable\/|contracts\/)((?:(?!\.\.)[^/]+\/)*?[^/]*?)"/g - const communityContractsRegex = /"(@openzeppelin\/)(community-contracts\/contracts\/)((?:(?!\.\.)[^/]+\/)*?[^/]*?)"/g + const contractsRegex = + /"(@openzeppelin\/)(contracts-upgradeable\/|contracts\/)((?:(?!\.\.)[^/]+\/)*?[^/]*?)"/g; + const communityContractsRegex = + /"(@openzeppelin\/)(community-contracts\/contracts\/)((?:(?!\.\.)[^/]+\/)*?[^/]*?)"/g; - return code. - replace(contractsRegex, `"$1$2$3"`). - replace(communityContractsRegex, `"$1$2$3"`); + return code + .replace( + contractsRegex, + `"$1$2$3"`, + ) + .replace( + communityContractsRegex, + `"$1$2$3"`, + ); } diff --git a/packages/ui/src/solidity/wiz-functions.ts b/packages/ui/src/solidity/wiz-functions.ts index 2c8ee6d8a..0b0c9efab 100644 --- a/packages/ui/src/solidity/wiz-functions.ts +++ b/packages/ui/src/solidity/wiz-functions.ts @@ -1,27 +1,54 @@ const commonOptions = { // 'false' gets converted to false - access: { type: 'string', enum: ['false', 'ownable', 'roles', 'managed'], description: 'The type of access control to provision. Ownable is a simple mechanism with a single account authorized for all privileged actions. Roles is a flexible mechanism with a separate role for each privileged action. A role can have many authorized accounts. Managed enables a central contract to define a policy that allows certain callers to access certain functions.' }, + access: { + type: 'string', + enum: ['false', 'ownable', 'roles', 'managed'], + description: + 'The type of access control to provision. Ownable is a simple mechanism with a single account authorized for all privileged actions. Roles is a flexible mechanism with a separate role for each privileged action. A role can have many authorized accounts. Managed enables a central contract to define a policy that allows certain callers to access certain functions.', + }, // 'false' gets converted to false - upgradeable: { type: 'string', enum: ['false', 'transparent', 'uups'], description: 'Whether the smart contract is upgradeable. Transparent uses more complex proxy with higher overhead, requires less changes in your contract.Can also be used with beacons. UUPS uses simpler proxy with less overhead, requires including extra code in your contract. Allows flexibility for authorizing upgrades.' }, + upgradeable: { + type: 'string', + enum: ['false', 'transparent', 'uups'], + description: + 'Whether the smart contract is upgradeable. Transparent uses more complex proxy with higher overhead, requires less changes in your contract.Can also be used with beacons. UUPS uses simpler proxy with less overhead, requires including extra code in your contract. Allows flexibility for authorizing upgrades.', + }, info: { type: 'object', description: 'Metadata about the contract and author', properties: { - securityContact: { type: 'string', description: 'Email where people can contact you to report security issues. Will only be visible if contract metadata is verified.' }, - license: { type: 'string', description: 'The license used by the contract, default is "MIT"' } - } - } -} + securityContact: { + type: 'string', + description: + 'Email where people can contact you to report security issues. Will only be visible if contract metadata is verified.', + }, + license: { + type: 'string', + description: 'The license used by the contract, default is "MIT"', + }, + }, + }, +}; const repeatedOptions = { name: { type: 'string', description: 'The name of the contract' }, symbol: { type: 'string', description: 'The short symbol for the token' }, - burnable: { type: 'boolean', description: 'Whether token holders will be able to destroy their tokens' }, - pausable: { type: 'boolean', description: 'Whether privileged accounts will be able to pause the functionality marked as whenNotPaused. Useful for emergency response.' }, - mintable: { type: 'boolean', description: 'Whether privileged accounts will be able to create more supply or emit more tokens' }, -} + burnable: { + type: 'boolean', + description: 'Whether token holders will be able to destroy their tokens', + }, + pausable: { + type: 'boolean', + description: + 'Whether privileged accounts will be able to pause the functionality marked as whenNotPaused. Useful for emergency response.', + }, + mintable: { + type: 'boolean', + description: 'Whether privileged accounts will be able to create more supply or emit more tokens', + }, +}; export const erc20Function = { name: 'erc20', @@ -33,17 +60,33 @@ export const erc20Function = { symbol: repeatedOptions.symbol, burnable: repeatedOptions.burnable, pausable: repeatedOptions.pausable, - premint: { type: 'number', description: 'The number of tokens to premint for the deployer.' }, + premint: { + type: 'number', + description: 'The number of tokens to premint for the deployer.', + }, mintable: repeatedOptions.mintable, - permit: { type: 'boolean', description: 'Whether without paying gas, token holders will be able to allow third parties to transfer from their account.' }, + permit: { + type: 'boolean', + description: + 'Whether without paying gas, token holders will be able to allow third parties to transfer from their account.', + }, // 'false' gets converted to false - votes: { type: 'string', enum: ['false', 'blocknumber', 'timestamp'], description: 'Whether to keep track of historical balances for voting in on-chain governance. Voting durations can be expressed as block numbers or timestamps.'}, - flashmint: { type: 'boolean', description: 'Whether to include built-in flash loans to allow lending tokens without requiring collateral as long as they\'re returned in the same transaction.' }, - ...commonOptions + votes: { + type: 'string', + enum: ['false', 'blocknumber', 'timestamp'], + description: + 'Whether to keep track of historical balances for voting in on-chain governance. Voting durations can be expressed as block numbers or timestamps.', + }, + flashmint: { + type: 'boolean', + description: + "Whether to include built-in flash loans to allow lending tokens without requiring collateral as long as they're returned in the same transaction.", + }, + ...commonOptions, }, required: ['name', 'symbol'], - } -} + }, +}; export const erc721Function = { name: 'erc721', @@ -54,19 +97,34 @@ export const erc721Function = { name: repeatedOptions.name, symbol: repeatedOptions.symbol, baseUri: { type: 'string', description: 'A base uri for the token' }, - enumerable: { type: 'boolean', description: 'Whether to allow on-chain enumeration of all tokens or those owned by an account. Increases gas cost of transfers.' }, - uriStorage: { type: 'boolean', description: 'Allows updating token URIs for individual token IDs'}, + enumerable: { + type: 'boolean', + description: + 'Whether to allow on-chain enumeration of all tokens or those owned by an account. Increases gas cost of transfers.', + }, + uriStorage: { + type: 'boolean', + description: 'Allows updating token URIs for individual token IDs', + }, burnable: repeatedOptions.burnable, pausable: repeatedOptions.pausable, mintable: repeatedOptions.mintable, - incremental: { type: 'boolean', description: 'Whether new tokens will be automatically assigned an incremental id' }, + incremental: { + type: 'boolean', + description: 'Whether new tokens will be automatically assigned an incremental id', + }, // 'false' gets converted to false - votes: { type: 'string', enum: ['false', 'blocknumber', 'timestamp'], description: 'Whether to keep track of individual units for voting in on-chain governance. Voting durations can be expressed as block numbers or timestamps.'}, - ...commonOptions + votes: { + type: 'string', + enum: ['false', 'blocknumber', 'timestamp'], + description: + 'Whether to keep track of individual units for voting in on-chain governance. Voting durations can be expressed as block numbers or timestamps.', + }, + ...commonOptions, }, required: ['name', 'symbol'], - } -} + }, +}; export const erc1155Function = { name: 'erc1155', @@ -75,39 +133,64 @@ export const erc1155Function = { type: 'object', properties: { name: repeatedOptions.name, - uri: { type: 'string', description: 'The Location of the metadata for the token. Clients will replace any instance of {id} in this string with the tokenId.' }, + uri: { + type: 'string', + description: + 'The Location of the metadata for the token. Clients will replace any instance of {id} in this string with the tokenId.', + }, burnable: repeatedOptions.burnable, pausable: repeatedOptions.pausable, mintable: repeatedOptions.mintable, - supply: { type: 'boolean', description: 'Whether to keep track of total supply of tokens' }, - updatableUri: { type: 'boolean', description: 'Whether privileged accounts will be able to set a new URI for all token types' }, - ...commonOptions + supply: { + type: 'boolean', + description: 'Whether to keep track of total supply of tokens', + }, + updatableUri: { + type: 'boolean', + description: 'Whether privileged accounts will be able to set a new URI for all token types', + }, + ...commonOptions, }, required: ['name', 'uri'], - } -} + }, +}; export const stablecoinFunction = { name: 'stablecoin', - description: 'Make a stablecoin token that uses the ERC-20 standard. Emphasize that this is experimental, and some features are not audited and subject to change.', + description: + 'Make a stablecoin token that uses the ERC-20 standard. Emphasize that this is experimental, and some features are not audited and subject to change.', parameters: { type: 'object', properties: { ...erc20Function.parameters.properties, - custodian: { type: 'boolean', description: 'Whether authorized accounts can freeze and unfreeze accounts for regulatory or security purposes. This feature is experimental, not audited and is subject to change.' }, + custodian: { + type: 'boolean', + description: + 'Whether authorized accounts can freeze and unfreeze accounts for regulatory or security purposes. This feature is experimental, not audited and is subject to change.', + }, // 'false' gets converted to false - limitations: { type: 'string', enum: ['false', 'allowlist', 'blocklist'], description: 'Whether to restrict certain users from transferring tokens, either via allowing or blocking them. This feature is experimental, not audited and is subject to change.' }, - upgradeable: { type: 'string', enum: ['false'], description: 'Upgradeability is not yet available for features that use @openzeppelin/community-contracts' }, + limitations: { + type: 'string', + enum: ['false', 'allowlist', 'blocklist'], + description: + 'Whether to restrict certain users from transferring tokens, either via allowing or blocking them. This feature is experimental, not audited and is subject to change.', + }, + upgradeable: { + type: 'string', + enum: ['false'], + description: 'Upgradeability is not yet available for features that use @openzeppelin/community-contracts', + }, }, required: ['name', 'symbol'], - } -} + }, +}; export const realWorldAssetFunction = { name: 'realworldasset', - description: 'Make a real-world asset token that uses the ERC-20 standard. Emphasize that this is experimental, and some features are not audited and subject to change.', + description: + 'Make a real-world asset token that uses the ERC-20 standard. Emphasize that this is experimental, and some features are not audited and subject to change.', parameters: stablecoinFunction.parameters, -} +}; export const governorFunction = { name: 'governor', @@ -116,27 +199,72 @@ export const governorFunction = { type: 'object', properties: { name: repeatedOptions.name, - delay: { type: 'string', description: 'The delay since proposal is created until voting starts, default is "1 day"' }, - period: { type: 'string', description: 'The length of period during which people can cast their vote, default is "1 week"' }, - blockTime: { type: 'number', description: 'The number of seconds assumed for a block, default is 12' }, + delay: { + type: 'string', + description: 'The delay since proposal is created until voting starts, default is "1 day"', + }, + period: { + type: 'string', + description: 'The length of period during which people can cast their vote, default is "1 week"', + }, + blockTime: { + type: 'number', + description: 'The number of seconds assumed for a block, default is 12', + }, // gets converted to a string to follow the API - proposalThreshold: { type: 'number', description: 'Minimum number of votes an account must have to create a proposal, default is 0.' }, - decimals: { type: 'number', description: 'The number of decimals to use for the contract, default is 18 for ERC20Votes and 0 for ERC721Votes (because it does not apply to ERC721Votes)' }, - quorumMode: { type: 'string', enum: ['percent', 'absolute'], description: 'The type of quorum mode to use' }, - quorumPercent: { type: 'number', description: 'The percent required, in cases of quorumMode equals percent' }, + proposalThreshold: { + type: 'number', + description: 'Minimum number of votes an account must have to create a proposal, default is 0.', + }, + decimals: { + type: 'number', + description: + 'The number of decimals to use for the contract, default is 18 for ERC20Votes and 0 for ERC721Votes (because it does not apply to ERC721Votes)', + }, + quorumMode: { + type: 'string', + enum: ['percent', 'absolute'], + description: 'The type of quorum mode to use', + }, + quorumPercent: { + type: 'number', + description: 'The percent required, in cases of quorumMode equals percent', + }, // gets converted to a string to follow the API - quorumAbsolute: { type: 'number', description: 'The absolute quorum required, in cases of quorumMode equals absolute' }, - votes: { type: 'string', enum: ['erc20votes', 'erc721votes'], description: 'The type of voting to use' }, - clockMode: { type: 'string', enum: ['blocknumber', 'timestamp'], description: 'The clock mode used by the voting token. For Governor, this must be chosen to match what the ERC20 or ERC721 voting token uses.' }, + quorumAbsolute: { + type: 'number', + description: 'The absolute quorum required, in cases of quorumMode equals absolute', + }, + votes: { + type: 'string', + enum: ['erc20votes', 'erc721votes'], + description: 'The type of voting to use', + }, + clockMode: { + type: 'string', + enum: ['blocknumber', 'timestamp'], + description: + 'The clock mode used by the voting token. For Governor, this must be chosen to match what the ERC20 or ERC721 voting token uses.', + }, // 'false' gets converted to false - timelock: { type: 'string', enum: ['false', 'openzeppelin', 'compound'], description: 'The type of timelock to use' }, - storage: { type: 'boolean', description: 'Enable storage of proposal details and enumerability of proposals' }, - settings: { type: 'boolean', description: 'Allow governance to update voting settings (delay, period, proposal threshold)' }, - ...commonOptions + timelock: { + type: 'string', + enum: ['false', 'openzeppelin', 'compound'], + description: 'The type of timelock to use', + }, + storage: { + type: 'boolean', + description: 'Enable storage of proposal details and enumerability of proposals', + }, + settings: { + type: 'boolean', + description: 'Allow governance to update voting settings (delay, period, proposal threshold)', + }, + ...commonOptions, }, required: ['name', 'delay', 'period'], - } -} + }, +}; export const customFunction = { name: 'custom', @@ -146,8 +274,8 @@ export const customFunction = { properties: { name: repeatedOptions.name, pausable: repeatedOptions.pausable, - ...commonOptions + ...commonOptions, }, required: ['name'], - } -} + }, +}; diff --git a/packages/ui/tailwind.config.js b/packages/ui/tailwind.config.js index ddd5b15e0..579a11b5e 100644 --- a/packages/ui/tailwind.config.js +++ b/packages/ui/tailwind.config.js @@ -32,8 +32,7 @@ module.exports = { 'fade-down': 'fade-down 0.5s ease-out', 'spin-slow': 'spin 2s linear infinite', }, - - } + }, }, - plugins: [] + plugins: [], }; diff --git a/scripts/bump-changelog.js b/scripts/bump-changelog.js index 541b8e0c3..fb756d7a2 100644 --- a/scripts/bump-changelog.js +++ b/scripts/bump-changelog.js @@ -16,4 +16,4 @@ if (!unreleased.test(changelog)) { fs.writeFileSync('CHANGELOG.md', changelog.replace(unreleased, `## ${version} (${date})`)); const proc = require('child_process'); -proc.execSync('git add CHANGELOG.md', { stdio: 'inherit' }); \ No newline at end of file +proc.execSync('git add CHANGELOG.md', { stdio: 'inherit' }); diff --git a/scripts/command-input.mjs b/scripts/command-input.mjs index 1e007c317..210f4937d 100644 --- a/scripts/command-input.mjs +++ b/scripts/command-input.mjs @@ -1,8 +1,8 @@ export function getCommandAndFlagsInput() { const [, , _languageFolderName, ...commandAndFlags] = process.argv; - if (commandAndFlags) return commandAndFlags.join(" "); + if (commandAndFlags) return commandAndFlags.join(' '); - console.error("Please provide a command."); + console.error('Please provide a command.'); process.exit(1); } diff --git a/scripts/execute-command.mjs b/scripts/execute-command.mjs index eaac4a3e5..b275d93df 100644 --- a/scripts/execute-command.mjs +++ b/scripts/execute-command.mjs @@ -1,18 +1,12 @@ -import { execSync } from "child_process"; +import { execSync } from 'child_process'; export function runYarnCommandForLanguage(languageInput, commandAndFlagsInput) { try { - execSync( - `yarn --cwd ./packages/core/${languageInput} ${commandAndFlagsInput}`, - { - stdio: "inherit", - } - ); + execSync(`yarn --cwd ./packages/core/${languageInput} ${commandAndFlagsInput}`, { + stdio: 'inherit', + }); } catch (error) { - console.error( - `Error running ${commandAndFlagsInput} in ${languageInput}:`, - error - ); + console.error(`Error running ${commandAndFlagsInput} in ${languageInput}:`, error); process.exit(1); } } diff --git a/scripts/language-input.mjs b/scripts/language-input.mjs index e6db7243f..4fc46e59a 100644 --- a/scripts/language-input.mjs +++ b/scripts/language-input.mjs @@ -1,10 +1,10 @@ -import { readdirSync, statSync } from "fs"; -import { join } from "path"; +import { readdirSync, statSync } from 'fs'; +import { join } from 'path'; -const coreSubfolderPath = "./packages/core"; +const coreSubfolderPath = './packages/core'; function getSupportedLanguageInCoreSubfolder() { - return readdirSync(coreSubfolderPath).filter((subfolder) => { + return readdirSync(coreSubfolderPath).filter(subfolder => { const subfolderPath = join(coreSubfolderPath, subfolder); return statSync(subfolderPath).isDirectory(); }); @@ -15,7 +15,7 @@ function getLanguageInput() { if (languageFolderName) return languageFolderName; - console.error("Please provide a language name."); + console.error('Please provide a language name.'); process.exit(1); } @@ -24,11 +24,8 @@ export function getAndCheckLanguageInput() { const supportedLanguages = getSupportedLanguageInCoreSubfolder(); - if (supportedLanguages.includes(languageFolderName)) - return languageFolderName; + if (supportedLanguages.includes(languageFolderName)) return languageFolderName; - console.error( - `Invalid language name ${languageFolderName}. Supported languages: ${supportedLanguages.join(", ")}` - ); + console.error(`Invalid language name ${languageFolderName}. Supported languages: ${supportedLanguages.join(', ')}`); process.exit(1); } diff --git a/scripts/run-command.mjs b/scripts/run-command.mjs index 28468c31e..3295a464d 100644 --- a/scripts/run-command.mjs +++ b/scripts/run-command.mjs @@ -1,8 +1,5 @@ -import { getCommandAndFlagsInput } from "./command-input.mjs"; -import { runYarnCommandForLanguage } from "./execute-command.mjs"; -import { getAndCheckLanguageInput } from "./language-input.mjs"; +import { getCommandAndFlagsInput } from './command-input.mjs'; +import { runYarnCommandForLanguage } from './execute-command.mjs'; +import { getAndCheckLanguageInput } from './language-input.mjs'; -runYarnCommandForLanguage( - getAndCheckLanguageInput(), - getCommandAndFlagsInput() -); +runYarnCommandForLanguage(getAndCheckLanguageInput(), getCommandAndFlagsInput()); diff --git a/yarn.lock b/yarn.lock index 0c990aae4..03e686265 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,7 +7,7 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.13": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ== @@ -28,6 +28,67 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.4.1": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/config-array@^0.19.2": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa" + integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e" + integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.0.tgz#96a558f45842989cca7ea1ecd785ad5491193846" + integrity sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.21.0", "@eslint/js@^9.21.0": + version "9.21.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.21.0.tgz#4303ef4e07226d87c395b8fad5278763e9c15c08" + integrity sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27" + integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g== + dependencies: + "@eslint/core" "^0.12.0" + levn "^0.4.1" + "@ethersproject/abi@^5.1.2": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" @@ -210,6 +271,34 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161" + integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -484,6 +573,11 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + "@polka/url@^1.0.0-next.24": version "1.0.0-next.28" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" @@ -794,7 +888,7 @@ dependencies: cssnano "*" -"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0": +"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.6": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== @@ -824,6 +918,11 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/lru-cache@^5.1.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" @@ -843,6 +942,11 @@ dependencies: undici-types "~5.26.4" +"@types/normalize-package-data@^2.4.3": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" + integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== + "@types/parse-json@^4.0.0": version "4.0.2" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" @@ -894,6 +998,87 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.1.tgz#d104c2a6212304c649105b18af2c110b4a1dd4ae" + integrity sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.24.1" + "@typescript-eslint/type-utils" "8.24.1" + "@typescript-eslint/utils" "8.24.1" + "@typescript-eslint/visitor-keys" "8.24.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^2.0.1" + +"@typescript-eslint/parser@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.24.1.tgz#67965c2d2ddd7eadb2f094c395695db8334ef9a2" + integrity sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ== + dependencies: + "@typescript-eslint/scope-manager" "8.24.1" + "@typescript-eslint/types" "8.24.1" + "@typescript-eslint/typescript-estree" "8.24.1" + "@typescript-eslint/visitor-keys" "8.24.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.24.1.tgz#1e1e76ec4560aa85077ab36deb9b2bead4ae124e" + integrity sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q== + dependencies: + "@typescript-eslint/types" "8.24.1" + "@typescript-eslint/visitor-keys" "8.24.1" + +"@typescript-eslint/type-utils@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.24.1.tgz#99113e1df63d1571309d87eef68967344c78dd65" + integrity sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw== + dependencies: + "@typescript-eslint/typescript-estree" "8.24.1" + "@typescript-eslint/utils" "8.24.1" + debug "^4.3.4" + ts-api-utils "^2.0.1" + +"@typescript-eslint/types@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.24.1.tgz#8777a024f3afc4ace5e48f9a804309c6dd38f95a" + integrity sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A== + +"@typescript-eslint/typescript-estree@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.1.tgz#3bb479401f8bd471b3c6dd3db89e7256977c54db" + integrity sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg== + dependencies: + "@typescript-eslint/types" "8.24.1" + "@typescript-eslint/visitor-keys" "8.24.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.1" + +"@typescript-eslint/utils@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.24.1.tgz#08d14eac33cfb3456feeee5a275b8ad3349e52ed" + integrity sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.24.1" + "@typescript-eslint/types" "8.24.1" + "@typescript-eslint/typescript-estree" "8.24.1" + +"@typescript-eslint/visitor-keys@8.24.1": + version "8.24.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.1.tgz#8bdfe47a89195344b34eb21ef61251562148202b" + integrity sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg== + dependencies: + "@typescript-eslint/types" "8.24.1" + eslint-visitor-keys "^4.2.0" + "@vercel/nft@^0.27.5": version "0.27.6" resolved "https://registry.yarnpkg.com/@vercel/nft/-/nft-0.27.6.tgz#4fffb7ad4ffdb70698213cfd67596be5e9cdfb6c" @@ -922,6 +1107,11 @@ acorn-import-attributes@^1.9.5: resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + acorn-walk@^8.1.1, acorn-walk@^8.3.4: version "8.3.4" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" @@ -929,7 +1119,7 @@ acorn-walk@^8.1.1, acorn-walk@^8.3.4: dependencies: acorn "^8.11.0" -acorn@^8.11.0, acorn@^8.13.0, acorn@^8.4.1, acorn@^8.6.0, acorn@^8.8.2: +acorn@^8.11.0, acorn@^8.13.0, acorn@^8.14.0, acorn@^8.4.1, acorn@^8.6.0, acorn@^8.8.2: version "8.14.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== @@ -954,6 +1144,16 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-align@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" @@ -1262,6 +1462,16 @@ browserslist@^4.0.0, browserslist@^4.21.4, browserslist@^4.23.3: node-releases "^2.0.18" update-browserslist-db "^1.1.1" +browserslist@^4.24.3: + version "4.24.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" + integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== + dependencies: + caniuse-lite "^1.0.30001688" + electron-to-chromium "^1.5.73" + node-releases "^2.0.19" + update-browserslist-db "^1.1.1" + bs58@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" @@ -1293,6 +1503,11 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== +builtin-modules@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-4.0.0.tgz#348db54ec0e6b197494423d26845f1674025ee46" + integrity sha512-p1n8zyCkt1BVrKNFymOHjcDSAl7oq/gUvfgULv2EblgpPVQlQr9yHnWjg9IJ2MhfwPqiYqMMrr01OY7yQoK2yA== + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1349,6 +1564,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001669: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz#5380ede637a33b9f9f1fc6045ea99bd142f3da5e" integrity sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA== +caniuse-lite@^1.0.30001688: + version "1.0.30001700" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz#26cd429cf09b4fd4e745daf4916039c794d720f6" + integrity sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ== + cbor@^9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/cbor/-/cbor-9.0.2.tgz#536b4f2d544411e70ec2b19a2453f10f83cd9fdb" @@ -1365,7 +1585,7 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1415,7 +1635,7 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== -ci-info@^4.0.0: +ci-info@^4.0.0, ci-info@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.1.0.tgz#92319d2fa29d2620180ea5afed31f589bc98cf83" integrity sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A== @@ -1433,6 +1653,13 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.4" safe-buffer "^5.2.1" +clean-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-regexp/-/clean-regexp-1.0.0.tgz#8df7c7aae51fd36874e8f8d05b9180bc11a3fed7" + integrity sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw== + dependencies: + escape-string-regexp "^1.0.5" + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -1593,6 +1820,13 @@ cookie@^0.4.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +core-js-compat@^3.40.0: + version "3.40.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.40.0.tgz#7485912a5a4a4315c2fdb2cbdc623e6881c88b38" + integrity sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ== + dependencies: + browserslist "^4.24.3" + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -1648,7 +1882,7 @@ cross-spawn@^6.0.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -1856,6 +2090,13 @@ debug@4, debug@^4.1.1, debug@^4.3.5, debug@^4.3.7: dependencies: ms "^2.1.3" +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -1871,6 +2112,11 @@ decode-uri-component@^0.2.2: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + deepmerge@^4.2.2: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" @@ -1990,6 +2236,11 @@ electron-to-chromium@^1.5.41: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.62.tgz#8289468414b0b0b3e9180ef619a763555debe612" integrity sha512-t8c+zLmJHa9dJy96yBZRXGQYoiCEnHYgFwn1asvSPZSUdVxnB62A4RASd7k41ytG3ErFBA0TpHlKg9D9SQBmLg== +electron-to-chromium@^1.5.73: + version "1.5.102" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz#81a452ace8e2c3fa7fba904ea4fed25052c53d3f" + integrity sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q== + elliptic@6.5.4: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" @@ -2120,17 +2371,138 @@ escape-string-regexp@^5.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== +eslint-config-prettier@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz#fbb03bfc8db0651df9ce4e8b7150d11c5fe3addf" + integrity sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw== + +eslint-plugin-prettier@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz#c4af01691a6fa9905207f0fbba0d7bea0902cce5" + integrity sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.9.1" + +eslint-plugin-unicorn@^57.0.0: + version "57.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unicorn/-/eslint-plugin-unicorn-57.0.0.tgz#4ae27a31e65b1a0307c09cb957f5de36b1773575" + integrity sha512-zUYYa6zfNdTeG9BISWDlcLmz16c+2Ck2o5ZDHh0UzXJz3DEP7xjmlVDTzbyV0W+XksgZ0q37WEWzN2D2Ze+g9Q== + dependencies: + "@babel/helper-validator-identifier" "^7.25.9" + "@eslint-community/eslint-utils" "^4.4.1" + ci-info "^4.1.0" + clean-regexp "^1.0.0" + core-js-compat "^3.40.0" + esquery "^1.6.0" + globals "^15.15.0" + indent-string "^5.0.0" + is-builtin-module "^4.0.0" + jsesc "^3.1.0" + pluralize "^8.0.0" + read-package-up "^11.0.0" + regexp-tree "^0.1.27" + regjsparser "^0.12.0" + semver "^7.7.1" + strip-indent "^4.0.0" + +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@^9.21.0: + version "9.21.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.21.0.tgz#b1c9c16f5153ff219791f627b94ab8f11f811591" + integrity sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.2" + "@eslint/core" "^0.12.0" + "@eslint/eslintrc" "^3.3.0" + "@eslint/js" "9.21.0" + "@eslint/plugin-kit" "^0.2.7" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== + dependencies: + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.5.0, esquery@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + estree-walker@2.0.2, estree-walker@^2.0.1, estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== -esutils@^2.0.3: +esutils@^2.0.2, esutils@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== @@ -2221,7 +2593,12 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -fast-diff@^1.2.0: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2, fast-diff@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== @@ -2237,6 +2614,16 @@ fast-glob@^3.3.2: merge2 "^1.3.0" micromatch "^4.0.4" +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + fastq@^1.6.0: version "1.17.1" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" @@ -2256,6 +2643,13 @@ figures@^6.1.0: dependencies: is-unicode-supported "^2.0.0" +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + file-saver@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38" @@ -2298,11 +2692,24 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + follow-redirects@^1.12.1: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" @@ -2475,6 +2882,16 @@ glob@^8.1.0: minimatch "^5.0.1" once "^1.3.0" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^15.15.0: + version "15.15.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.15.0.tgz#7c4761299d41c32b075715a4ce1ede7897ff72a8" + integrity sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg== + globby@^14.0.2: version "14.0.2" resolved "https://registry.yarnpkg.com/globby/-/globby-14.0.2.tgz#06554a54ccfe9264e5a9ff8eded46aa1e306482f" @@ -2499,6 +2916,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + hardhat@^2.1.1: version "2.22.16" resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.22.16.tgz#6cf3413f63b14770f863f35452da891ac2bd50cb" @@ -2641,6 +3063,13 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hosted-git-info@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" + integrity sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w== + dependencies: + lru-cache "^10.0.1" + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -2677,7 +3106,7 @@ ignore-by-default@^2.1.0: resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-2.1.0.tgz#c0e0de1a99b6065bdc93315a6f728867981464db" integrity sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw== -ignore@^5.2.4: +ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -2715,6 +3144,11 @@ indent-string@^5.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== +index-to-position@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/index-to-position/-/index-to-position-0.1.2.tgz#e11bfe995ca4d8eddb1ec43274488f3c201a7f09" + integrity sha512-MWDKS3AS1bGCHLBA2VLImJz42f7bJh8wQsTGCzI3j519/CASStoDONUBVz2I/VID0MpiX3SGSnbOD2xUalbE5g== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2760,6 +3194,13 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-builtin-module@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-4.0.0.tgz#dfbf2080dad42d28af2bde71df7e4bc3f1dee6c0" + integrity sha512-rWP3AMAalQSesXO8gleROyL2iKU73SX5Er66losQn9rWOWL4Gef0a/xOEOVqjWGMuR2vHG3FJ8UUmT700O8oFg== + dependencies: + builtin-modules "^4.0.0" + is-callable@^1.1.3: version "1.2.7" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -2799,7 +3240,7 @@ is-generator-function@^1.0.7: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -2937,11 +3378,36 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsesc@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +jsesc@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json-stream-stringify@^3.1.4: version "3.1.6" resolved "https://registry.yarnpkg.com/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz#ebe32193876fb99d4ec9f612389a8d8e2b5d54d4" @@ -2982,11 +3448,26 @@ keccak@^3.0.0, keccak@^3.0.2: node-gyp-build "^4.2.0" readable-stream "^3.6.0" +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kleur@^4.1.4: version "4.1.5" resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + lie@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" @@ -3054,6 +3535,11 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -3072,7 +3558,7 @@ log-symbols@^4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" -lru-cache@^10.2.0: +lru-cache@^10.0.1, lru-cache@^10.2.0: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== @@ -3186,7 +3672,7 @@ mimic-function@^5.0.0: resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076" integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA== -min-indent@^1.0.0: +min-indent@^1.0.0, min-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== @@ -3201,7 +3687,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -3326,6 +3812,11 @@ nanoid@^3.3.7: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -3358,6 +3849,11 @@ node-releases@^2.0.18: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + nofilter@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-3.1.0.tgz#c757ba68801d41ff930ba2ec55bab52ca184aa66" @@ -3370,6 +3866,15 @@ nopt@^5.0.0: dependencies: abbrev "1" +normalize-package-data@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.2.tgz#a7bc22167fe24025412bcff0a9651eb768b03506" + integrity sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g== + dependencies: + hosted-git-info "^7.0.0" + semver "^7.3.5" + validate-npm-package-license "^3.0.4" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -3431,6 +3936,18 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + "opts@>= 1.2.0": version "2.0.2" resolved "https://registry.yarnpkg.com/opts/-/opts-2.0.2.tgz#a17e189fbbfee171da559edd8a42423bc5993ce1" @@ -3541,6 +4058,15 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-json@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-8.1.0.tgz#91cdc7728004e955af9cb734de5684733b24a717" + integrity sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA== + dependencies: + "@babel/code-frame" "^7.22.13" + index-to-position "^0.1.2" + type-fest "^4.7.1" + parse-ms@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-4.0.0.tgz#c0c058edd47c2a590151a718990533fd62803df4" @@ -3642,6 +4168,11 @@ plur@^5.1.0: dependencies: irregular-plurals "^3.3.0" +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + possible-typed-array-names@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" @@ -4139,6 +4670,23 @@ postcss@^8.2.8, postcss@^8.4.47, postcss@^8.4.5: picocolors "^1.1.1" source-map-js "^1.2.1" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.1.tgz#22fac9d0b18c0b92055ac8fb619ac1c7bef02fb7" + integrity sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw== + pretty-ms@^9.1.0: version "9.2.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-9.2.0.tgz#e14c0aad6493b69ed63114442a84133d7e560ef0" @@ -4159,6 +4707,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + query-string@^7.1.0: version "7.1.3" resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" @@ -4198,6 +4751,26 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" +read-package-up@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/read-package-up/-/read-package-up-11.0.0.tgz#71fb879fdaac0e16891e6e666df22de24a48d5ba" + integrity sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ== + dependencies: + find-up-simple "^1.0.0" + read-pkg "^9.0.0" + type-fest "^4.6.0" + +read-pkg@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-9.0.1.tgz#b1b81fb15104f5dbb121b6bbdee9bbc9739f569b" + integrity sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA== + dependencies: + "@types/normalize-package-data" "^2.4.3" + normalize-package-data "^6.0.0" + parse-json "^8.0.0" + type-fest "^4.6.0" + unicorn-magic "^0.1.0" + readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" @@ -4232,6 +4805,18 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +regexp-tree@^0.1.27: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + +regjsparser@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.12.0.tgz#0e846df6c6530586429377de56e0475583b088dc" + integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ== + dependencies: + jsesc "~3.0.2" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -4470,6 +5055,11 @@ semver@^7.3.2, semver@^7.3.5, semver@^7.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.7.1: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -4642,6 +5232,32 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66" + integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.21" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz#6d6e980c9df2b6fc905343a3b2d702a6239536c3" + integrity sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg== + split-on-first@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" @@ -4794,6 +5410,13 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" +strip-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853" + integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA== + dependencies: + min-indent "^1.0.1" + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -4918,6 +5541,14 @@ svgo@^3.3.2: csso "^5.0.5" picocolors "^1.0.0" +synckit@^0.9.1: + version "0.9.2" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" + integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + tailwindcss@^3.0.15: version "3.4.15" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.15.tgz#04808bf4bf1424b105047d19e7d4bfab368044a9" @@ -5051,6 +5682,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +ts-api-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd" + integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w== + ts-interface-checker@^0.1.9: version "0.1.13" resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" @@ -5080,7 +5716,7 @@ tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.3.1: +tslib@^2.0.0, tslib@^2.3.1, tslib@^2.6.2: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -5100,6 +5736,13 @@ tweetnacl@^1.0.3: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-fest@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" @@ -5120,7 +5763,21 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -typescript@^5.0.0: +type-fest@^4.6.0, type-fest@^4.7.1: + version "4.35.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.35.0.tgz#007ed74d65c2ca0fb3b564b3dc8170d5c872d665" + integrity sha512-2/AwEFQDFEy30iOLjrvHDIH7e4HEWH+f1Yl1bI5XMqzuoCUqwYCdxachgsgv0og/JdVZUhbfjcJAoHj5L1753A== + +typescript-eslint@^8.24.1: + version "8.24.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.24.1.tgz#ce85d791392608a2a9f80c4b2530a214d16a2a47" + integrity sha512-cw3rEdzDqBs70TIcb0Gdzbt6h11BSs2pS0yaq7hDWDBtCCSei1pPSUXE9qUdQ/Wm9NgFg8mKtMt1b8fTHIl1jA== + dependencies: + "@typescript-eslint/eslint-plugin" "8.24.1" + "@typescript-eslint/parser" "8.24.1" + "@typescript-eslint/utils" "8.24.1" + +typescript@^5.0.0, typescript@^5.7.3: version "5.7.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e" integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw== @@ -5175,6 +5832,13 @@ update-browserslist-db@^1.1.1: escalade "^3.2.0" picocolors "^1.1.0" +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -5201,6 +5865,14 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +validate-npm-package-license@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -5263,6 +5935,11 @@ widest-line@^3.1.0: dependencies: string-width "^4.0.0" +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + workerpool@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544"